Merge "Revert "[PM] Add more logs to debug the flaky test"" into main
diff --git a/AconfigFlags.bp b/AconfigFlags.bp
index fbe4905..c6ce799 100644
--- a/AconfigFlags.bp
+++ b/AconfigFlags.bp
@@ -24,6 +24,7 @@
         "android-sdk-flags-java",
         "android.adaptiveauth.flags-aconfig-java",
         "android.app.appfunctions.flags-aconfig-java",
+        "android.app.assist.flags-aconfig-java",
         "android.app.contextualsearch.flags-aconfig-java",
         "android.app.flags-aconfig-java",
         "android.app.jank.flags-aconfig-java",
@@ -64,6 +65,7 @@
         "android.server.app.flags-aconfig-java",
         "android.service.autofill.flags-aconfig-java",
         "android.service.chooser.flags-aconfig-java",
+        "android.service.compat.flags-aconfig-java",
         "android.service.controls.flags-aconfig-java",
         "android.service.dreams.flags-aconfig-java",
         "android.service.notification.flags-aconfig-java",
@@ -862,6 +864,21 @@
     defaults: ["framework-minus-apex-aconfig-java-defaults"],
 }
 
+aconfig_declarations {
+    name: "android.service.compat.flags-aconfig",
+    package: "com.android.server.compat",
+    container: "system",
+    srcs: [
+        "services/core/java/com/android/server/compat/*.aconfig",
+    ],
+}
+
+java_aconfig_library {
+    name: "android.service.compat.flags-aconfig-java",
+    aconfig_declarations: "android.service.compat.flags-aconfig",
+    defaults: ["framework-minus-apex-aconfig-java-defaults"],
+}
+
 // Multi user
 aconfig_declarations {
     name: "android.multiuser.flags-aconfig",
@@ -1230,6 +1247,20 @@
     defaults: ["framework-minus-apex-aconfig-java-defaults"],
 }
 
+// Assist
+aconfig_declarations {
+    name: "android.app.assist.flags-aconfig",
+    package: "android.app.assist.flags",
+    container: "system",
+    srcs: ["core/java/android/app/assist/flags.aconfig"],
+}
+
+java_aconfig_library {
+    name: "android.app.assist.flags-aconfig-java",
+    aconfig_declarations: "android.app.assist.flags-aconfig",
+    defaults: ["framework-minus-apex-aconfig-java-defaults"],
+}
+
 // Smartspace
 aconfig_declarations {
     name: "android.app.smartspace.flags-aconfig",
diff --git a/Android.bp b/Android.bp
index 811755d..252aeef 100644
--- a/Android.bp
+++ b/Android.bp
@@ -150,6 +150,7 @@
         // etc.
         ":framework-javastream-protos",
         ":statslog-framework-java-gen", // FrameworkStatsLog.java
+        ":statslog-hwui-java-gen", // HwuiStatsLog.java
         ":audio_policy_configuration_V7_0",
     ],
 }
@@ -170,12 +171,6 @@
         //same purpose.
         "//external/robolectric:__subpackages__",
         "//frameworks/layoutlib:__subpackages__",
-
-        // This is for the same purpose as robolectric -- to build "framework.jar" for host-side
-        // testing.
-        // TODO: Once Ravenwood is stable, move the host side jar targets to this directory,
-        // and remove this line.
-        "//frameworks/base/tools/hoststubgen:__subpackages__",
     ],
 }
 
diff --git a/Ravenwood.bp b/Ravenwood.bp
index ec58210..2e038e0 100644
--- a/Ravenwood.bp
+++ b/Ravenwood.bp
@@ -12,256 +12,19 @@
 // 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-base. 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"],
-}
-
-// Process framework-all with hoststubgen for Ravenwood.
-// This step takes several tens of seconds, so we manually shard it to multiple modules.
-// All the copies have to be kept in sync.
-// TODO: Do the sharding better, either by making hostsubgen support sharding natively, or
-// making a better build rule.
-
-genrule_defaults {
-    name: "framework-minus-apex.ravenwood-base_defaults",
-    defaults: ["ravenwood-internal-only-visibility-genrule"],
-    tools: ["hoststubgen"],
-    srcs: [
-        ":framework-minus-apex-for-hoststubgen",
-        ":ravenwood-framework-policies",
-        ":ravenwood-standard-options",
-        ":ravenwood-annotation-allowed-classes",
-    ],
-    out: [
-        "ravenwood.jar",
-        "hoststubgen_framework-minus-apex.log",
-    ],
-}
-
-framework_minus_apex_cmd = "$(location hoststubgen) " +
-    "@$(location :ravenwood-standard-options) " +
-    "--debug-log $(location hoststubgen_framework-minus-apex.log) " +
-    "--out-jar $(location ravenwood.jar) " +
-    "--in-jar $(location :framework-minus-apex-for-hoststubgen) " +
-    "--policy-override-file $(location :ravenwood-framework-policies) " +
-    "--annotation-allowed-classes-file $(location :ravenwood-annotation-allowed-classes) "
-
-java_genrule {
-    name: "framework-minus-apex.ravenwood-base_X0",
-    defaults: ["framework-minus-apex.ravenwood-base_defaults"],
-    cmd: framework_minus_apex_cmd + " --num-shards 10 --shard-index 0",
-}
-
-java_genrule {
-    name: "framework-minus-apex.ravenwood-base_X1",
-    defaults: ["framework-minus-apex.ravenwood-base_defaults"],
-    cmd: framework_minus_apex_cmd + " --num-shards 10 --shard-index 1",
-}
-
-java_genrule {
-    name: "framework-minus-apex.ravenwood-base_X2",
-    defaults: ["framework-minus-apex.ravenwood-base_defaults"],
-    cmd: framework_minus_apex_cmd + " --num-shards 10 --shard-index 2",
-}
-
-java_genrule {
-    name: "framework-minus-apex.ravenwood-base_X3",
-    defaults: ["framework-minus-apex.ravenwood-base_defaults"],
-    cmd: framework_minus_apex_cmd + " --num-shards 10 --shard-index 3",
-}
-
-java_genrule {
-    name: "framework-minus-apex.ravenwood-base_X4",
-    defaults: ["framework-minus-apex.ravenwood-base_defaults"],
-    cmd: framework_minus_apex_cmd + " --num-shards 10 --shard-index 4",
-}
-
-java_genrule {
-    name: "framework-minus-apex.ravenwood-base_X5",
-    defaults: ["framework-minus-apex.ravenwood-base_defaults"],
-    cmd: framework_minus_apex_cmd + " --num-shards 10 --shard-index 5",
-}
-
-java_genrule {
-    name: "framework-minus-apex.ravenwood-base_X6",
-    defaults: ["framework-minus-apex.ravenwood-base_defaults"],
-    cmd: framework_minus_apex_cmd + " --num-shards 10 --shard-index 6",
-}
-
-java_genrule {
-    name: "framework-minus-apex.ravenwood-base_X7",
-    defaults: ["framework-minus-apex.ravenwood-base_defaults"],
-    cmd: framework_minus_apex_cmd + " --num-shards 10 --shard-index 7",
-}
-
-java_genrule {
-    name: "framework-minus-apex.ravenwood-base_X8",
-    defaults: ["framework-minus-apex.ravenwood-base_defaults"],
-    cmd: framework_minus_apex_cmd + " --num-shards 10 --shard-index 8",
-}
-
-java_genrule {
-    name: "framework-minus-apex.ravenwood-base_X9",
-    defaults: ["framework-minus-apex.ravenwood-base_defaults"],
-    cmd: framework_minus_apex_cmd + " --num-shards 10 --shard-index 9",
-}
-
-// Build framework-minus-apex.ravenwood-base without sharding.
-// We extract the various dump files from this one, rather than the sharded ones, because
-// some dumps use the output from other classes (e.g. base classes) which may not be in the
-// same shard. Also some of the dump files ("apis") may be slow even when sharded, because
-// the output contains the information from all the input classes, rather than the output classes.
-// Not using sharding is fine for this module because it's only used for collecting the
-// dump / stats files, which don't have to happen regularly.
-java_genrule {
-    name: "framework-minus-apex.ravenwood-base_all",
-    defaults: ["framework-minus-apex.ravenwood-base_defaults"],
-    cmd: framework_minus_apex_cmd +
-        "--stats-file $(location hoststubgen_framework-minus-apex_stats.csv) " +
-        "--supported-api-list-file $(location hoststubgen_framework-minus-apex_apis.csv) " +
-
-        "--gen-keep-all-file $(location hoststubgen_framework-minus-apex_keep_all.txt) " +
-        "--gen-input-dump-file $(location hoststubgen_framework-minus-apex_dump.txt) ",
-
-    out: [
-        "hoststubgen_framework-minus-apex_keep_all.txt",
-        "hoststubgen_framework-minus-apex_dump.txt",
-        "hoststubgen_framework-minus-apex_stats.csv",
-        "hoststubgen_framework-minus-apex_apis.csv",
-    ],
-}
-
-// Marge all the sharded jars
-java_genrule {
-    name: "framework-minus-apex.ravenwood",
-    defaults: ["ravenwood-internal-only-visibility-java"],
-    cmd: "$(location merge_zips) $(out) $(in)",
-    tools: ["merge_zips"],
-    srcs: [
-        ":framework-minus-apex.ravenwood-base_X0{ravenwood.jar}",
-        ":framework-minus-apex.ravenwood-base_X1{ravenwood.jar}",
-        ":framework-minus-apex.ravenwood-base_X2{ravenwood.jar}",
-        ":framework-minus-apex.ravenwood-base_X3{ravenwood.jar}",
-        ":framework-minus-apex.ravenwood-base_X4{ravenwood.jar}",
-        ":framework-minus-apex.ravenwood-base_X5{ravenwood.jar}",
-        ":framework-minus-apex.ravenwood-base_X6{ravenwood.jar}",
-        ":framework-minus-apex.ravenwood-base_X7{ravenwood.jar}",
-        ":framework-minus-apex.ravenwood-base_X8{ravenwood.jar}",
-        ":framework-minus-apex.ravenwood-base_X9{ravenwood.jar}",
-    ],
-    out: [
-        "framework-minus-apex.ravenwood.jar",
-    ],
-}
+// "framework-minus-apex" and "all-updatable-modules-system-stubs" are not
+// visible publicly. We re-export them to Ravenwood in this file.
 
 java_library {
-    name: "services.core-for-hoststubgen",
-    installable: false, // host only jar.
-    static_libs: [
-        "services.core",
-    ],
-    sdk_version: "core_platform",
-    visibility: ["//visibility:private"],
-}
-
-java_genrule {
-    name: "services.core.ravenwood-base",
-    tools: ["hoststubgen"],
-    cmd: "$(location hoststubgen) " +
-        "@$(location :ravenwood-standard-options) " +
-
-        "--debug-log $(location hoststubgen_services.core.log) " +
-        "--stats-file $(location hoststubgen_services.core_stats.csv) " +
-        "--supported-api-list-file $(location hoststubgen_services.core_apis.csv) " +
-
-        "--out-jar $(location ravenwood.jar) " +
-
-        "--gen-keep-all-file $(location hoststubgen_services.core_keep_all.txt) " +
-        "--gen-input-dump-file $(location hoststubgen_services.core_dump.txt) " +
-
-        "--in-jar $(location :services.core-for-hoststubgen) " +
-        "--policy-override-file $(location :ravenwood-services-policies) " +
-        "--annotation-allowed-classes-file $(location :ravenwood-annotation-allowed-classes) ",
-    srcs: [
-        ":services.core-for-hoststubgen",
-        ":ravenwood-services-policies",
-        ":ravenwood-standard-options",
-        ":ravenwood-annotation-allowed-classes",
-    ],
-    out: [
-        "ravenwood.jar",
-
-        // Following files are created just as FYI.
-        "hoststubgen_services.core_keep_all.txt",
-        "hoststubgen_services.core_dump.txt",
-
-        "hoststubgen_services.core.log",
-        "hoststubgen_services.core_stats.csv",
-        "hoststubgen_services.core_apis.csv",
-    ],
-    defaults: ["ravenwood-internal-only-visibility-genrule"],
-}
-
-java_genrule {
-    name: "services.core.ravenwood",
-    defaults: ["ravenwood-internal-only-visibility-genrule"],
-    cmd: "cp $(in) $(out)",
-    srcs: [
-        ":services.core.ravenwood-base{ravenwood.jar}",
-    ],
-    out: [
-        "services.core.ravenwood.jar",
-    ],
-}
-
-// TODO(b/313930116) This jarjar is a bit slow. We should use hoststubgen for renaming,
-// but services.core.ravenwood has complex dependencies, so it'll take more than
-// just using hoststubgen "rename"s.
-java_library {
-    name: "services.core.ravenwood-jarjar",
-    defaults: ["ravenwood-internal-only-visibility-java"],
+    name: "framework-minus-apex-for-host",
     installable: false,
-    static_libs: [
-        "services.core.ravenwood",
-    ],
-    jarjar_rules: ":ravenwood-services-jarjar-rules",
+    static_libs: ["framework-minus-apex"],
+    visibility: ["//frameworks/base/ravenwood"],
 }
 
-// Jars in "ravenwood-runtime" are set to the classpath, sorted alphabetically.
-// Rename some of the dependencies to make sure they're included in the intended order.
 java_library {
-    name: "100-framework-minus-apex.ravenwood",
-    defaults: ["ravenwood-internal-only-visibility-java"],
-    static_libs: [
-        "framework-minus-apex.ravenwood",
-    ],
-    sdk_version: "core_platform",
-    // See b/313930116. Jarjar is too slow on this jar. We use HostStubGen to do the rename.
-    // jarjar_rules: ":ravenwood-framework-jarjar-rules",
-}
-
-java_genrule {
-    // Use 200 to make sure it comes before the mainline stub ("all-updatable...").
-    name: "200-kxml2-android",
-    defaults: ["ravenwood-internal-only-visibility-genrule"],
-    cmd: "cp $(in) $(out)",
-    srcs: [":kxml2-android"],
-    out: ["200-kxml2-android.jar"],
-}
-
-java_genrule {
-    name: "z00-all-updatable-modules-system-stubs",
-    defaults: ["ravenwood-internal-only-visibility-genrule"],
-    cmd: "cp $(in) $(out)",
-    srcs: [":all-updatable-modules-system-stubs"],
-    out: ["z00-all-updatable-modules-system-stubs.jar"],
+    name: "all-updatable-modules-system-stubs-for-host",
+    installable: false,
+    static_libs: ["all-updatable-modules-system-stubs"],
+    visibility: ["//frameworks/base/ravenwood"],
 }
diff --git a/apex/jobscheduler/service/aconfig/job.aconfig b/apex/jobscheduler/service/aconfig/job.aconfig
index e5389b4..11c5b51 100644
--- a/apex/jobscheduler/service/aconfig/job.aconfig
+++ b/apex/jobscheduler/service/aconfig/job.aconfig
@@ -75,3 +75,10 @@
        purpose: PURPOSE_BUGFIX
    }
 }
+
+flag {
+   name: "enforce_quota_policy_to_fgs_jobs"
+   namespace: "backstage_power"
+   description: "Applies the normal quota policy to FGS jobs"
+   bug: "341201311"
+}
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java
index a1c72fb..03a3a0d 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java
@@ -99,10 +99,10 @@
  * the number of jobs or sessions that can run within the window. Regardless of bucket, apps will
  * not be allowed to run more than 20 jobs within the past 10 minutes.
  *
- * Jobs are throttled while an app is not in a foreground state. All jobs are allowed to run
- * freely when an app enters the foreground state and are restricted when the app leaves the
- * foreground state. However, jobs that are started while the app is in the TOP state do not count
- * towards any quota and are not restricted regardless of the app's state change.
+ * Jobs are throttled while an app is not in a TOP or BOUND_TOP state. All jobs are allowed to run
+ * freely when an app enters the TOP or BOUND_TOP state and are restricted when the app leaves those
+ * states. However, jobs that are started while the app is in the TOP state do not count towards any
+ * quota and are not restricted regardless of the app's state change.
  *
  * Jobs will not be throttled when the device is charging. The device is considered to be charging
  * once the {@link BatteryManager#ACTION_CHARGING} intent has been broadcast.
@@ -567,6 +567,11 @@
             ActivityManager.getService().registerUidObserver(new QcUidObserver(),
                     ActivityManager.UID_OBSERVER_PROCSTATE,
                     ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE, null);
+            if (Flags.enforceQuotaPolicyToFgsJobs()) {
+                ActivityManager.getService().registerUidObserver(new QcUidObserver(),
+                        ActivityManager.UID_OBSERVER_PROCSTATE,
+                        ActivityManager.PROCESS_STATE_BOUND_TOP, null);
+            }
             ActivityManager.getService().registerUidObserver(new QcUidObserver(),
                     ActivityManager.UID_OBSERVER_PROCSTATE,
                     ActivityManager.PROCESS_STATE_TOP, null);
@@ -2706,6 +2711,12 @@
         }
     }
 
+    @VisibleForTesting
+    int getProcessStateQuotaFreeThreshold() {
+        return Flags.enforceQuotaPolicyToFgsJobs() ? ActivityManager.PROCESS_STATE_BOUND_TOP :
+                ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE;
+    }
+
     private class QcHandler extends Handler {
 
         QcHandler(Looper looper) {
@@ -2832,15 +2843,15 @@
                                 mTopAppCache.put(uid, true);
                                 mTopAppGraceCache.delete(uid);
                                 if (mForegroundUids.get(uid)) {
-                                    // Went from FGS to TOP. We don't need to reprocess timers or
-                                    // jobs.
+                                    // Went from a process state with quota free to TOP. We don't
+                                    // need to reprocess timers or jobs.
                                     break;
                                 }
                                 mForegroundUids.put(uid, true);
                                 isQuotaFree = true;
                             } else {
                                 final boolean reprocess;
-                                if (procState <= ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE) {
+                                if (procState <= getProcessStateQuotaFreeThreshold()) {
                                     reprocess = !mForegroundUids.get(uid);
                                     mForegroundUids.put(uid, true);
                                     isQuotaFree = true;
diff --git a/api/api.go b/api/api.go
index e9f1fee..1bbf370 100644
--- a/api/api.go
+++ b/api/api.go
@@ -514,7 +514,7 @@
 func combinedApisModuleFactory() android.Module {
 	module := &CombinedApis{}
 	module.AddProperties(&module.properties)
-	android.InitAndroidModule(module)
+	android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon)
 	android.AddLoadHook(module, func(ctx android.LoadHookContext) { module.createInternalModules(ctx) })
 	return module
 }
diff --git a/cmds/bootanimation/Android.bp b/cmds/bootanimation/Android.bp
index 3534624..f80ccf7 100644
--- a/cmds/bootanimation/Android.bp
+++ b/cmds/bootanimation/Android.bp
@@ -7,6 +7,18 @@
     default_applicable_licenses: ["frameworks_base_license"],
 }
 
+aconfig_declarations {
+    name: "bootanimation_flags",
+    package: "com.android.graphics.bootanimation.flags",
+    container: "system",
+    srcs: ["bootanimation_flags.aconfig"],
+}
+
+cc_aconfig_library {
+    name: "libbootanimationflags",
+    aconfig_declarations: "bootanimation_flags",
+}
+
 cc_defaults {
     name: "bootanimation_defaults",
 
@@ -28,6 +40,10 @@
         "liblog",
         "libutils",
     ],
+
+    static_libs: [
+        "libbootanimationflags",
+    ],
 }
 
 // bootanimation executable
diff --git a/cmds/bootanimation/BootAnimation.cpp b/cmds/bootanimation/BootAnimation.cpp
index c2f6e30..14e2387 100644
--- a/cmds/bootanimation/BootAnimation.cpp
+++ b/cmds/bootanimation/BootAnimation.cpp
@@ -15,6 +15,7 @@
  */
 
 #define LOG_NDEBUG 0
+
 #define LOG_TAG "BootAnimation"
 #define ATRACE_TAG ATRACE_TAG_GRAPHICS
 
@@ -61,6 +62,8 @@
 
 #include "BootAnimation.h"
 
+#include <com_android_graphics_bootanimation_flags.h>
+
 #define ANIM_PATH_MAX 255
 #define STR(x)   #x
 #define STRTO(x) STR(x)
@@ -106,7 +109,6 @@
 static const int TEXT_MISSING_VALUE = INT_MIN;
 static const char EXIT_PROP_NAME[] = "service.bootanim.exit";
 static const char PROGRESS_PROP_NAME[] = "service.bootanim.progress";
-static const char DISPLAYS_PROP_NAME[] = "persist.service.bootanim.displays";
 static const char CLOCK_ENABLED_PROP_NAME[] = "persist.sys.bootanim.clock.enabled";
 static const int ANIM_ENTRY_NAME_MAX = ANIM_PATH_MAX + 1;
 static const int MAX_CHECK_EXIT_INTERVAL_US = 50000;
@@ -449,19 +451,21 @@
                     auto token = SurfaceComposerClient::getPhysicalDisplayToken(
                         event.header.displayId);
 
-                    if (token != mBootAnimation->mDisplayToken) {
+                    auto firstDisplay = mBootAnimation->mDisplays.front();
+                    if (token != firstDisplay.displayToken) {
                         // ignore hotplug of a secondary display
                         continue;
                     }
 
                     DisplayMode displayMode;
                     const status_t error = SurfaceComposerClient::getActiveDisplayMode(
-                        mBootAnimation->mDisplayToken, &displayMode);
+                                               firstDisplay.displayToken, &displayMode);
                     if (error != NO_ERROR) {
                         SLOGE("Can't get active display mode.");
                     }
                     mBootAnimation->resizeSurface(displayMode.resolution.getWidth(),
-                        displayMode.resolution.getHeight());
+                                                  displayMode.resolution.getHeight(),
+                                                  firstDisplay);
                 }
             }
         } while (numEvents > 0);
@@ -507,141 +511,106 @@
 status_t BootAnimation::readyToRun() {
     ATRACE_CALL();
     mAssets.addDefaultAssets();
+    return initDisplaysAndSurfaces();
+}
 
-    const std::vector<PhysicalDisplayId> ids = SurfaceComposerClient::getPhysicalDisplayIds();
-    if (ids.empty()) {
-        SLOGE("Failed to get ID for any displays\n");
+status_t BootAnimation::initDisplaysAndSurfaces() {
+    std::vector<PhysicalDisplayId> displayIds = SurfaceComposerClient::getPhysicalDisplayIds();
+    if (displayIds.empty()) {
+        SLOGE("Failed to get ID for any displays");
         return NAME_NOT_FOUND;
     }
 
-    // this system property specifies multi-display IDs to show the boot animation
-    // multiple ids can be set with comma (,) as separator, for example:
-    // setprop persist.boot.animation.displays 19260422155234049,19261083906282754
-    Vector<PhysicalDisplayId> physicalDisplayIds;
-    char displayValue[PROPERTY_VALUE_MAX] = "";
-    property_get(DISPLAYS_PROP_NAME, displayValue, "");
-    bool isValid = displayValue[0] != '\0';
-    if (isValid) {
-        char *p = displayValue;
-        while (*p) {
-            if (!isdigit(*p) && *p != ',') {
-                isValid = false;
-                break;
-            }
-            p ++;
-        }
-        if (!isValid)
-            SLOGE("Invalid syntax for the value of system prop: %s", DISPLAYS_PROP_NAME);
-    }
-    if (isValid) {
-        std::istringstream stream(displayValue);
-        for (PhysicalDisplayId id; stream >> id.value; ) {
-            physicalDisplayIds.add(id);
-            if (stream.peek() == ',')
-                stream.ignore();
-        }
-
-        // the first specified display id is used to retrieve mDisplayToken
-        for (const auto id : physicalDisplayIds) {
-            if (std::find(ids.begin(), ids.end(), id) != ids.end()) {
-                if (const auto token = SurfaceComposerClient::getPhysicalDisplayToken(id)) {
-                    mDisplayToken = token;
-                    break;
-                }
-            }
-        }
+    // If Multi-Display isn't explicitly enabled, ignore all displays after the first one
+    if (!com::android::graphics::bootanimation::flags::multidisplay()) {
+        displayIds.erase(displayIds.begin() + 1, displayIds.end());
     }
 
-    // If the system property is not present or invalid, display 0 is used
-    if (mDisplayToken == nullptr) {
-        mDisplayToken = SurfaceComposerClient::getPhysicalDisplayToken(ids.front());
-        if (mDisplayToken == nullptr) {
+    for (const auto id : displayIds) {
+        if (const auto token = SurfaceComposerClient::getPhysicalDisplayToken(id)) {
+            mDisplays.push_back({.displayToken = token});
+        } else {
+            SLOGE("Failed to get display token for a display");
+            SLOGE("Failed to get display token for display %" PRIu64, id.value);
             return NAME_NOT_FOUND;
         }
     }
 
-    DisplayMode displayMode;
-    const status_t error =
-            SurfaceComposerClient::getActiveDisplayMode(mDisplayToken, &displayMode);
-    if (error != NO_ERROR) {
-        return error;
-    }
+    // Initialize EGL
+    mEgl = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+    eglInitialize(mEgl, nullptr, nullptr);
+    EGLConfig config = getEglConfig(mEgl);
+    EGLint contextAttributes[] = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE};
+    mEglContext = eglCreateContext(mEgl, config, nullptr, contextAttributes);
 
     mMaxWidth = android::base::GetIntProperty("ro.surface_flinger.max_graphics_width", 0);
     mMaxHeight = android::base::GetIntProperty("ro.surface_flinger.max_graphics_height", 0);
-    ui::Size resolution = displayMode.resolution;
-    resolution = limitSurfaceSize(resolution.width, resolution.height);
-    // create the native surface
-    sp<SurfaceControl> control = session()->createSurface(String8("BootAnimation"),
-            resolution.getWidth(), resolution.getHeight(), PIXEL_FORMAT_RGB_565,
-            ISurfaceComposerClient::eOpaque);
 
-    SurfaceComposerClient::Transaction t;
-    if (isValid) {
-        // In the case of multi-display, boot animation shows on the specified displays
-        for (const auto id : physicalDisplayIds) {
-            if (std::find(ids.begin(), ids.end(), id) != ids.end()) {
-                if (const auto token = SurfaceComposerClient::getPhysicalDisplayToken(id)) {
-                    t.setDisplayLayerStack(token, ui::DEFAULT_LAYER_STACK);
-                }
-            }
+    for (size_t displayIdx = 0; displayIdx < mDisplays.size(); displayIdx++) {
+        auto& display = mDisplays[displayIdx];
+        DisplayMode displayMode;
+        const status_t error =
+                SurfaceComposerClient::getActiveDisplayMode(display.displayToken, &displayMode);
+        if (error != NO_ERROR) {
+            return error;
         }
-        t.setLayerStack(control, ui::DEFAULT_LAYER_STACK);
-    }
+        ui::Size resolution = displayMode.resolution;
+        // Clamp each surface to max size
+        resolution = limitSurfaceSize(resolution.width, resolution.height);
+        // Create the native surface
+        display.surfaceControl =
+                session()->createSurface(String8("BootAnimation"), resolution.width,
+                                         resolution.height, PIXEL_FORMAT_RGB_565,
+                                         ISurfaceComposerClient::eOpaque);
+        // Attach surface to layerstack, and associate layerstack with physical display
+        configureDisplayAndLayerStack(display, ui::LayerStack::fromValue(displayIdx));
+        display.surface = display.surfaceControl->getSurface();
+        display.eglSurface = eglCreateWindowSurface(mEgl, config, display.surface.get(), nullptr);
 
-    t.setLayer(control, 0x40000000)
-        .apply();
+        EGLint w, h;
+        eglQuerySurface(mEgl, display.eglSurface, EGL_WIDTH, &w);
+        eglQuerySurface(mEgl, display.eglSurface, EGL_HEIGHT, &h);
+        if (eglMakeCurrent(mEgl, display.eglSurface, display.eglSurface,
+                           mEglContext) == EGL_FALSE) {
+            return NO_INIT;
+        }
+        display.initWidth = display.width = w;
+        display.initHeight = display.height = h;
+        mTargetInset = -1;
 
-    sp<Surface> s = control->getSurface();
+        // Rotate the boot animation according to the value specified in the sysprop
+        // ro.bootanim.set_orientation_<display_id>. Four values are supported: ORIENTATION_0,
+        // ORIENTATION_90, ORIENTATION_180 and ORIENTATION_270.
+        // If the value isn't specified or is ORIENTATION_0, nothing will be changed.
+        // This is needed to support boot animation in orientations different from the natural
+        // device orientation. For example, on tablets that may want to keep natural orientation
+        // portrait for applications compatibility and to have the boot animation in landscape.
+        rotateAwayFromNaturalOrientationIfNeeded(display);
 
-    // initialize opengl and egl
-    EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
-    eglInitialize(display, nullptr, nullptr);
-    EGLConfig config = getEglConfig(display);
-    EGLSurface surface = eglCreateWindowSurface(display, config, s.get(), nullptr);
-    // Initialize egl context with client version number 2.0.
-    EGLint contextAttributes[] = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE};
-    EGLContext context = eglCreateContext(display, config, nullptr, contextAttributes);
-    EGLint w, h;
-    eglQuerySurface(display, surface, EGL_WIDTH, &w);
-    eglQuerySurface(display, surface, EGL_HEIGHT, &h);
-
-    if (eglMakeCurrent(display, surface, surface, context) == EGL_FALSE) {
-        return NO_INIT;
-    }
-
-    mDisplay = display;
-    mContext = context;
-    mSurface = surface;
-    mInitWidth = mWidth = w;
-    mInitHeight = mHeight = h;
-    mFlingerSurfaceControl = control;
-    mFlingerSurface = s;
-    mTargetInset = -1;
-
-    // Rotate the boot animation according to the value specified in the sysprop
-    // ro.bootanim.set_orientation_<display_id>. Four values are supported: ORIENTATION_0,
-    // ORIENTATION_90, ORIENTATION_180 and ORIENTATION_270.
-    // If the value isn't specified or is ORIENTATION_0, nothing will be changed.
-    // This is needed to support having boot animation in orientations different from the natural
-    // device orientation. For example, on tablets that may want to keep natural orientation
-    // portrait for applications compatibility and to have the boot animation in landscape.
-    rotateAwayFromNaturalOrientationIfNeeded();
-
-    projectSceneToWindow();
+        projectSceneToWindow(display);
+    } // end iteration over all display tokens
 
     // Register a display event receiver
     mDisplayEventReceiver = std::make_unique<DisplayEventReceiver>();
     status_t status = mDisplayEventReceiver->initCheck();
     SLOGE_IF(status != NO_ERROR, "Initialization of DisplayEventReceiver failed with status: %d",
-            status);
+             status);
     mLooper->addFd(mDisplayEventReceiver->getFd(), 0, Looper::EVENT_INPUT,
-            new DisplayEventCallback(this), nullptr);
+                   new DisplayEventCallback(this), nullptr);
 
     return NO_ERROR;
 }
 
-void BootAnimation::rotateAwayFromNaturalOrientationIfNeeded() {
+void BootAnimation::configureDisplayAndLayerStack(const Display& display,
+                                                  ui::LayerStack layerStack) {
+    SurfaceComposerClient::Transaction t;
+    t.setDisplayLayerStack(display.displayToken, layerStack);
+    t.setLayerStack(display.surfaceControl, layerStack)
+     .setLayer(display.surfaceControl, 0x40000000)
+     .apply();
+}
+
+void BootAnimation::rotateAwayFromNaturalOrientationIfNeeded(Display& display) {
     ATRACE_CALL();
     const auto orientation = parseOrientationProperty();
 
@@ -651,16 +620,16 @@
     }
 
     if (orientation == ui::ROTATION_90 || orientation == ui::ROTATION_270) {
-        std::swap(mWidth, mHeight);
-        std::swap(mInitWidth, mInitHeight);
-        mFlingerSurfaceControl->updateDefaultBufferSize(mWidth, mHeight);
+        std::swap(display.width, display.height);
+        std::swap(display.initWidth, display.initHeight);
+        display.surfaceControl->updateDefaultBufferSize(display.width, display.height);
     }
 
-    Rect displayRect(0, 0, mWidth, mHeight);
-    Rect layerStackRect(0, 0, mWidth, mHeight);
+    Rect displayRect(0, 0, display.width, display.height);
+    Rect layerStackRect(0, 0, display.width, display.height);
 
     SurfaceComposerClient::Transaction t;
-    t.setDisplayProjection(mDisplayToken, orientation, layerStackRect, displayRect);
+    t.setDisplayProjection(display.displayToken, orientation, layerStackRect, displayRect);
     t.apply();
 }
 
@@ -691,38 +660,37 @@
     return ui::ROTATION_0;
 }
 
-void BootAnimation::projectSceneToWindow() {
+void BootAnimation::projectSceneToWindow(const Display& display) {
     ATRACE_CALL();
-    glViewport(0, 0, mWidth, mHeight);
-    glScissor(0, 0, mWidth, mHeight);
+    glViewport(0, 0, display.width, display.height);
+    glScissor(0, 0, display.width, display.height);
 }
 
-void BootAnimation::resizeSurface(int newWidth, int newHeight) {
+void BootAnimation::resizeSurface(int newWidth, int newHeight, Display& display) {
     ATRACE_CALL();
     // We assume this function is called on the animation thread.
-    if (newWidth == mWidth && newHeight == mHeight) {
+    if (newWidth == display.width && newHeight == display.height) {
         return;
     }
-    SLOGV("Resizing the boot animation surface to %d %d", newWidth, newHeight);
 
-    eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
-    eglDestroySurface(mDisplay, mSurface);
+    eglMakeCurrent(mEgl, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+    eglDestroySurface(mEgl, display.eglSurface);
 
     const auto limitedSize = limitSurfaceSize(newWidth, newHeight);
-    mWidth = limitedSize.width;
-    mHeight = limitedSize.height;
+    display.width = limitedSize.width;
+    display.height = limitedSize.height;
 
-    mFlingerSurfaceControl->updateDefaultBufferSize(mWidth, mHeight);
-    EGLConfig config = getEglConfig(mDisplay);
-    EGLSurface surface = eglCreateWindowSurface(mDisplay, config, mFlingerSurface.get(), nullptr);
-    if (eglMakeCurrent(mDisplay, surface, surface, mContext) == EGL_FALSE) {
-        SLOGE("Can't make the new surface current. Error %d", eglGetError());
+    display.surfaceControl->updateDefaultBufferSize(display.width, display.height);
+    EGLConfig config = getEglConfig(mEgl);
+    EGLSurface eglSurface = eglCreateWindowSurface(mEgl, config, display.surface.get(), nullptr);
+    if (eglMakeCurrent(mEgl, eglSurface, eglSurface, mEglContext) == EGL_FALSE) {
+        SLOGE("Can't make the new eglSurface current. Error %d", eglGetError());
         return;
     }
 
-    projectSceneToWindow();
+    projectSceneToWindow(display);
 
-    mSurface = surface;
+    display.eglSurface = eglSurface;
 }
 
 bool BootAnimation::preloadAnimation() {
@@ -852,24 +820,26 @@
     // animation.
     if (mZipFileName.empty()) {
         ALOGD("No animation file");
-        result = android();
+        result = android(mDisplays.front());
     } else {
         result = movie();
     }
 
     mCallbacks->shutdown();
-    eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
-    eglDestroyContext(mDisplay, mContext);
-    eglDestroySurface(mDisplay, mSurface);
-    mFlingerSurface.clear();
-    mFlingerSurfaceControl.clear();
-    eglTerminate(mDisplay);
+    eglMakeCurrent(mEgl, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+    eglDestroyContext(mEgl, mEglContext);
+    for (auto& display : mDisplays) {
+        eglDestroySurface(mEgl, display.eglSurface);
+        display.surface.clear();
+        display.surfaceControl.clear();
+    }
+    eglTerminate(mEgl);
     eglReleaseThread();
     IPCThreadState::self()->stopProcess();
     return result;
 }
 
-bool BootAnimation::android() {
+bool BootAnimation::android(const Display& display) {
     ATRACE_CALL();
     glActiveTexture(GL_TEXTURE0);
 
@@ -887,7 +857,7 @@
 
     glClearColor(0,0,0,1);
     glClear(GL_COLOR_BUFFER_BIT);
-    eglSwapBuffers(mDisplay, mSurface);
+    eglSwapBuffers(mEgl, display.eglSurface);
 
     // Blend state
     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
@@ -895,11 +865,11 @@
     const nsecs_t startTime = systemTime();
     do {
         processDisplayEvents();
-        const GLint xc = (mWidth  - mAndroid[0].w) / 2;
-        const GLint yc = (mHeight - mAndroid[0].h) / 2;
+        const GLint xc = (display.width  - mAndroid[0].w) / 2;
+        const GLint yc = (display.height - mAndroid[0].h) / 2;
         const Rect updateRect(xc, yc, xc + mAndroid[0].w, yc + mAndroid[0].h);
-        glScissor(updateRect.left, mHeight - updateRect.bottom, updateRect.width(),
-                updateRect.height());
+        glScissor(updateRect.left, display.height - updateRect.bottom, updateRect.width(),
+                  updateRect.height());
 
         nsecs_t now = systemTime();
         double time = now - startTime;
@@ -913,14 +883,14 @@
         glEnable(GL_SCISSOR_TEST);
         glDisable(GL_BLEND);
         glBindTexture(GL_TEXTURE_2D, mAndroid[1].name);
-        drawTexturedQuad(x,                 yc, mAndroid[1].w, mAndroid[1].h);
-        drawTexturedQuad(x + mAndroid[1].w, yc, mAndroid[1].w, mAndroid[1].h);
+        drawTexturedQuad(x,                 yc, mAndroid[1].w, mAndroid[1].h, display);
+        drawTexturedQuad(x + mAndroid[1].w, yc, mAndroid[1].w, mAndroid[1].h, display);
 
         glEnable(GL_BLEND);
         glBindTexture(GL_TEXTURE_2D, mAndroid[0].name);
-        drawTexturedQuad(xc, yc, mAndroid[0].w, mAndroid[0].h);
+        drawTexturedQuad(xc, yc, mAndroid[0].w, mAndroid[0].h, display);
 
-        EGLBoolean res = eglSwapBuffers(mDisplay, mSurface);
+        EGLBoolean res = eglSwapBuffers(mEgl, display.eglSurface);
         if (res == EGL_FALSE)
             break;
 
@@ -939,7 +909,7 @@
 
 void BootAnimation::checkExit() {
     ATRACE_CALL();
-    // Allow surface flinger to gracefully request shutdown
+    // Allow SurfaceFlinger to gracefully request shutdown
     char value[PROPERTY_VALUE_MAX];
     property_get(EXIT_PROP_NAME, value, "0");
     int exitnow = atoi(value);
@@ -1085,7 +1055,8 @@
     return status;
 }
 
-void BootAnimation::drawText(const char* str, const Font& font, bool bold, int* x, int* y) {
+void BootAnimation::drawText(const char* str, const Font& font, bool bold,
+                             int* x, int* y, const Display& display) {
     ATRACE_CALL();
     glEnable(GL_BLEND);  // Allow us to draw on top of the animation
     glBindTexture(GL_TEXTURE_2D, font.texture.name);
@@ -1096,14 +1067,14 @@
     const int strWidth = font.char_width * len;
 
     if (*x == TEXT_CENTER_VALUE) {
-        *x = (mWidth - strWidth) / 2;
+        *x = (display.width - strWidth) / 2;
     } else if (*x < 0) {
-        *x = mWidth + *x - strWidth;
+        *x = display.width + *x - strWidth;
     }
     if (*y == TEXT_CENTER_VALUE) {
-        *y = (mHeight - font.char_height) / 2;
+        *y = (display.height - font.char_height) / 2;
     } else if (*y < 0) {
-        *y = mHeight + *y - font.char_height;
+        *y = display.height + *y - font.char_height;
     }
 
     for (int i = 0; i < len; i++) {
@@ -1123,7 +1094,7 @@
         float v1 = v0 + 1.0f / FONT_NUM_ROWS / 2;
         float u1 = u0 + 1.0f / FONT_NUM_COLS;
         glUniform4f(mTextCropAreaLocation, u0, v0, u1, v1);
-        drawTexturedQuad(*x, *y, font.char_width, font.char_height);
+        drawTexturedQuad(*x, *y, font.char_width, font.char_height, display);
 
         *x += font.char_width;
     }
@@ -1133,7 +1104,8 @@
 }
 
 // We render 12 or 24 hour time.
-void BootAnimation::drawClock(const Font& font, const int xPos, const int yPos) {
+void BootAnimation::drawClock(const Font& font, const int xPos, const int yPos,
+                              const Display& display) {
     ATRACE_CALL();
     static constexpr char TIME_FORMAT_12[] = "%l:%M";
     static constexpr char TIME_FORMAT_24[] = "%H:%M";
@@ -1156,10 +1128,11 @@
     char* out = timeBuff[0] == ' ' ? &timeBuff[1] : &timeBuff[0];
     int x = xPos;
     int y = yPos;
-    drawText(out, font, false, &x, &y);
+    drawText(out, font, false, &x, &y, display);
 }
 
-void BootAnimation::drawProgress(int percent, const Font& font, const int xPos, const int yPos) {
+void BootAnimation::drawProgress(int percent, const Font& font, const int xPos, const int yPos,
+                                 const Display& display) {
     ATRACE_CALL();
     static constexpr int PERCENT_LENGTH = 5;
 
@@ -1169,7 +1142,7 @@
     sprintf(percentBuff, "%d;", percent);
     int x = xPos;
     int y = yPos;
-    drawText(percentBuff, font, false, &x, &y);
+    drawText(percentBuff, font, false, &x, &y, display);
 }
 
 bool BootAnimation::parseAnimationDesc(Animation& animation)  {
@@ -1298,8 +1271,7 @@
 
 bool BootAnimation::preloadZip(Animation& animation) {
     ATRACE_CALL();
-    // read all the data structures
-    const size_t pcount = animation.parts.size();
+    const size_t numParts = animation.parts.size();
     void *cookie = nullptr;
     ZipFileRO* zip = animation.zip;
     if (!zip->startIteration(&cookie)) {
@@ -1335,8 +1307,8 @@
                 continue;
             }
 
-            for (size_t j = 0; j < pcount; j++) {
-                if (path.string() == animation.parts[j].path.c_str()) {
+            for (size_t partIdx = 0; partIdx < numParts; partIdx++) {
+                if (path.string() == animation.parts[partIdx].path.c_str()) {
                     uint16_t method;
                     // supports only stored png files
                     if (zip->getEntryInfo(entry, &method, nullptr, nullptr, nullptr, nullptr,
@@ -1344,7 +1316,7 @@
                         if (method == ZipFileRO::kCompressStored) {
                             FileMap* map = zip->createEntryFileMap(entry);
                             if (map) {
-                                Animation::Part& part(animation.parts.editItemAt(j));
+                                Animation::Part& part(animation.parts.editItemAt(partIdx));
                                 if (leaf == "audio.wav") {
                                     // a part may have at most one audio file
                                     part.audioData = (uint8_t *)map->getDataPtr();
@@ -1375,7 +1347,8 @@
     // If there is trimData present, override the positioning defaults.
     for (Animation::Part& part : animation.parts) {
         const char* trimDataStr = part.trimData.c_str();
-        for (size_t frameIdx = 0; frameIdx < part.frames.size(); frameIdx++) {
+        const size_t numFramesInPart = part.frames.size();
+        for (size_t frameIdxInPart = 0; frameIdxInPart < numFramesInPart; frameIdxInPart++) {
             const char* endl = strstr(trimDataStr, "\n");
             // No more trimData for this part.
             if (endl == nullptr) {
@@ -1386,7 +1359,7 @@
             trimDataStr = ++endl;
             int width = 0, height = 0, x = 0, y = 0;
             if (sscanf(lineStr, "%dx%d+%d+%d", &width, &height, &x, &y) == 4) {
-                Animation::Frame& frame(part.frames.editItemAt(frameIdx));
+                Animation::Frame& frame(part.frames.editItemAt(frameIdxInPart));
                 frame.trimWidth = width;
                 frame.trimHeight = height;
                 frame.trimX = x;
@@ -1509,13 +1482,15 @@
     return b1 + ( x - a1 ) * ( b2 - b1 ) / ( a2 - a1 );
 }
 
-void BootAnimation::drawTexturedQuad(float xStart, float yStart, float width, float height) {
+void BootAnimation::drawTexturedQuad(float xStart, float yStart,
+                                     float width, float height,
+                                     const Display& display) {
     ATRACE_CALL();
     // Map coordinates from screen space to world space.
-    float x0 = mapLinear(xStart, 0, mWidth, -1, 1);
-    float y0 = mapLinear(yStart, 0, mHeight, -1, 1);
-    float x1 = mapLinear(xStart + width, 0, mWidth, -1, 1);
-    float y1 = mapLinear(yStart + height, 0, mHeight, -1, 1);
+    float x0 = mapLinear(xStart, 0, display.width, -1, 1);
+    float y0 = mapLinear(yStart, 0, display.height, -1, 1);
+    float x1 = mapLinear(xStart + width, 0, display.width, -1, 1);
+    float y1 = mapLinear(yStart + height, 0, display.height, -1, 1);
     // Update quad vertex positions.
     quadPositions[0] = x0;
     quadPositions[1] = y0;
@@ -1562,7 +1537,7 @@
 
 bool BootAnimation::playAnimation(const Animation& animation) {
     ATRACE_CALL();
-    const size_t pcount = animation.parts.size();
+    const size_t numParts = animation.parts.size();
     nsecs_t frameDuration = s2ns(1) / animation.fps;
 
     SLOGD("%sAnimationShownTiming start time: %" PRId64 "ms", mShuttingDown ? "Shutdown" : "Boot",
@@ -1572,9 +1547,9 @@
     int lastDisplayedProgress = 0;
     int colorTransitionStart = animation.colorTransitionStart;
     int colorTransitionEnd = animation.colorTransitionEnd;
-    for (size_t i=0 ; i<pcount ; i++) {
-        const Animation::Part& part(animation.parts[i]);
-        const size_t fcount = part.frames.size();
+    for (size_t partIdx = 0; partIdx < numParts; partIdx++) {
+        const Animation::Part& part(animation.parts[partIdx]);
+        const size_t numFramesInPart = part.frames.size();
         glBindTexture(GL_TEXTURE_2D, 0);
 
         // Handle animation package
@@ -1586,7 +1561,9 @@
         }
 
         // process the part not only while the count allows but also if already fading
-        for (int r=0 ; !part.count || r<part.count || fadedFramesCount > 0 ; r++) {
+        for (int frameIdx = 0;
+             !part.count || frameIdx < part.count || fadedFramesCount > 0;
+             frameIdx++) {
             if (shouldStopPlayingPart(part, fadedFramesCount, lastDisplayedProgress)) break;
 
             // It's possible that the sysprops were not loaded yet at this boot phase.
@@ -1601,12 +1578,12 @@
                     const int transitionLength = colorTransitionEnd - colorTransitionStart;
                     if (part.postDynamicColoring) {
                         colorTransitionStart = 0;
-                        colorTransitionEnd = fmin(transitionLength, fcount - 1);
+                        colorTransitionEnd = fmin(transitionLength, numFramesInPart - 1);
                     }
                 }
             }
 
-            mCallbacks->playPart(i, part, r);
+            mCallbacks->playPart(partIdx, part, frameIdx);
 
             glClearColor(
                     part.backgroundColor[0],
@@ -1620,11 +1597,10 @@
 
             // For the last animation, if we have progress indicator from
             // the system, display it.
-            int currentProgress = android::base::GetIntProperty(PROGRESS_PROP_NAME, 0);
-            bool displayProgress = animation.progressEnabled &&
-                (i == (pcount -1)) && currentProgress != 0;
+            const bool displayProgress = animation.progressEnabled && (partIdx == (numParts - 1)) &&
+                    android::base::GetIntProperty(PROGRESS_PROP_NAME, 0) != 0;
 
-            for (size_t j=0 ; j<fcount ; j++) {
+            for (size_t frameIdxInPart = 0; frameIdxInPart < numFramesInPart; frameIdxInPart++) {
                 if (shouldStopPlayingPart(part, fadedFramesCount, lastDisplayedProgress)) break;
 
                 // Color progress is
@@ -1635,21 +1611,15 @@
                 // - 1 for parts that come after.
                 float colorProgress = part.useDynamicColoring
                     ? fmin(fmax(
-                        ((float)j - colorTransitionStart) /
+                        (static_cast<float>(frameIdxInPart) - colorTransitionStart) /
                             fmax(colorTransitionEnd - colorTransitionStart, 1.0f), 0.0f), 1.0f)
                     : (part.postDynamicColoring ? 1 : 0);
-
                 processDisplayEvents();
 
-                const double ratio_w = static_cast<double>(mWidth) / mInitWidth;
-                const double ratio_h = static_cast<double>(mHeight) / mInitHeight;
-                const int animationX = (mWidth - animation.width * ratio_w) / 2;
-                const int animationY = (mHeight - animation.height * ratio_h) / 2;
-
-                const Animation::Frame& frame(part.frames[j]);
+                const Animation::Frame& frame(part.frames[frameIdxInPart]);
                 nsecs_t lastFrame = systemTime();
 
-                if (r > 0) {
+                if (frameIdx > 0) {
                     glBindTexture(GL_TEXTURE_2D, frame.tid);
                 } else {
                     if (part.count != 1) {
@@ -1662,17 +1632,6 @@
                     initTexture(frame.map, &w, &h, false /* don't premultiply alpha */);
                 }
 
-                const int trimWidth = frame.trimWidth * ratio_w;
-                const int trimHeight = frame.trimHeight * ratio_h;
-                const int trimX = frame.trimX * ratio_w;
-                const int trimY = frame.trimY * ratio_h;
-                const int xc = animationX + trimX;
-                const int yc = animationY + trimY;
-                glClear(GL_COLOR_BUFFER_BIT);
-                // specify the y center as ceiling((mHeight - frame.trimHeight) / 2)
-                // which is equivalent to mHeight - (yc + frame.trimHeight)
-                const int frameDrawY = mHeight - (yc + trimHeight);
-
                 float fade = 0;
                 // if the part hasn't been stopped yet then continue fading if necessary
                 if (exitPending() && part.hasFadingPhase()) {
@@ -1681,40 +1640,66 @@
                         fadedFramesCount = MAX_FADED_FRAMES_COUNT; // no more fading
                     }
                 }
-                glUseProgram(mImageShader);
-                glUniform1i(mImageTextureLocation, 0);
-                glUniform1f(mImageFadeLocation, fade);
-                if (animation.dynamicColoringEnabled) {
-                    glUniform1f(mImageColorProgressLocation, colorProgress);
-                }
-                glEnable(GL_BLEND);
-                drawTexturedQuad(xc, frameDrawY, trimWidth, trimHeight);
-                glDisable(GL_BLEND);
 
-                if (mClockEnabled && mTimeIsAccurate && validClock(part)) {
-                    drawClock(animation.clockFont, part.clockPosX, part.clockPosY);
-                }
+                // Draw the current frame's texture on every physical display that is enabled.
+                for (const auto& display : mDisplays) {
+                    eglMakeCurrent(mEgl, display.eglSurface, display.eglSurface, mEglContext);
 
-                if (displayProgress) {
-                    int newProgress = android::base::GetIntProperty(PROGRESS_PROP_NAME, 0);
-                    // In case the new progress jumped suddenly, still show an
-                    // increment of 1.
-                    if (lastDisplayedProgress != 100) {
-                      // Artificially sleep 1/10th a second to slow down the animation.
-                      usleep(100000);
-                      if (lastDisplayedProgress < newProgress) {
-                        lastDisplayedProgress++;
-                      }
+                    const double ratioW =
+                            static_cast<double>(display.width) / display.initWidth;
+                    const double ratioH =
+                            static_cast<double>(display.height) / display.initHeight;
+                    const int animationX = (display.width - animation.width * ratioW) / 2;
+                    const int animationY = (display.height - animation.height * ratioH) / 2;
+
+                    const int trimWidth = frame.trimWidth * ratioW;
+                    const int trimHeight = frame.trimHeight * ratioH;
+                    const int trimX = frame.trimX * ratioW;
+                    const int trimY = frame.trimY * ratioH;
+                    const int xc = animationX + trimX;
+                    const int yc = animationY + trimY;
+                    projectSceneToWindow(display);
+                    handleViewport(frameDuration, display);
+                    glClear(GL_COLOR_BUFFER_BIT);
+                    // specify the y center as ceiling((height - frame.trimHeight) / 2)
+                    // which is equivalent to height - (yc + frame.trimHeight)
+                    const int frameDrawY = display.height - (yc + trimHeight);
+
+                    glUseProgram(mImageShader);
+                    glUniform1i(mImageTextureLocation, 0);
+                    glUniform1f(mImageFadeLocation, fade);
+                    if (animation.dynamicColoringEnabled) {
+                        glUniform1f(mImageColorProgressLocation, colorProgress);
                     }
-                    // Put the progress percentage right below the animation.
-                    int posY = animation.height / 3;
-                    int posX = TEXT_CENTER_VALUE;
-                    drawProgress(lastDisplayedProgress, animation.progressFont, posX, posY);
+                    glEnable(GL_BLEND);
+                    drawTexturedQuad(xc, frameDrawY, trimWidth, trimHeight, display);
+                    glDisable(GL_BLEND);
+
+                    if (mClockEnabled && mTimeIsAccurate && validClock(part)) {
+                        drawClock(animation.clockFont, part.clockPosX, part.clockPosY, display);
+                    }
+
+                    if (displayProgress) {
+                        int newProgress = android::base::GetIntProperty(PROGRESS_PROP_NAME, 0);
+                        // In case the new progress jumped suddenly, still show an
+                        // increment of 1.
+                        if (lastDisplayedProgress != 100) {
+                          // Artificially sleep 1/10th a second to slow down the animation.
+                          usleep(100000);
+                          if (lastDisplayedProgress < newProgress) {
+                            lastDisplayedProgress++;
+                          }
+                        }
+                        // Put the progress percentage right below the animation.
+                        int posY = animation.height / 3;
+                        int posX = TEXT_CENTER_VALUE;
+                        drawProgress(lastDisplayedProgress,
+                            animation.progressFont, posX, posY, display);
+                    }
+
+                    eglSwapBuffers(mEgl, display.eglSurface);
                 }
 
-                handleViewport(frameDuration);
-
-                eglSwapBuffers(mDisplay, mSurface);
 
                 nsecs_t now = systemTime();
                 nsecs_t delay = frameDuration - (now - lastFrame);
@@ -1760,9 +1745,7 @@
     // Free textures created for looping parts now that the animation is done.
     for (const Animation::Part& part : animation.parts) {
         if (part.count != 1) {
-            const size_t fcount = part.frames.size();
-            for (size_t j = 0; j < fcount; j++) {
-                const Animation::Frame& frame(part.frames[j]);
+            for (const auto& frame : part.frames) {
                 glDeleteTextures(1, &frame.tid);
             }
         }
@@ -1781,16 +1764,17 @@
     mLooper->pollOnce(0);
 }
 
-void BootAnimation::handleViewport(nsecs_t timestep) {
+void BootAnimation::handleViewport(nsecs_t timestep, const Display& display) {
     ATRACE_CALL();
-    if (mShuttingDown || !mFlingerSurfaceControl || mTargetInset == 0) {
+    if (mShuttingDown || !display.surfaceControl || mTargetInset == 0) {
         return;
     }
     if (mTargetInset < 0) {
         // Poll the amount for the top display inset. This will return -1 until persistent properties
         // have been loaded.
-        mTargetInset = android::base::GetIntProperty("persist.sys.displayinset.top",
-                -1 /* default */, -1 /* min */, mHeight / 2 /* max */);
+        mTargetInset =
+                android::base::GetIntProperty("persist.sys.displayinset.top", -1 /* default */,
+                                              -1 /* min */, display.height / 2 /* max */);
     }
     if (mTargetInset <= 0) {
         return;
@@ -1802,19 +1786,27 @@
         int interpolatedInset = (cosf((fraction + 1) * M_PI) / 2.0f + 0.5f) * mTargetInset;
 
         SurfaceComposerClient::Transaction()
-                .setCrop(mFlingerSurfaceControl, Rect(0, interpolatedInset, mWidth, mHeight))
+                .setCrop(display.surfaceControl,
+                         Rect(0, interpolatedInset, display.width, display.height))
                 .apply();
     } else {
         // At the end of the animation, we switch to the viewport that DisplayManager will apply
         // later. This changes the coordinate system, and means we must move the surface up by
         // the inset amount.
-        Rect layerStackRect(0, 0, mWidth, mHeight - mTargetInset);
-        Rect displayRect(0, mTargetInset, mWidth, mHeight);
-
+        Rect layerStackRect(0, 0,
+                display.width,
+                display.height - mTargetInset);
+        Rect displayRect(0, mTargetInset,
+                display.width,
+                display.height);
         SurfaceComposerClient::Transaction t;
-        t.setPosition(mFlingerSurfaceControl, 0, -mTargetInset)
-                .setCrop(mFlingerSurfaceControl, Rect(0, mTargetInset, mWidth, mHeight));
-        t.setDisplayProjection(mDisplayToken, ui::ROTATION_0, layerStackRect, displayRect);
+        t.setPosition(display.surfaceControl, 0, -mTargetInset)
+                .setCrop(display.surfaceControl,
+                         Rect(0, mTargetInset,
+                              display.width,
+                              display.height));
+        t.setDisplayProjection(display.displayToken,
+                ui::ROTATION_0, layerStackRect, displayRect);
         t.apply();
 
         mTargetInset = mCurrentInset = 0;
diff --git a/cmds/bootanimation/BootAnimation.h b/cmds/bootanimation/BootAnimation.h
index 8683b71..0a05746 100644
--- a/cmds/bootanimation/BootAnimation.h
+++ b/cmds/bootanimation/BootAnimation.h
@@ -31,6 +31,7 @@
 #include <binder/IBinder.h>
 
 #include <ui/Rotation.h>
+#include <ui/LayerStack.h>
 
 #include <EGL/egl.h>
 #include <GLES2/gl2.h>
@@ -119,6 +120,18 @@
         float endColors[4][3];   // End colors of dynamic color transition.
     };
 
+    // Collects all attributes that must be tracked per physical display.
+    struct Display {
+        int width;
+        int height;
+        int initWidth;
+        int initHeight;
+        EGLDisplay  eglSurface;
+        sp<IBinder> displayToken;
+        sp<SurfaceControl> surfaceControl;
+        sp<Surface> surface;
+    };
+
     // All callbacks will be called from this class's internal thread.
     class Callbacks : public RefBase {
     public:
@@ -181,14 +194,18 @@
         bool premultiplyAlpha = true);
     status_t initFont(Font* font, const char* fallback);
     void initShaders();
-    bool android();
+    bool android(const Display& display);
+    status_t initDisplaysAndSurfaces();
     bool movie();
-    void drawText(const char* str, const Font& font, bool bold, int* x, int* y);
-    void drawClock(const Font& font, const int xPos, const int yPos);
-    void drawProgress(int percent, const Font& font, const int xPos, const int yPos);
+    void drawText(const char* str, const Font& font, bool bold,
+                  int* x, int* y, const Display& display);
+    void drawClock(const Font& font, const int xPos, const int yPos, const Display& display);
+    void drawProgress(int percent, const Font& font,
+                      const int xPos, const int yPos, const Display& display);
     void fadeFrame(int frameLeft, int frameBottom, int frameWidth, int frameHeight,
                    const Animation::Part& part, int fadedFramesCount);
-    void drawTexturedQuad(float xStart, float yStart, float width, float height);
+    void drawTexturedQuad(float xStart, float yStart,
+                          float width, float height, const Display& display);
     bool validClock(const Animation::Part& part);
     Animation* loadAnimation(const String8&);
     bool playAnimation(const Animation&);
@@ -200,36 +217,31 @@
     bool preloadAnimation();
     EGLConfig getEglConfig(const EGLDisplay&);
     ui::Size limitSurfaceSize(int width, int height) const;
-    void resizeSurface(int newWidth, int newHeight);
-    void projectSceneToWindow();
-    void rotateAwayFromNaturalOrientationIfNeeded();
+    void resizeSurface(int newWidth, int newHeight, Display& display);
+    void projectSceneToWindow(const Display& display);
+    void rotateAwayFromNaturalOrientationIfNeeded(Display& display);
     ui::Rotation parseOrientationProperty();
+    void configureDisplayAndLayerStack(const Display& display, ui::LayerStack layerStack);
 
     bool shouldStopPlayingPart(const Animation::Part& part, int fadedFramesCount,
                                int lastDisplayedProgress);
     void checkExit();
 
-    void handleViewport(nsecs_t timestep);
+    void handleViewport(nsecs_t timestep, const Display& display);
     void initDynamicColors();
 
     sp<SurfaceComposerClient>       mSession;
     AssetManager mAssets;
     Texture     mAndroid[2];
-    int         mWidth;
-    int         mHeight;
-    int         mInitWidth;
-    int         mInitHeight;
     int         mMaxWidth = 0;
     int         mMaxHeight = 0;
     int         mCurrentInset;
     int         mTargetInset;
     bool        mUseNpotTextures = false;
-    EGLDisplay  mDisplay;
-    EGLDisplay  mContext;
-    EGLDisplay  mSurface;
-    sp<IBinder> mDisplayToken;
-    sp<SurfaceControl> mFlingerSurfaceControl;
-    sp<Surface> mFlingerSurface;
+    EGLDisplay  mEgl;
+    EGLDisplay  mEglContext;
+    // Per-Display Attributes (to support multi-display)
+    std::vector<Display> mDisplays;
     bool        mClockEnabled;
     bool        mTimeIsAccurate;
     bool        mTimeFormat12Hour;
diff --git a/cmds/bootanimation/bootanimation_flags.aconfig b/cmds/bootanimation/bootanimation_flags.aconfig
new file mode 100644
index 0000000..04837b9
--- /dev/null
+++ b/cmds/bootanimation/bootanimation_flags.aconfig
@@ -0,0 +1,12 @@
+package: "com.android.graphics.bootanimation.flags"
+container: "system"
+
+flag {
+  name: "multidisplay"
+  namespace: "bootanimation"
+  description: "Enable boot animation on multiple displays (e.g. foldables)"
+  bug: "335406617"
+  is_fixed_read_only: true
+}
+
+
diff --git a/cmds/hid/Android.bp b/cmds/hid/Android.bp
index a6e2769..b93227a 100644
--- a/cmds/hid/Android.bp
+++ b/cmds/hid/Android.bp
@@ -22,5 +22,5 @@
     name: "hid",
     wrapper: "hid.sh",
     srcs: ["**/*.java"],
-    required: ["libhidcommand_jni"],
+    jni_libs: ["libhidcommand_jni"],
 }
diff --git a/cmds/idmap2/include/idmap2/Idmap.h b/cmds/idmap2/include/idmap2/Idmap.h
index e86f814..b0ba019 100644
--- a/cmds/idmap2/include/idmap2/Idmap.h
+++ b/cmds/idmap2/include/idmap2/Idmap.h
@@ -21,18 +21,19 @@
  * header                     := magic version target_crc overlay_crc fulfilled_policies
  *                               enforce_overlayable target_path overlay_path overlay_name
  *                               debug_info
- * data                       := data_header target_entry* target_inline_entry*
-                                 target_inline_entry_value* config* overlay_entry* string_pool
+ * data                       := data_header target_entries target_inline_entries
+                                 target_inline_entry_value* config* overlay_entries string_pool
  * data_header                := target_entry_count target_inline_entry_count
                                  target_inline_entry_value_count config_count overlay_entry_count
  *                               string_pool_index
- * target_entry               := target_id overlay_id
- * target_inline_entry        := target_id start_value_index value_count
+ * target_entries             := target_id* overlay_id*
+ * target_inline_entries      := target_id* target_inline_value_header*
+ * target_inline_value_header := start_value_index value_count
  * target_inline_entry_value  := config_index Res_value::size padding(1) Res_value::type
  *                               Res_value::value
  * config                     := target_id Res_value::size padding(1) Res_value::type
  *                               Res_value::value
- * overlay_entry              := overlay_id target_id
+ * overlay_entries            := overlay_id* target_id*
  *
  * debug_info                       := string
  * enforce_overlayable              := <uint32_t>
diff --git a/cmds/idmap2/libidmap2/BinaryStreamVisitor.cpp b/cmds/idmap2/libidmap2/BinaryStreamVisitor.cpp
index 8976924..00ef0c7 100644
--- a/cmds/idmap2/libidmap2/BinaryStreamVisitor.cpp
+++ b/cmds/idmap2/libidmap2/BinaryStreamVisitor.cpp
@@ -66,43 +66,57 @@
 void BinaryStreamVisitor::visit(const IdmapData& data) {
   for (const auto& target_entry : data.GetTargetEntries()) {
     Write32(target_entry.target_id);
+  }
+  for (const auto& target_entry : data.GetTargetEntries()) {
     Write32(target_entry.overlay_id);
   }
 
-  static constexpr uint16_t kValueSize = 8U;
-  std::vector<std::pair<ConfigDescription, TargetValue>> target_values;
-  target_values.reserve(data.GetHeader()->GetTargetInlineEntryValueCount());
-  for (const auto& target_entry : data.GetTargetInlineEntries()) {
-    Write32(target_entry.target_id);
-    Write32(target_values.size());
-    Write32(target_entry.values.size());
-    target_values.insert(
-        target_values.end(), target_entry.values.begin(), target_entry.values.end());
+  uint32_t current_inline_entry_values_count = 0;
+  for (const auto& target_inline_entry : data.GetTargetInlineEntries()) {
+    Write32(target_inline_entry.target_id);
+  }
+  for (const auto& target_inline_entry : data.GetTargetInlineEntries()) {
+    Write32(current_inline_entry_values_count);
+    Write32(target_inline_entry.values.size());
+    current_inline_entry_values_count += target_inline_entry.values.size();
   }
 
   std::vector<ConfigDescription> configs;
   configs.reserve(data.GetHeader()->GetConfigCount());
-  for (const auto& target_entry_value : target_values) {
-    auto config_it = find(configs.begin(), configs.end(), target_entry_value.first);
-    if (config_it != configs.end()) {
-      Write32(config_it - configs.begin());
-    } else {
-      Write32(configs.size());
-      configs.push_back(target_entry_value.first);
+  for (const auto& target_entry : data.GetTargetInlineEntries()) {
+    for (const auto& target_entry_value : target_entry.values) {
+      auto config_it = std::find(configs.begin(), configs.end(), target_entry_value.first);
+      if (config_it != configs.end()) {
+        Write32(config_it - configs.begin());
+      } else {
+        Write32(configs.size());
+        configs.push_back(target_entry_value.first);
+      }
+      // We're writing a Res_value entry here, and the first 3 bytes of that are
+      // sizeof() + a padding 0 byte
+      static constexpr decltype(android::Res_value::size) kSize = sizeof(android::Res_value);
+      Write16(kSize);
+      Write8(0U);
+      Write8(target_entry_value.second.data_type);
+      Write32(target_entry_value.second.data_value);
     }
-    Write16(kValueSize);
-    Write8(0U);  // padding
-    Write8(target_entry_value.second.data_type);
-    Write32(target_entry_value.second.data_value);
   }
 
-  for( auto& cd : configs) {
-    cd.swapHtoD();
-    stream_.write(reinterpret_cast<char*>(&cd), sizeof(cd));
+  if (!configs.empty()) {
+    stream_.write(reinterpret_cast<const char*>(&configs.front()),
+                  sizeof(configs.front()) * configs.size());
+    if (configs.size() >= 100) {
+      // Let's write a message to future us so that they know when to replace the linear search
+      // in `configs` vector with something more efficient.
+      LOG(WARNING) << "Idmap got " << configs.size()
+                   << " configurations, time to fix the bruteforce search";
+    }
   }
 
   for (const auto& overlay_entry : data.GetOverlayEntries()) {
     Write32(overlay_entry.overlay_id);
+  }
+  for (const auto& overlay_entry : data.GetOverlayEntries()) {
     Write32(overlay_entry.target_id);
   }
 
diff --git a/cmds/idmap2/libidmap2/Idmap.cpp b/cmds/idmap2/libidmap2/Idmap.cpp
index 12d9dd9..7680109 100644
--- a/cmds/idmap2/libidmap2/Idmap.cpp
+++ b/cmds/idmap2/libidmap2/Idmap.cpp
@@ -204,73 +204,91 @@
   }
 
   // Read the mapping of target resource id to overlay resource value.
+  data->target_entries_.resize(data->header_->GetTargetEntryCount());
   for (size_t i = 0; i < data->header_->GetTargetEntryCount(); i++) {
-    TargetEntry target_entry{};
-    if (!Read32(stream, &target_entry.target_id) || !Read32(stream, &target_entry.overlay_id)) {
+    if (!Read32(stream, &data->target_entries_[i].target_id)) {
       return nullptr;
     }
-    data->target_entries_.emplace_back(target_entry);
+  }
+  for (size_t i = 0; i < data->header_->GetTargetEntryCount(); i++) {
+    if (!Read32(stream, &data->target_entries_[i].overlay_id)) {
+      return nullptr;
+    }
   }
 
   // Read the mapping of target resource id to inline overlay values.
-  std::vector<std::tuple<TargetInlineEntry, uint32_t, uint32_t>> target_inline_entries;
+  struct TargetInlineEntryHeader {
+    ResourceId target_id;
+    uint32_t values_offset;
+    uint32_t values_count;
+  };
+  std::vector<TargetInlineEntryHeader> target_inline_entries(
+      data->header_->GetTargetInlineEntryCount());
   for (size_t i = 0; i < data->header_->GetTargetInlineEntryCount(); i++) {
-    TargetInlineEntry target_entry{};
-    uint32_t entry_offset;
-    uint32_t entry_count;
-    if (!Read32(stream, &target_entry.target_id) || !Read32(stream, &entry_offset)
-        || !Read32(stream, &entry_count)) {
+    if (!Read32(stream, &target_inline_entries[i].target_id)) {
       return nullptr;
     }
-    target_inline_entries.emplace_back(target_entry, entry_offset, entry_count);
+  }
+  for (size_t i = 0; i < data->header_->GetTargetInlineEntryCount(); i++) {
+    if (!Read32(stream, &target_inline_entries[i].values_offset) ||
+        !Read32(stream, &target_inline_entries[i].values_count)) {
+      return nullptr;
+    }
   }
 
   // Read the inline overlay resource values
-  std::vector<std::pair<uint32_t, TargetValue>> target_values;
-  uint8_t unused1;
-  uint16_t unused2;
-  for (size_t i = 0; i < data->header_->GetTargetInlineEntryValueCount(); i++) {
+  struct TargetValueHeader {
     uint32_t config_index;
-    if (!Read32(stream, &config_index)) {
+    DataType data_type;
+    DataValue data_value;
+  };
+  std::vector<TargetValueHeader> target_values(data->header_->GetTargetInlineEntryValueCount());
+  for (size_t i = 0; i < data->header_->GetTargetInlineEntryValueCount(); i++) {
+    auto& value = target_values[i];
+    if (!Read32(stream, &value.config_index)) {
       return nullptr;
     }
-    TargetValue value;
-    if (!Read16(stream, &unused2)
-        || !Read8(stream, &unused1)
-        || !Read8(stream, &value.data_type)
-        || !Read32(stream, &value.data_value)) {
+    // skip the padding
+    stream.seekg(3, std::ios::cur);
+    if (!Read8(stream, &value.data_type) || !Read32(stream, &value.data_value)) {
       return nullptr;
     }
-    target_values.emplace_back(config_index, value);
   }
 
   // Read the configurations
-  std::vector<ConfigDescription> configurations;
-  for (size_t i = 0; i < data->header_->GetConfigCount(); i++) {
-    ConfigDescription cd;
-    if (!stream.read(reinterpret_cast<char*>(&cd), sizeof(ConfigDescription))) {
+  std::vector<ConfigDescription> configurations(data->header_->GetConfigCount());
+  if (!configurations.empty()) {
+    if (!stream.read(reinterpret_cast<char*>(&configurations.front()),
+                     sizeof(configurations.front()) * configurations.size())) {
       return nullptr;
     }
-    configurations.emplace_back(cd);
   }
 
   // Construct complete target inline entries
-  for (auto [target_entry, entry_offset, entry_count] : target_inline_entries) {
-    for(size_t i = 0; i < entry_count; i++) {
-      const auto& target_value = target_values[entry_offset + i];
-      const auto& config = configurations[target_value.first];
-      target_entry.values[config] = target_value.second;
+  data->target_inline_entries_.reserve(target_inline_entries.size());
+  for (auto&& entry_header : target_inline_entries) {
+    TargetInlineEntry& entry = data->target_inline_entries_.emplace_back();
+    entry.target_id = entry_header.target_id;
+    for (size_t i = 0; i < entry_header.values_count; i++) {
+      const auto& value_header = target_values[entry_header.values_offset + i];
+      const auto& config = configurations[value_header.config_index];
+      auto& value = entry.values[config];
+      value.data_type = value_header.data_type;
+      value.data_value = value_header.data_value;
     }
-    data->target_inline_entries_.emplace_back(target_entry);
   }
 
   // Read the mapping of overlay resource id to target resource id.
+  data->overlay_entries_.resize(data->header_->GetOverlayEntryCount());
   for (size_t i = 0; i < data->header_->GetOverlayEntryCount(); i++) {
-    OverlayEntry overlay_entry{};
-    if (!Read32(stream, &overlay_entry.overlay_id) || !Read32(stream, &overlay_entry.target_id)) {
+    if (!Read32(stream, &data->overlay_entries_[i].overlay_id)) {
       return nullptr;
     }
-    data->overlay_entries_.emplace_back(overlay_entry);
+  }
+  for (size_t i = 0; i < data->header_->GetOverlayEntryCount(); i++) {
+    if (!Read32(stream, &data->overlay_entries_[i].target_id)) {
+      return nullptr;
+    }
   }
 
   // Read raw string pool bytes.
@@ -320,7 +338,7 @@
   std::unique_ptr<IdmapData> data(new IdmapData());
   data->string_pool_data_ = std::string(resource_mapping.GetStringPoolData());
   uint32_t inline_value_count = 0;
-  std::set<std::string> config_set;
+  std::set<std::string_view> config_set;
   for (const auto& mapping : resource_mapping.GetTargetToOverlayMap()) {
     if (auto overlay_resource = std::get_if<ResourceId>(&mapping.second)) {
       data->target_entries_.push_back({mapping.first, *overlay_resource});
@@ -329,7 +347,9 @@
       for (const auto& [config, value] : std::get<ConfigMap>(mapping.second)) {
         config_set.insert(config);
         ConfigDescription cd;
-        ConfigDescription::Parse(config, &cd);
+        if (!ConfigDescription::Parse(config, &cd)) {
+          return Error("failed to parse configuration string '%s'", config.c_str());
+        }
         values[cd] = value;
         inline_value_count++;
       }
diff --git a/cmds/idmap2/tests/IdmapTests.cpp b/cmds/idmap2/tests/IdmapTests.cpp
index c85619c..1b656e8 100644
--- a/cmds/idmap2/tests/IdmapTests.cpp
+++ b/cmds/idmap2/tests/IdmapTests.cpp
@@ -68,7 +68,7 @@
   std::unique_ptr<const IdmapHeader> header = IdmapHeader::FromBinaryStream(stream);
   ASSERT_THAT(header, NotNull());
   ASSERT_EQ(header->GetMagic(), 0x504d4449U);
-  ASSERT_EQ(header->GetVersion(), 0x09U);
+  ASSERT_EQ(header->GetVersion(), 10);
   ASSERT_EQ(header->GetTargetCrc(), 0x1234U);
   ASSERT_EQ(header->GetOverlayCrc(), 0x5678U);
   ASSERT_EQ(header->GetFulfilledPolicies(), 0x11);
@@ -143,7 +143,7 @@
 
   ASSERT_THAT(idmap->GetHeader(), NotNull());
   ASSERT_EQ(idmap->GetHeader()->GetMagic(), 0x504d4449U);
-  ASSERT_EQ(idmap->GetHeader()->GetVersion(), 0x09U);
+  ASSERT_EQ(idmap->GetHeader()->GetVersion(), 10);
   ASSERT_EQ(idmap->GetHeader()->GetTargetCrc(), 0x1234U);
   ASSERT_EQ(idmap->GetHeader()->GetOverlayCrc(), 0x5678U);
   ASSERT_EQ(idmap->GetHeader()->GetFulfilledPolicies(), kIdmapRawDataPolicies);
@@ -204,7 +204,7 @@
 
   ASSERT_THAT(idmap->GetHeader(), NotNull());
   ASSERT_EQ(idmap->GetHeader()->GetMagic(), 0x504d4449U);
-  ASSERT_EQ(idmap->GetHeader()->GetVersion(), 0x09U);
+  ASSERT_EQ(idmap->GetHeader()->GetVersion(), 10);
   ASSERT_EQ(idmap->GetHeader()->GetTargetCrc(), android::idmap2::TestConstants::TARGET_CRC);
   ASSERT_EQ(idmap->GetHeader()->GetOverlayCrc(), android::idmap2::TestConstants::OVERLAY_CRC);
   ASSERT_EQ(idmap->GetHeader()->GetFulfilledPolicies(), PolicyFlags::PUBLIC);
diff --git a/cmds/idmap2/tests/RawPrintVisitorTests.cpp b/cmds/idmap2/tests/RawPrintVisitorTests.cpp
index 68164e2..7fae1c6 100644
--- a/cmds/idmap2/tests/RawPrintVisitorTests.cpp
+++ b/cmds/idmap2/tests/RawPrintVisitorTests.cpp
@@ -64,7 +64,7 @@
   (*idmap)->accept(&visitor);
 
   ASSERT_CONTAINS_REGEX(ADDRESS "504d4449  magic\n", stream.str());
-  ASSERT_CONTAINS_REGEX(ADDRESS "00000009  version\n", stream.str());
+  ASSERT_CONTAINS_REGEX(ADDRESS "0000000a  version\n", stream.str());
   ASSERT_CONTAINS_REGEX(
       StringPrintf(ADDRESS "%s  target crc\n", android::idmap2::TestConstants::TARGET_CRC_STRING),
       stream.str());
@@ -113,7 +113,7 @@
   (*idmap)->accept(&visitor);
 
   ASSERT_CONTAINS_REGEX(ADDRESS "504d4449  magic\n", stream.str());
-  ASSERT_CONTAINS_REGEX(ADDRESS "00000009  version\n", stream.str());
+  ASSERT_CONTAINS_REGEX(ADDRESS "0000000a  version\n", stream.str());
   ASSERT_CONTAINS_REGEX(ADDRESS "00001234  target crc\n", stream.str());
   ASSERT_CONTAINS_REGEX(ADDRESS "00005678  overlay crc\n", stream.str());
   ASSERT_CONTAINS_REGEX(ADDRESS "00000011  fulfilled policies: public|signature\n", stream.str());
diff --git a/cmds/idmap2/tests/TestHelpers.h b/cmds/idmap2/tests/TestHelpers.h
index bf01c32..2b4ebd1 100644
--- a/cmds/idmap2/tests/TestHelpers.h
+++ b/cmds/idmap2/tests/TestHelpers.h
@@ -34,7 +34,7 @@
     0x49, 0x44, 0x4d, 0x50,
 
     // 0x4: version
-    0x09, 0x00, 0x00, 0x00,
+    0x0a, 0x00, 0x00, 0x00,
 
     // 0x8: target crc
     0x34, 0x12, 0x00, 0x00,
@@ -95,19 +95,15 @@
     // TARGET ENTRIES
     // 0x6c: target id (0x7f020000)
     0x00, 0x00, 0x02, 0x7f,
-
-    // 0x70: overlay_id (0x7f020000)
-    0x00, 0x00, 0x02, 0x7f,
-
-    // 0x74: target id (0x7f030000)
+    // 0x70: target id (0x7f030000)
     0x00, 0x00, 0x03, 0x7f,
-
-    // 0x78: overlay_id (0x7f030000)
-    0x00, 0x00, 0x03, 0x7f,
-
-    // 0x7c: target id (0x7f030002)
+    // 0x74: target id (0x7f030002)
     0x02, 0x00, 0x03, 0x7f,
 
+    // 0x78: overlay_id (0x7f020000)
+    0x00, 0x00, 0x02, 0x7f,
+    // 0x7c: overlay_id (0x7f030000)
+    0x00, 0x00, 0x03, 0x7f,
     // 0x80: overlay_id (0x7f030001)
     0x01, 0x00, 0x03, 0x7f,
 
@@ -178,16 +174,20 @@
     // 0xe1: padding
     0x00, 0x00, 0x00,
 
-
     // OVERLAY ENTRIES
-    // 0xe4: 0x7f020000 -> 0x7f020000
-    0x00, 0x00, 0x02, 0x7f, 0x00, 0x00, 0x02, 0x7f,
+    // 0xe4: 0x7f020000 -> ...
+    0x00, 0x00, 0x02, 0x7f,
+    // 0xe8: 0x7f030000 -> ...
+    0x00, 0x00, 0x03, 0x7f,
+    // 0xec: 0x7f030001 -> ...
+    0x01, 0x00, 0x03, 0x7f,
 
-    // 0xec: 0x7f030000 -> 0x7f030000
-    0x00, 0x00, 0x03, 0x7f, 0x00, 0x00, 0x03, 0x7f,
-
-    // 0xf4: 0x7f030001 -> 0x7f030002
-    0x01, 0x00, 0x03, 0x7f, 0x02, 0x00, 0x03, 0x7f,
+    // 0xf0: ... -> 0x7f020000
+    0x00, 0x00, 0x02, 0x7f,
+    // 0xf4: ... -> 0x7f030000
+    0x00, 0x00, 0x03, 0x7f,
+    // 0xf8: ... -> 0x7f030002
+    0x02, 0x00, 0x03, 0x7f,
 
     // 0xfc: string pool
     // string length,
diff --git a/cmds/uinput/Android.bp b/cmds/uinput/Android.bp
index da497dc..cec8a0d8 100644
--- a/cmds/uinput/Android.bp
+++ b/cmds/uinput/Android.bp
@@ -25,7 +25,7 @@
         "src/**/*.java",
         ":uinputcommand_aidl",
     ],
-    required: ["libuinputcommand_jni"],
+    jni_libs: ["libuinputcommand_jni"],
 }
 
 filegroup {
diff --git a/core/api/current.txt b/core/api/current.txt
index d1c0c42..ebc534f6 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -4950,7 +4950,7 @@
     field @Deprecated @FlaggedApi("com.android.window.flags.bal_additional_start_modes") public static final int MODE_BACKGROUND_ACTIVITY_START_ALLOWED = 1; // 0x1
     field @FlaggedApi("com.android.window.flags.bal_additional_start_modes") public static final int MODE_BACKGROUND_ACTIVITY_START_ALLOW_ALWAYS = 3; // 0x3
     field @FlaggedApi("com.android.window.flags.bal_additional_start_modes") public static final int MODE_BACKGROUND_ACTIVITY_START_ALLOW_IF_VISIBLE = 4; // 0x4
-    field @FlaggedApi("com.android.window.flags.bal_additional_start_modes") public static final int MODE_BACKGROUND_ACTIVITY_START_DENIED = 2; // 0x2
+    field public static final int MODE_BACKGROUND_ACTIVITY_START_DENIED = 2; // 0x2
     field public static final int MODE_BACKGROUND_ACTIVITY_START_SYSTEM_DEFINED = 0; // 0x0
   }
 
@@ -5103,6 +5103,7 @@
     method public int noteProxyOpNoThrow(@NonNull String, @Nullable String, int, @Nullable String, @Nullable String);
     method @Nullable public static String permissionToOp(@NonNull String);
     method public void setOnOpNotedCallback(@Nullable java.util.concurrent.Executor, @Nullable android.app.AppOpsManager.OnOpNotedCallback);
+    method @FlaggedApi("android.permission.flags.sync_on_op_noted_api") public void setOnOpNotedCallback(@Nullable java.util.concurrent.Executor, @Nullable android.app.AppOpsManager.OnOpNotedCallback, int);
     method @Deprecated public int startOp(@NonNull String, int, @NonNull String);
     method public int startOp(@NonNull String, int, @Nullable String, @Nullable String, @Nullable String);
     method @Deprecated public int startOpNoThrow(@NonNull String, int, @NonNull String);
@@ -5157,6 +5158,7 @@
     field public static final String OPSTR_WRITE_CONTACTS = "android:write_contacts";
     field public static final String OPSTR_WRITE_EXTERNAL_STORAGE = "android:write_external_storage";
     field public static final String OPSTR_WRITE_SETTINGS = "android:write_settings";
+    field @FlaggedApi("android.permission.flags.sync_on_op_noted_api") public static final int OP_NOTED_CALLBACK_FLAG_IGNORE_ASYNC = 1; // 0x1
     field public static final int WATCH_FOREGROUND_CHANGES = 1; // 0x1
   }
 
@@ -8792,7 +8794,8 @@
     ctor public AppFunctionService();
     method @NonNull public final android.os.IBinder onBind(@Nullable android.content.Intent);
     method @Deprecated @MainThread public void onExecuteFunction(@NonNull android.app.appfunctions.ExecuteAppFunctionRequest, @NonNull java.util.function.Consumer<android.app.appfunctions.ExecuteAppFunctionResponse>);
-    method @MainThread public void onExecuteFunction(@NonNull android.app.appfunctions.ExecuteAppFunctionRequest, @NonNull android.os.CancellationSignal, @NonNull java.util.function.Consumer<android.app.appfunctions.ExecuteAppFunctionResponse>);
+    method @Deprecated @MainThread public void onExecuteFunction(@NonNull android.app.appfunctions.ExecuteAppFunctionRequest, @NonNull android.os.CancellationSignal, @NonNull java.util.function.Consumer<android.app.appfunctions.ExecuteAppFunctionResponse>);
+    method @MainThread public void onExecuteFunction(@NonNull android.app.appfunctions.ExecuteAppFunctionRequest, @NonNull String, @NonNull android.os.CancellationSignal, @NonNull java.util.function.Consumer<android.app.appfunctions.ExecuteAppFunctionResponse>);
     field @NonNull public static final String SERVICE_INTERFACE = "android.app.appfunctions.AppFunctionService";
   }
 
@@ -9834,6 +9837,7 @@
   public final class AssociationInfo implements android.os.Parcelable {
     method public int describeContents();
     method @Nullable public android.companion.AssociatedDevice getAssociatedDevice();
+    method @FlaggedApi("android.companion.association_device_icon") @Nullable public android.graphics.drawable.Icon getDeviceIcon();
     method @Nullable public android.net.MacAddress getDeviceMacAddress();
     method @Nullable public String getDeviceProfile();
     method @Nullable public CharSequence getDisplayName();
@@ -9847,6 +9851,7 @@
 
   public final class AssociationRequest implements android.os.Parcelable {
     method public int describeContents();
+    method @FlaggedApi("android.companion.association_device_icon") @Nullable public android.graphics.drawable.Icon getDeviceIcon();
     method @Nullable public String getDeviceProfile();
     method @Nullable public CharSequence getDisplayName();
     method public boolean isForceConfirmation();
@@ -9866,6 +9871,7 @@
     ctor public AssociationRequest.Builder();
     method @NonNull public android.companion.AssociationRequest.Builder addDeviceFilter(@Nullable android.companion.DeviceFilter<?>);
     method @NonNull public android.companion.AssociationRequest build();
+    method @FlaggedApi("android.companion.association_device_icon") @NonNull @RequiresPermission(android.Manifest.permission.REQUEST_COMPANION_SELF_MANAGED) public android.companion.AssociationRequest.Builder setDeviceIcon(@NonNull android.graphics.drawable.Icon);
     method @NonNull public android.companion.AssociationRequest.Builder setDeviceProfile(@NonNull String);
     method @NonNull public android.companion.AssociationRequest.Builder setDisplayName(@NonNull CharSequence);
     method @NonNull @RequiresPermission(android.Manifest.permission.REQUEST_COMPANION_SELF_MANAGED) public android.companion.AssociationRequest.Builder setForceConfirmation(boolean);
@@ -12286,6 +12292,7 @@
     method public int getMemtagMode();
     method public int getNativeHeapZeroInitialized();
     method public int getRequestRawExternalStorageAccess();
+    method @FlaggedApi("android.content.pm.audio_playback_capture_allowance") public boolean isAudioPlaybackCaptureAllowed();
     method public boolean isProfileable();
     method public boolean isProfileableByShell();
     method public boolean isResourceOverlay();
@@ -21415,6 +21422,7 @@
     field public static final int ENCODING_AAC_XHE = 16; // 0x10
     field public static final int ENCODING_AC3 = 5; // 0x5
     field public static final int ENCODING_AC4 = 17; // 0x11
+    field @FlaggedApi("android.media.audio.dolby_ac4_level4_encoding_api") public static final int ENCODING_AC4_L4 = 32; // 0x20
     field public static final int ENCODING_DEFAULT = 1; // 0x1
     field public static final int ENCODING_DOLBY_MAT = 19; // 0x13
     field public static final int ENCODING_DOLBY_TRUEHD = 14; // 0xe
@@ -22600,6 +22608,7 @@
     method public void sendEvent(int, int, @Nullable byte[]) throws android.media.MediaCasException;
     method public void setEventListener(@Nullable android.media.MediaCas.EventListener, @Nullable android.os.Handler);
     method public void setPrivateData(@NonNull byte[]) throws android.media.MediaCasException;
+    method @FlaggedApi("com.android.media.flags.update_client_profile_priority") public boolean updateResourcePriority(int, int);
     field public static final int PLUGIN_STATUS_PHYSICAL_MODULE_CHANGED = 0; // 0x0
     field public static final int PLUGIN_STATUS_SESSION_NUMBER_CHANGED = 1; // 0x1
     field public static final int SCRAMBLING_MODE_AES128 = 9; // 0x9
@@ -26918,7 +26927,6 @@
     field public static final int STATE_FAST_FORWARDING = 4; // 0x4
     field public static final int STATE_NONE = 0; // 0x0
     field public static final int STATE_PAUSED = 2; // 0x2
-    field @FlaggedApi("com.android.media.flags.enable_notifying_activity_manager_with_media_session_status_change") public static final int STATE_PLAYBACK_SUPPRESSED = 12; // 0xc
     field public static final int STATE_PLAYING = 3; // 0x3
     field public static final int STATE_REWINDING = 5; // 0x5
     field public static final int STATE_SKIPPING_TO_NEXT = 10; // 0xa
@@ -33923,9 +33931,12 @@
   public class RemoteCallbackList<E extends android.os.IInterface> {
     ctor public RemoteCallbackList();
     method public int beginBroadcast();
+    method @FlaggedApi("android.os.binder_frozen_state_change_callback") public void broadcast(@NonNull java.util.function.Consumer<E>);
     method public void finishBroadcast();
     method public Object getBroadcastCookie(int);
     method public E getBroadcastItem(int);
+    method @FlaggedApi("android.os.binder_frozen_state_change_callback") public int getFrozenCalleePolicy();
+    method @FlaggedApi("android.os.binder_frozen_state_change_callback") public int getMaxQueueSize();
     method public Object getRegisteredCallbackCookie(int);
     method public int getRegisteredCallbackCount();
     method public E getRegisteredCallbackItem(int);
@@ -33935,6 +33946,16 @@
     method public boolean register(E);
     method public boolean register(E, Object);
     method public boolean unregister(E);
+    field @FlaggedApi("android.os.binder_frozen_state_change_callback") public static final int FROZEN_CALLEE_POLICY_DROP = 3; // 0x3
+    field @FlaggedApi("android.os.binder_frozen_state_change_callback") public static final int FROZEN_CALLEE_POLICY_ENQUEUE_ALL = 1; // 0x1
+    field @FlaggedApi("android.os.binder_frozen_state_change_callback") public static final int FROZEN_CALLEE_POLICY_ENQUEUE_MOST_RECENT = 2; // 0x2
+    field @FlaggedApi("android.os.binder_frozen_state_change_callback") public static final int FROZEN_CALLEE_POLICY_UNSET = 0; // 0x0
+  }
+
+  @FlaggedApi("android.os.binder_frozen_state_change_callback") public static final class RemoteCallbackList.Builder<E extends android.os.IInterface> {
+    ctor public RemoteCallbackList.Builder(int);
+    method @NonNull public android.os.RemoteCallbackList<E> build();
+    method @NonNull public android.os.RemoteCallbackList.Builder setMaxQueueSize(int);
   }
 
   public class RemoteException extends android.util.AndroidException {
@@ -34334,6 +34355,7 @@
     method @FlaggedApi("android.os.vibrator.normalized_pwle_effects") public boolean areEnvelopeEffectsSupported();
     method @NonNull public boolean[] arePrimitivesSupported(@NonNull int...);
     method @RequiresPermission(android.Manifest.permission.VIBRATE) public abstract void cancel();
+    method @FlaggedApi("android.os.vibrator.normalized_pwle_effects") @Nullable public android.os.vibrator.VibratorFrequencyProfile getFrequencyProfile();
     method public int getId();
     method @FlaggedApi("android.os.vibrator.normalized_pwle_effects") public int getMaxEnvelopeEffectControlPointDurationMillis();
     method @FlaggedApi("android.os.vibrator.normalized_pwle_effects") public int getMaxEnvelopeEffectDurationMillis();
@@ -34687,6 +34709,19 @@
 
 }
 
+package android.os.vibrator {
+
+  @FlaggedApi("android.os.vibrator.normalized_pwle_effects") public final class VibratorFrequencyProfile {
+    method @FlaggedApi("android.os.vibrator.normalized_pwle_effects") @NonNull public android.util.SparseArray<java.lang.Float> getFrequenciesOutputAcceleration();
+    method @FlaggedApi("android.os.vibrator.normalized_pwle_effects") @Nullable public android.util.Range<java.lang.Float> getFrequencyRange(float);
+    method @FlaggedApi("android.os.vibrator.normalized_pwle_effects") public float getMaxFrequencyHz();
+    method @FlaggedApi("android.os.vibrator.normalized_pwle_effects") public float getMaxOutputAccelerationGs();
+    method @FlaggedApi("android.os.vibrator.normalized_pwle_effects") public float getMinFrequencyHz();
+    method @FlaggedApi("android.os.vibrator.normalized_pwle_effects") public float getOutputAccelerationGs(float);
+  }
+
+}
+
 package android.preference {
 
   @Deprecated public class CheckBoxPreference extends android.preference.TwoStatePreference {
@@ -49240,6 +49275,7 @@
     field public static final String ARG_PROTOCOL = "android.arg.protocol";
     field public static final String ARG_QUANTITY = "android.arg.quantity";
     field public static final String ARG_QUERY_STRING = "android.arg.query_string";
+    field @FlaggedApi("com.android.text.flags.tts_span_duration") public static final String ARG_SECONDS = "android.arg.seconds";
     field public static final String ARG_TEXT = "android.arg.text";
     field public static final String ARG_UNIT = "android.arg.unit";
     field public static final String ARG_USERNAME = "android.arg.username";
@@ -49276,6 +49312,7 @@
     field public static final String TYPE_DATE = "android.type.date";
     field public static final String TYPE_DECIMAL = "android.type.decimal";
     field public static final String TYPE_DIGITS = "android.type.digits";
+    field @FlaggedApi("com.android.text.flags.tts_span_duration") public static final String TYPE_DURATION = "android.type.duration";
     field public static final String TYPE_ELECTRONIC = "android.type.electronic";
     field public static final String TYPE_FRACTION = "android.type.fraction";
     field public static final String TYPE_MEASURE = "android.type.measure";
@@ -49335,6 +49372,13 @@
     method public android.text.style.TtsSpan.DigitsBuilder setDigits(String);
   }
 
+  @FlaggedApi("com.android.text.flags.tts_span_duration") public static class TtsSpan.DurationBuilder extends android.text.style.TtsSpan.SemioticClassBuilder<android.text.style.TtsSpan.DurationBuilder> {
+    ctor @FlaggedApi("com.android.text.flags.tts_span_duration") public TtsSpan.DurationBuilder();
+    method @FlaggedApi("com.android.text.flags.tts_span_duration") @NonNull public android.text.style.TtsSpan.DurationBuilder setHours(int);
+    method @FlaggedApi("com.android.text.flags.tts_span_duration") @NonNull public android.text.style.TtsSpan.DurationBuilder setMinutes(int);
+    method @FlaggedApi("com.android.text.flags.tts_span_duration") @NonNull public android.text.style.TtsSpan.DurationBuilder setSeconds(int);
+  }
+
   public static class TtsSpan.ElectronicBuilder extends android.text.style.TtsSpan.SemioticClassBuilder<android.text.style.TtsSpan.ElectronicBuilder> {
     ctor public TtsSpan.ElectronicBuilder();
     method public android.text.style.TtsSpan.ElectronicBuilder setDomain(String);
@@ -49417,6 +49461,7 @@
     ctor public TtsSpan.TimeBuilder(int, int);
     method public android.text.style.TtsSpan.TimeBuilder setHours(int);
     method public android.text.style.TtsSpan.TimeBuilder setMinutes(int);
+    method @FlaggedApi("com.android.text.flags.tts_span_duration") @NonNull public android.text.style.TtsSpan.TimeBuilder setSeconds(int);
   }
 
   public static class TtsSpan.VerbatimBuilder extends android.text.style.TtsSpan.SemioticClassBuilder<android.text.style.TtsSpan.VerbatimBuilder> {
@@ -52549,10 +52594,12 @@
     ctor public SurfaceView(android.content.Context, android.util.AttributeSet, int);
     ctor public SurfaceView(android.content.Context, android.util.AttributeSet, int, int);
     method public void applyTransactionToFrame(@NonNull android.view.SurfaceControl.Transaction);
+    method @FlaggedApi("android.view.flags.surface_view_set_composition_order") public int getCompositionOrder();
     method public android.view.SurfaceHolder getHolder();
     method @Deprecated @Nullable public android.os.IBinder getHostToken();
     method public android.view.SurfaceControl getSurfaceControl();
     method public void setChildSurfacePackage(@NonNull android.view.SurfaceControlViewHost.SurfacePackage);
+    method @FlaggedApi("android.view.flags.surface_view_set_composition_order") public void setCompositionOrder(int);
     method @FlaggedApi("com.android.graphics.hwui.flags.limited_hdr") public void setDesiredHdrHeadroom(@FloatRange(from=0.0f, to=10000.0) float);
     method public void setSecure(boolean);
     method public void setSurfaceLifecycle(int);
@@ -54890,6 +54937,7 @@
     method public void setPackageName(CharSequence);
     method public void setSpeechStateChangeTypes(int);
     method public void writeToParcel(android.os.Parcel, int);
+    field @FlaggedApi("android.view.accessibility.tri_state_checked") public static final int CONTENT_CHANGE_TYPE_CHECKED = 8192; // 0x2000
     field public static final int CONTENT_CHANGE_TYPE_CONTENT_DESCRIPTION = 4; // 0x4
     field public static final int CONTENT_CHANGE_TYPE_CONTENT_INVALID = 1024; // 0x400
     field public static final int CONTENT_CHANGE_TYPE_DRAG_CANCELLED = 512; // 0x200
@@ -55035,6 +55083,7 @@
     method @Deprecated public void getBoundsInParent(android.graphics.Rect);
     method public void getBoundsInScreen(android.graphics.Rect);
     method public void getBoundsInWindow(@NonNull android.graphics.Rect);
+    method @FlaggedApi("android.view.accessibility.tri_state_checked") public int getChecked();
     method public android.view.accessibility.AccessibilityNodeInfo getChild(int);
     method @Nullable public android.view.accessibility.AccessibilityNodeInfo getChild(int, int);
     method public int getChildCount();
@@ -55077,7 +55126,7 @@
     method public boolean isAccessibilityDataSensitive();
     method public boolean isAccessibilityFocused();
     method public boolean isCheckable();
-    method public boolean isChecked();
+    method @Deprecated @FlaggedApi("android.view.accessibility.tri_state_checked") public boolean isChecked();
     method public boolean isClickable();
     method public boolean isContentInvalid();
     method public boolean isContextClickable();
@@ -55122,7 +55171,8 @@
     method public void setBoundsInWindow(@NonNull android.graphics.Rect);
     method public void setCanOpenPopup(boolean);
     method public void setCheckable(boolean);
-    method public void setChecked(boolean);
+    method @Deprecated @FlaggedApi("android.view.accessibility.tri_state_checked") public void setChecked(boolean);
+    method @FlaggedApi("android.view.accessibility.tri_state_checked") public void setChecked(int);
     method public void setClassName(CharSequence);
     method public void setClickable(boolean);
     method public void setCollectionInfo(android.view.accessibility.AccessibilityNodeInfo.CollectionInfo);
@@ -55218,6 +55268,9 @@
     field public static final int ACTION_SELECT = 4; // 0x4
     field public static final int ACTION_SET_SELECTION = 131072; // 0x20000
     field public static final int ACTION_SET_TEXT = 2097152; // 0x200000
+    field @FlaggedApi("android.view.accessibility.tri_state_checked") public static final int CHECKED_STATE_FALSE = 0; // 0x0
+    field @FlaggedApi("android.view.accessibility.tri_state_checked") public static final int CHECKED_STATE_PARTIAL = 2; // 0x2
+    field @FlaggedApi("android.view.accessibility.tri_state_checked") public static final int CHECKED_STATE_TRUE = 1; // 0x1
     field @NonNull public static final android.os.Parcelable.Creator<android.view.accessibility.AccessibilityNodeInfo> CREATOR;
     field public static final String EXTRA_DATA_RENDERING_INFO_KEY = "android.view.accessibility.extra.DATA_RENDERING_INFO_KEY";
     field public static final String EXTRA_DATA_TEXT_CHARACTER_LOCATION_ARG_LENGTH = "android.view.accessibility.extra.DATA_TEXT_CHARACTER_LOCATION_ARG_LENGTH";
diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt
index 287e787..4d1a423 100644
--- a/core/api/module-lib-current.txt
+++ b/core/api/module-lib-current.txt
@@ -321,7 +321,7 @@
 package android.net.wifi {
 
   public final class WifiMigration {
-    method @FlaggedApi("android.net.wifi.flags.legacy_keystore_to_wifi_blobstore_migration_read_only") public static int migrateLegacyKeystoreToWifiBlobstore();
+    method @FlaggedApi("android.net.wifi.flags.legacy_keystore_to_wifi_blobstore_migration_read_only") public static void migrateLegacyKeystoreToWifiBlobstore(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.IntConsumer);
     field @FlaggedApi("android.net.wifi.flags.legacy_keystore_to_wifi_blobstore_migration_read_only") public static final int KEYSTORE_MIGRATION_FAILURE_ENCOUNTERED_EXCEPTION = 2; // 0x2
     field @FlaggedApi("android.net.wifi.flags.legacy_keystore_to_wifi_blobstore_migration_read_only") public static final int KEYSTORE_MIGRATION_SUCCESS_MIGRATION_COMPLETE = 0; // 0x0
     field @FlaggedApi("android.net.wifi.flags.legacy_keystore_to_wifi_blobstore_migration_read_only") public static final int KEYSTORE_MIGRATION_SUCCESS_MIGRATION_NOT_NEEDED = 1; // 0x1
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 7e43e46..49b711b 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -694,6 +694,7 @@
     field public static final String OPSTR_PROJECT_MEDIA = "android:project_media";
     field @FlaggedApi("android.view.contentprotection.flags.rapid_clear_notifications_by_listener_app_op_enabled") public static final String OPSTR_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER = "android:rapid_clear_notifications_by_listener";
     field public static final String OPSTR_READ_CLIPBOARD = "android:read_clipboard";
+    field @FlaggedApi("android.permission.flags.replace_body_sensor_permission_enabled") public static final String OPSTR_READ_HEART_RATE = "android:read_heart_rate";
     field public static final String OPSTR_READ_ICC_SMS = "android:read_icc_sms";
     field public static final String OPSTR_READ_MEDIA_AUDIO = "android:read_media_audio";
     field public static final String OPSTR_READ_MEDIA_IMAGES = "android:read_media_images";
@@ -3488,39 +3489,41 @@
 
   public static class VirtualDeviceManager.VirtualDevice implements java.lang.AutoCloseable {
     method public void addActivityListener(@NonNull java.util.concurrent.Executor, @NonNull android.companion.virtual.VirtualDeviceManager.ActivityListener);
-    method @FlaggedApi("android.companion.virtual.flags.dynamic_policy") @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public void addActivityPolicyExemption(@NonNull android.content.ComponentName);
-    method @FlaggedApi("android.companion.virtualdevice.flags.activity_control_api") @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public void addActivityPolicyExemption(@NonNull android.companion.virtual.ActivityPolicyExemption);
+    method @FlaggedApi("android.companion.virtual.flags.dynamic_policy") public void addActivityPolicyExemption(@NonNull android.content.ComponentName);
+    method @FlaggedApi("android.companion.virtualdevice.flags.activity_control_api") public void addActivityPolicyExemption(@NonNull android.companion.virtual.ActivityPolicyExemption);
     method public void addSoundEffectListener(@NonNull java.util.concurrent.Executor, @NonNull android.companion.virtual.VirtualDeviceManager.SoundEffectListener);
-    method @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public void close();
+    method public void close();
     method @NonNull public android.content.Context createContext();
-    method @NonNull @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public android.companion.virtual.audio.VirtualAudioDevice createVirtualAudioDevice(@NonNull android.hardware.display.VirtualDisplay, @Nullable java.util.concurrent.Executor, @Nullable android.companion.virtual.audio.VirtualAudioDevice.AudioConfigurationChangeCallback);
-    method @FlaggedApi("android.companion.virtual.flags.virtual_camera") @NonNull @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public android.companion.virtual.camera.VirtualCamera createVirtualCamera(@NonNull android.companion.virtual.camera.VirtualCameraConfig);
+    method @NonNull public android.companion.virtual.audio.VirtualAudioDevice createVirtualAudioDevice(@NonNull android.hardware.display.VirtualDisplay, @Nullable java.util.concurrent.Executor, @Nullable android.companion.virtual.audio.VirtualAudioDevice.AudioConfigurationChangeCallback);
+    method @FlaggedApi("android.companion.virtual.flags.virtual_camera") @NonNull public android.companion.virtual.camera.VirtualCamera createVirtualCamera(@NonNull android.companion.virtual.camera.VirtualCameraConfig);
     method @Deprecated @Nullable public android.hardware.display.VirtualDisplay createVirtualDisplay(@IntRange(from=1) int, @IntRange(from=1) int, @IntRange(from=1) int, @Nullable android.view.Surface, int, @Nullable java.util.concurrent.Executor, @Nullable android.hardware.display.VirtualDisplay.Callback);
     method @Nullable public android.hardware.display.VirtualDisplay createVirtualDisplay(@NonNull android.hardware.display.VirtualDisplayConfig, @Nullable java.util.concurrent.Executor, @Nullable android.hardware.display.VirtualDisplay.Callback);
-    method @NonNull @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public android.hardware.input.VirtualDpad createVirtualDpad(@NonNull android.hardware.input.VirtualDpadConfig);
-    method @NonNull @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public android.hardware.input.VirtualKeyboard createVirtualKeyboard(@NonNull android.hardware.input.VirtualKeyboardConfig);
-    method @Deprecated @NonNull @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public android.hardware.input.VirtualKeyboard createVirtualKeyboard(@NonNull android.hardware.display.VirtualDisplay, @NonNull String, int, int);
-    method @NonNull @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public android.hardware.input.VirtualMouse createVirtualMouse(@NonNull android.hardware.input.VirtualMouseConfig);
-    method @Deprecated @NonNull @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public android.hardware.input.VirtualMouse createVirtualMouse(@NonNull android.hardware.display.VirtualDisplay, @NonNull String, int, int);
-    method @NonNull @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public android.hardware.input.VirtualNavigationTouchpad createVirtualNavigationTouchpad(@NonNull android.hardware.input.VirtualNavigationTouchpadConfig);
-    method @FlaggedApi("android.companion.virtualdevice.flags.virtual_rotary") @NonNull @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public android.hardware.input.VirtualRotaryEncoder createVirtualRotaryEncoder(@NonNull android.hardware.input.VirtualRotaryEncoderConfig);
-    method @FlaggedApi("android.companion.virtual.flags.virtual_stylus") @NonNull @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public android.hardware.input.VirtualStylus createVirtualStylus(@NonNull android.hardware.input.VirtualStylusConfig);
-    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 @NonNull public android.hardware.input.VirtualDpad createVirtualDpad(@NonNull android.hardware.input.VirtualDpadConfig);
+    method @NonNull public android.hardware.input.VirtualKeyboard createVirtualKeyboard(@NonNull android.hardware.input.VirtualKeyboardConfig);
+    method @Deprecated @NonNull public android.hardware.input.VirtualKeyboard createVirtualKeyboard(@NonNull android.hardware.display.VirtualDisplay, @NonNull String, int, int);
+    method @NonNull public android.hardware.input.VirtualMouse createVirtualMouse(@NonNull android.hardware.input.VirtualMouseConfig);
+    method @Deprecated @NonNull public android.hardware.input.VirtualMouse createVirtualMouse(@NonNull android.hardware.display.VirtualDisplay, @NonNull String, int, int);
+    method @NonNull public android.hardware.input.VirtualNavigationTouchpad createVirtualNavigationTouchpad(@NonNull android.hardware.input.VirtualNavigationTouchpadConfig);
+    method @FlaggedApi("android.companion.virtualdevice.flags.virtual_rotary") @NonNull public android.hardware.input.VirtualRotaryEncoder createVirtualRotaryEncoder(@NonNull android.hardware.input.VirtualRotaryEncoderConfig);
+    method @FlaggedApi("android.companion.virtual.flags.virtual_stylus") @NonNull public android.hardware.input.VirtualStylus createVirtualStylus(@NonNull android.hardware.input.VirtualStylusConfig);
+    method @NonNull public android.hardware.input.VirtualTouchscreen createVirtualTouchscreen(@NonNull android.hardware.input.VirtualTouchscreenConfig);
+    method @Deprecated @NonNull public android.hardware.input.VirtualTouchscreen createVirtualTouchscreen(@NonNull android.hardware.display.VirtualDisplay, @NonNull String, int, int);
     method public int getDeviceId();
     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 @FlaggedApi("android.companion.virtualdevice.flags.device_aware_display_power") public void goToSleep();
     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);
+    method public void registerIntentInterceptor(@NonNull android.content.IntentFilter, @NonNull java.util.concurrent.Executor, @NonNull android.companion.virtual.VirtualDeviceManager.IntentInterceptorCallback);
     method public void removeActivityListener(@NonNull android.companion.virtual.VirtualDeviceManager.ActivityListener);
-    method @FlaggedApi("android.companion.virtual.flags.dynamic_policy") @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public void removeActivityPolicyExemption(@NonNull android.content.ComponentName);
-    method @FlaggedApi("android.companion.virtualdevice.flags.activity_control_api") @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public void removeActivityPolicyExemption(@NonNull android.companion.virtual.ActivityPolicyExemption);
+    method @FlaggedApi("android.companion.virtual.flags.dynamic_policy") public void removeActivityPolicyExemption(@NonNull android.content.ComponentName);
+    method @FlaggedApi("android.companion.virtualdevice.flags.activity_control_api") public void removeActivityPolicyExemption(@NonNull android.companion.virtual.ActivityPolicyExemption);
     method public void removeSoundEffectListener(@NonNull android.companion.virtual.VirtualDeviceManager.SoundEffectListener);
-    method @FlaggedApi("android.companion.virtual.flags.dynamic_policy") @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public void setDevicePolicy(int, int);
-    method @FlaggedApi("android.companion.virtualdevice.flags.activity_control_api") @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public void setDevicePolicy(int, int, int);
-    method @FlaggedApi("android.companion.virtual.flags.vdm_custom_ime") @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public void setDisplayImePolicy(int, int);
-    method @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public void setShowPointerIcon(boolean);
-    method @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public void unregisterIntentInterceptor(@NonNull android.companion.virtual.VirtualDeviceManager.IntentInterceptorCallback);
+    method @FlaggedApi("android.companion.virtual.flags.dynamic_policy") public void setDevicePolicy(int, int);
+    method @FlaggedApi("android.companion.virtualdevice.flags.activity_control_api") public void setDevicePolicy(int, int, int);
+    method @FlaggedApi("android.companion.virtual.flags.vdm_custom_ime") public void setDisplayImePolicy(int, int);
+    method public void setShowPointerIcon(boolean);
+    method public void unregisterIntentInterceptor(@NonNull android.companion.virtual.VirtualDeviceManager.IntentInterceptorCallback);
+    method @FlaggedApi("android.companion.virtualdevice.flags.device_aware_display_power") public void wakeUp();
   }
 
   public final class VirtualDeviceParams implements android.os.Parcelable {
@@ -3629,7 +3632,7 @@
 package android.companion.virtual.camera {
 
   @FlaggedApi("android.companion.virtual.flags.virtual_camera") public final class VirtualCamera implements java.io.Closeable {
-    method @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public void close();
+    method public void close();
     method @NonNull public android.companion.virtual.camera.VirtualCameraConfig getConfig();
   }
 
@@ -3681,7 +3684,7 @@
     method public int getDeviceId();
     method @NonNull public String getName();
     method public int getType();
-    method @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public void sendEvent(@NonNull android.companion.virtual.sensor.VirtualSensorEvent);
+    method public void sendEvent(@NonNull android.companion.virtual.sensor.VirtualSensorEvent);
     method public void writeToParcel(@NonNull android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.companion.virtual.sensor.VirtualSensor> CREATOR;
   }
@@ -5692,8 +5695,8 @@
 package android.hardware.input {
 
   public class VirtualDpad implements java.io.Closeable {
-    method @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public void close();
-    method @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public void sendKeyEvent(@NonNull android.hardware.input.VirtualKeyEvent);
+    method public void close();
+    method public void sendKeyEvent(@NonNull android.hardware.input.VirtualKeyEvent);
   }
 
   public final class VirtualDpadConfig extends android.hardware.input.VirtualInputDeviceConfig implements android.os.Parcelable {
@@ -5744,8 +5747,8 @@
   }
 
   public class VirtualKeyboard implements java.io.Closeable {
-    method @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public void close();
-    method @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public void sendKeyEvent(@NonNull android.hardware.input.VirtualKeyEvent);
+    method public void close();
+    method public void sendKeyEvent(@NonNull android.hardware.input.VirtualKeyEvent);
   }
 
   public final class VirtualKeyboardConfig extends android.hardware.input.VirtualInputDeviceConfig implements android.os.Parcelable {
@@ -5766,11 +5769,11 @@
   }
 
   public class VirtualMouse implements java.io.Closeable {
-    method @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public void close();
-    method @NonNull @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public android.graphics.PointF getCursorPosition();
-    method @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public void sendButtonEvent(@NonNull android.hardware.input.VirtualMouseButtonEvent);
-    method @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public void sendRelativeEvent(@NonNull android.hardware.input.VirtualMouseRelativeEvent);
-    method @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public void sendScrollEvent(@NonNull android.hardware.input.VirtualMouseScrollEvent);
+    method public void close();
+    method @NonNull public android.graphics.PointF getCursorPosition();
+    method public void sendButtonEvent(@NonNull android.hardware.input.VirtualMouseButtonEvent);
+    method public void sendRelativeEvent(@NonNull android.hardware.input.VirtualMouseRelativeEvent);
+    method public void sendScrollEvent(@NonNull android.hardware.input.VirtualMouseScrollEvent);
   }
 
   public final class VirtualMouseButtonEvent implements android.os.Parcelable {
@@ -5843,8 +5846,8 @@
   }
 
   public class VirtualNavigationTouchpad implements java.io.Closeable {
-    method @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public void close();
-    method @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public void sendTouchEvent(@NonNull android.hardware.input.VirtualTouchEvent);
+    method public void close();
+    method public void sendTouchEvent(@NonNull android.hardware.input.VirtualTouchEvent);
   }
 
   public final class VirtualNavigationTouchpadConfig extends android.hardware.input.VirtualInputDeviceConfig implements android.os.Parcelable {
@@ -5861,8 +5864,8 @@
   }
 
   @FlaggedApi("android.companion.virtualdevice.flags.virtual_rotary") public class VirtualRotaryEncoder implements java.io.Closeable {
-    method @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public void close();
-    method @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public void sendScrollEvent(@NonNull android.hardware.input.VirtualRotaryEncoderScrollEvent);
+    method public void close();
+    method public void sendScrollEvent(@NonNull android.hardware.input.VirtualRotaryEncoderScrollEvent);
   }
 
   @FlaggedApi("android.companion.virtualdevice.flags.virtual_rotary") public final class VirtualRotaryEncoderConfig extends android.hardware.input.VirtualInputDeviceConfig implements android.os.Parcelable {
@@ -5892,9 +5895,9 @@
   }
 
   @FlaggedApi("android.companion.virtual.flags.virtual_stylus") public class VirtualStylus implements java.io.Closeable {
-    method @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public void close();
-    method @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public void sendButtonEvent(@NonNull android.hardware.input.VirtualStylusButtonEvent);
-    method @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public void sendMotionEvent(@NonNull android.hardware.input.VirtualStylusMotionEvent);
+    method public void close();
+    method public void sendButtonEvent(@NonNull android.hardware.input.VirtualStylusButtonEvent);
+    method public void sendMotionEvent(@NonNull android.hardware.input.VirtualStylusMotionEvent);
   }
 
   @FlaggedApi("android.companion.virtual.flags.virtual_stylus") public final class VirtualStylusButtonEvent implements android.os.Parcelable {
@@ -5997,8 +6000,8 @@
   }
 
   public class VirtualTouchscreen implements java.io.Closeable {
-    method @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public void close();
-    method @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public void sendTouchEvent(@NonNull android.hardware.input.VirtualTouchEvent);
+    method public void close();
+    method public void sendTouchEvent(@NonNull android.hardware.input.VirtualTouchEvent);
   }
 
   public final class VirtualTouchscreenConfig extends android.hardware.input.VirtualInputDeviceConfig implements android.os.Parcelable {
@@ -8540,11 +8543,14 @@
     method public long getAudioHandle();
     method @NonNull public java.util.List<android.media.AudioPresentation> getAudioPresentations();
     method public long getAvDataId();
+    method @FlaggedApi("android.media.tv.flags.tuner_w_apis") public int getDataGroupId();
     method public long getDataLength();
     method public long getDts();
     method @Nullable public android.media.tv.tuner.filter.AudioDescriptor getExtraMetaData();
+    method @FlaggedApi("android.media.tv.flags.tuner_w_apis") @IntRange(from=0) public int getIndexInDataGroup();
     method @Nullable public android.media.MediaCodec.LinearBlock getLinearBlock();
     method @IntRange(from=0) public int getMpuSequenceNumber();
+    method @FlaggedApi("android.media.tv.flags.tuner_w_apis") @IntRange(from=0) public int getNumDataPieces();
     method public long getOffset();
     method public long getPts();
     method public int getScIndexMask();
@@ -11951,6 +11957,11 @@
   }
 
   @FlaggedApi("android.provider.new_default_account_api_enabled") public static final class ContactsContract.RawContacts.DefaultAccount {
+    method @FlaggedApi("android.provider.new_default_account_api_enabled") @NonNull @RequiresPermission(android.Manifest.permission.SET_DEFAULT_ACCOUNT_FOR_CONTACTS) public static java.util.List<android.accounts.Account> getEligibleCloudAccounts(@NonNull android.content.ContentResolver);
+    method @FlaggedApi("android.provider.new_default_account_api_enabled") @RequiresPermission(allOf={android.Manifest.permission.READ_CONTACTS, android.Manifest.permission.SET_DEFAULT_ACCOUNT_FOR_CONTACTS}) public static int getNumberOfMovableLocalContacts(@NonNull android.content.ContentResolver);
+    method @FlaggedApi("android.provider.new_default_account_api_enabled") @RequiresPermission(allOf={android.Manifest.permission.READ_CONTACTS, android.Manifest.permission.SET_DEFAULT_ACCOUNT_FOR_CONTACTS}) public static int getNumberOfMovableSimContacts(@NonNull android.content.ContentResolver);
+    method @FlaggedApi("android.provider.new_default_account_api_enabled") @RequiresPermission(allOf={android.Manifest.permission.WRITE_CONTACTS, android.Manifest.permission.SET_DEFAULT_ACCOUNT_FOR_CONTACTS}) public static void moveLocalContactsToCloudDefaultAccount(@NonNull android.content.ContentResolver);
+    method @FlaggedApi("android.provider.new_default_account_api_enabled") @RequiresPermission(allOf={android.Manifest.permission.WRITE_CONTACTS, android.Manifest.permission.SET_DEFAULT_ACCOUNT_FOR_CONTACTS}) public static void moveSimContactsToCloudDefaultAccount(@NonNull android.content.ContentResolver);
     method @FlaggedApi("android.provider.new_default_account_api_enabled") @RequiresPermission(android.Manifest.permission.SET_DEFAULT_ACCOUNT_FOR_CONTACTS) public static void setDefaultAccountForNewContacts(@NonNull android.content.ContentResolver, @NonNull android.provider.ContactsContract.RawContacts.DefaultAccount.DefaultAccountAndState);
   }
 
@@ -15415,6 +15426,7 @@
     field public static final int EVENT_DATA_CONNECTION_STATE_CHANGED = 7; // 0x7
     field @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public static final int EVENT_DATA_ENABLED_CHANGED = 34; // 0x22
     field public static final int EVENT_DISPLAY_INFO_CHANGED = 21; // 0x15
+    field @FlaggedApi("com.android.internal.telephony.flags.emergency_callback_mode_notification") @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public static final int EVENT_EMERGENCY_CALLBACK_MODE_CHANGED = 40; // 0x28
     field @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public static final int EVENT_EMERGENCY_NUMBER_LIST_CHANGED = 25; // 0x19
     field @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public static final int EVENT_IMS_CALL_DISCONNECT_CAUSE_CHANGED = 28; // 0x1c
     field @RequiresPermission(android.Manifest.permission.READ_CALL_LOG) public static final int EVENT_LEGACY_CALL_STATE_CHANGED = 36; // 0x24
@@ -15452,6 +15464,12 @@
     method @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public void onDataEnabledChanged(boolean, int);
   }
 
+  @FlaggedApi("com.android.internal.telephony.flags.emergency_callback_mode_notification") public static interface TelephonyCallback.EmergencyCallbackModeListener {
+    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void onCallbackModeRestarted(int, @NonNull java.time.Duration, int);
+    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void onCallbackModeStarted(int, @NonNull java.time.Duration, int);
+    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void onCallbackModeStopped(int, int, int);
+  }
+
   public static interface TelephonyCallback.LinkCapacityEstimateChangedListener {
     method @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public void onLinkCapacityEstimateChanged(@NonNull java.util.List<android.telephony.LinkCapacityEstimate>);
   }
@@ -15713,6 +15731,8 @@
     field public static final int CELL_BROADCAST_RESULT_SUCCESS = 0; // 0x0
     field public static final int CELL_BROADCAST_RESULT_UNKNOWN = -1; // 0xffffffff
     field public static final int CELL_BROADCAST_RESULT_UNSUPPORTED = 1; // 0x1
+    field @FlaggedApi("com.android.internal.telephony.flags.emergency_callback_mode_notification") public static final int EMERGENCY_CALLBACK_MODE_CALL = 1; // 0x1
+    field @FlaggedApi("com.android.internal.telephony.flags.emergency_callback_mode_notification") public static final int EMERGENCY_CALLBACK_MODE_SMS = 2; // 0x2
     field public static final int ENABLE_NR_DUAL_CONNECTIVITY_INVALID_STATE = 4; // 0x4
     field public static final int ENABLE_NR_DUAL_CONNECTIVITY_NOT_SUPPORTED = 1; // 0x1
     field public static final int ENABLE_NR_DUAL_CONNECTIVITY_RADIO_ERROR = 3; // 0x3
@@ -15770,6 +15790,13 @@
     field public static final int SRVCC_STATE_HANDOVER_FAILED = 2; // 0x2
     field public static final int SRVCC_STATE_HANDOVER_NONE = -1; // 0xffffffff
     field public static final int SRVCC_STATE_HANDOVER_STARTED = 0; // 0x0
+    field @FlaggedApi("com.android.internal.telephony.flags.emergency_callback_mode_notification") public static final int STOP_REASON_EMERGENCY_SMS_SENT = 4; // 0x4
+    field @FlaggedApi("com.android.internal.telephony.flags.emergency_callback_mode_notification") public static final int STOP_REASON_NORMAL_SMS_SENT = 2; // 0x2
+    field @FlaggedApi("com.android.internal.telephony.flags.emergency_callback_mode_notification") public static final int STOP_REASON_OUTGOING_EMERGENCY_CALL_INITIATED = 3; // 0x3
+    field @FlaggedApi("com.android.internal.telephony.flags.emergency_callback_mode_notification") public static final int STOP_REASON_OUTGOING_NORMAL_CALL_INITIATED = 1; // 0x1
+    field @FlaggedApi("com.android.internal.telephony.flags.emergency_callback_mode_notification") public static final int STOP_REASON_TIMER_EXPIRED = 5; // 0x5
+    field @FlaggedApi("com.android.internal.telephony.flags.emergency_callback_mode_notification") public static final int STOP_REASON_UNKNOWN = 0; // 0x0
+    field @FlaggedApi("com.android.internal.telephony.flags.emergency_callback_mode_notification") public static final int STOP_REASON_USER_ACTION = 6; // 0x6
     field public static final int THERMAL_MITIGATION_RESULT_INVALID_STATE = 3; // 0x3
     field public static final int THERMAL_MITIGATION_RESULT_MODEM_ERROR = 1; // 0x1
     field public static final int THERMAL_MITIGATION_RESULT_MODEM_NOT_AVAILABLE = 2; // 0x2
@@ -18548,6 +18575,7 @@
     method @Deprecated public abstract void setUserAgent(int);
     method public abstract void setVideoOverlayForEmbeddedEncryptedVideoEnabled(boolean);
     field public static final long ENABLE_SIMPLIFIED_DARK_MODE = 214741472L; // 0xcccb1e0L
+    field @FlaggedApi("android.webkit.user_agent_reduction") public static final long ENABLE_USER_AGENT_REDUCTION = 371034303L; // 0x161d88bfL
   }
 
   public class WebStorage {
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 9bcdf95..5e4485c 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -914,6 +914,7 @@
     ctor public AssociationInfo.Builder(@NonNull android.companion.AssociationInfo);
     method @NonNull public android.companion.AssociationInfo build();
     method @NonNull public android.companion.AssociationInfo.Builder setAssociatedDevice(@Nullable android.companion.AssociatedDevice);
+    method @FlaggedApi("android.companion.association_device_icon") @NonNull public android.companion.AssociationInfo.Builder setDeviceIcon(@Nullable android.graphics.drawable.Icon);
     method @NonNull public android.companion.AssociationInfo.Builder setDeviceMacAddress(@Nullable android.net.MacAddress);
     method @NonNull public android.companion.AssociationInfo.Builder setDeviceProfile(@Nullable String);
     method @NonNull public android.companion.AssociationInfo.Builder setDisplayName(@Nullable CharSequence);
@@ -2603,7 +2604,7 @@
 
   public abstract class Vibrator {
     method public int getDefaultVibrationIntensity(int);
-    method @Nullable public android.os.vibrator.VibratorFrequencyProfile getFrequencyProfile();
+    method @Nullable public android.os.vibrator.VibratorFrequencyProfileLegacy getFrequencyProfileLegacy();
     method public boolean hasFrequencyControl();
     field public static final int VIBRATION_INTENSITY_HIGH = 3; // 0x3
     field public static final int VIBRATION_INTENSITY_LOW = 1; // 0x1
@@ -2793,7 +2794,7 @@
     field @NonNull public static final android.os.Parcelable.Creator<android.os.vibrator.VibrationEffectSegment> CREATOR;
   }
 
-  public final class VibratorFrequencyProfile {
+  public final class VibratorFrequencyProfileLegacy {
     method public float getMaxAmplitudeMeasurementInterval();
     method @FloatRange(from=0, to=1) @NonNull public float[] getMaxAmplitudeMeasurements();
     method public float getMaxFrequency();
diff --git a/core/java/Android.bp b/core/java/Android.bp
index 2fa418a..1265de1 100644
--- a/core/java/Android.bp
+++ b/core/java/Android.bp
@@ -647,7 +647,6 @@
 
 java_library {
     name: "protolog-lib",
-    platform_apis: true,
     srcs: [
         "com/android/internal/protolog/ProtoLogImpl.java",
         "com/android/internal/protolog/ProtoLogViewerConfigReader.java",
diff --git a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
index 8bb2857..5bc7de9 100644
--- a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
+++ b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
@@ -84,19 +84,25 @@
  * @attr ref android.R.styleable#AccessibilityService_accessibilityEventTypes
  * @attr ref android.R.styleable#AccessibilityService_accessibilityFeedbackType
  * @attr ref android.R.styleable#AccessibilityService_accessibilityFlags
+ * @attr ref android.R.styleable#AccessibilityService_animatedImageDrawable
+ * @attr ref android.R.styleable#AccessibilityService_canControlMagnification
+ * @attr ref android.R.styleable#AccessibilityService_canPerformGestures
  * @attr ref android.R.styleable#AccessibilityService_canRequestFilterKeyEvents
+ * @attr ref android.R.styleable#AccessibilityService_canRequestFingerprintGestures
  * @attr ref android.R.styleable#AccessibilityService_canRequestTouchExplorationMode
  * @attr ref android.R.styleable#AccessibilityService_canRetrieveWindowContent
- * @attr ref android.R.styleable#AccessibilityService_intro
+ * @attr ref android.R.styleable#AccessibilityService_canTakeScreenshot
  * @attr ref android.R.styleable#AccessibilityService_description
- * @attr ref android.R.styleable#AccessibilityService_summary
+ * @attr ref android.R.styleable#AccessibilityService_htmlDescription
+ * @attr ref android.R.styleable#AccessibilityService_interactiveUiTimeout
+ * @attr ref android.R.styleable#AccessibilityService_intro
+ * @attr ref android.R.styleable#AccessibilityService_isAccessibilityTool
+ * @attr ref android.R.styleable#AccessibilityService_nonInteractiveUiTimeout
  * @attr ref android.R.styleable#AccessibilityService_notificationTimeout
  * @attr ref android.R.styleable#AccessibilityService_packageNames
  * @attr ref android.R.styleable#AccessibilityService_settingsActivity
+ * @attr ref android.R.styleable#AccessibilityService_summary
  * @attr ref android.R.styleable#AccessibilityService_tileService
- * @attr ref android.R.styleable#AccessibilityService_nonInteractiveUiTimeout
- * @attr ref android.R.styleable#AccessibilityService_interactiveUiTimeout
- * @attr ref android.R.styleable#AccessibilityService_canTakeScreenshot
  * @see AccessibilityService
  * @see android.view.accessibility.AccessibilityEvent
  * @see android.view.accessibility.AccessibilityManager
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index d318812..3bd121a 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -1323,4 +1323,12 @@
      */
     public abstract void killApplicationSync(String pkgName, int appId, int userId,
             String reason, int exitInfoReason);
+
+    /**
+     * Add a creator token for all embedded intents (stored as extra) of the given intent.
+     *
+     * @param intent The given intent
+     * @hide
+     */
+    public abstract void addCreatorToken(Intent intent);
 }
diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java
index 6ab39b0..832c88a 100644
--- a/core/java/android/app/ActivityOptions.java
+++ b/core/java/android/app/ActivityOptions.java
@@ -120,7 +120,7 @@
     /**
      * Grants the {@link PendingIntent} background activity start privileges.
      *
-     * This behaves the same as {@link #MODE_BACKGROUND_ACTIVITY_START_ALLOWED_ALWAYS}, except it
+     * This behaves the same as {@link #MODE_BACKGROUND_ACTIVITY_START_ALLOW_ALWAYS}, except it
      * does not grant background activity launch permissions based on the privileged permission
      * <code>START_ACTIVITIES_FROM_BACKGROUND</code>.
      *
@@ -136,7 +136,6 @@
     /**
      * Denies the {@link PendingIntent} any background activity start privileges.
      */
-    @FlaggedApi(Flags.FLAG_BAL_ADDITIONAL_START_MODES)
     public static final int MODE_BACKGROUND_ACTIVITY_START_DENIED = 2;
     /**
      * Grants the {@link PendingIntent} all background activity start privileges, including
@@ -146,12 +145,12 @@
      * <p><b>Caution:</b> This mode should be used sparingly. Most apps should use
      * {@link #MODE_BACKGROUND_ACTIVITY_START_ALLOW_IF_VISIBLE} instead, relying on notifications
      * or foreground services for background interactions to minimize user disruption. However,
-     * this mode  is necessary for specific use cases, such as companion apps responding to
+     * this mode is necessary for specific use cases, such as companion apps responding to
      * prompts from a connected device.
      *
      * <p>For more information on background activity start restrictions, see:
      * <a href="https://developer.android.com/guide/components/activities/background-starts">
-     * Restrictions on starting activities from  the background</a>
+     * Restrictions on starting activities from the background</a>
      */
     @FlaggedApi(Flags.FLAG_BAL_ADDITIONAL_START_MODES)
     public static final int MODE_BACKGROUND_ACTIVITY_START_ALLOW_ALWAYS = 3;
diff --git a/core/java/android/app/AppOps.md b/core/java/android/app/AppOps.md
index 7b11a03..535d62c 100644
--- a/core/java/android/app/AppOps.md
+++ b/core/java/android/app/AppOps.md
@@ -119,20 +119,20 @@
 In addition to proc state, the `AppOpsService` also receives process capability update from the
 `ActivityManagerService`. Proc capability specifies what while-in-use(`MODE_FOREGROUND`) operations
  the proc is allowed to perform in its current proc state. There are three proc capabilities
- defined so far: 
+ defined so far:
 `PROCESS_CAPABILITY_FOREGROUND_LOCATION`, `PROCESS_CAPABILITY_FOREGROUND_CAMERA` and
 `PROCESS_CAPABILITY_FOREGROUND_MICROPHONE`, they correspond to the while-in-use operation of
 location, camera and microphone (microphone is `RECORD_AUDIO`).
 
 In `ActivityManagerService`, `PROCESS_STATE_TOP` and `PROCESS_STATE_PERSISTENT` have all
 three capabilities, `PROCESS_STATE_FOREGROUND_SERVICE` has capabilities defined by
- `foregroundServiceType` that is specified in foreground service's manifest file. A client process 
+ `foregroundServiceType` that is specified in foreground service's manifest file. A client process
  can pass its capabilities to service using `BIND_INCLUDE_CAPABILITIES` flag.
 
 The proc state and capability are used for two use cases: Firstly, Tracking remembers the proc state
  for each tracked event. Secondly, `noteOp`/`checkOp` calls for app-op that are set to
  `MODE_FOREGROUND` are translated using the `AppOpsService.UidState.evalMode` method into
- `MODE_ALLOWED` when the app has the capability and `MODE_IGNORED` when the app does not have the 
+ `MODE_ALLOWED` when the app has the capability and `MODE_IGNORED` when the app does not have the
  capability. `checkOpRaw` calls are not affected.
 
 The current proc state and capability for an app can be read from `dumpsys appops`.
@@ -284,7 +284,7 @@
 ##### Self data accesses
 
 This is similar to the [synchronous data access](#synchronous-data-accesses) case only that the data
-provider and client are in the same process. In this case Android's RPC code is no involved and
+provider and client are in the same process. In this case Android's RPC code is not involved and
 `AppOpsManager.noteOp` directly triggers `OnOpNotedCallback.onSelfNoted`. This should be a uncommon
 case as it is uncommon for an app to provide data, esp. to itself.
 
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 5907af0..2e3d226 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -54,6 +54,7 @@
 import android.content.pm.ParceledListSlice;
 import android.database.DatabaseUtils;
 import android.health.connect.HealthConnectManager;
+import android.health.connect.HealthPermissions;
 import android.media.AudioAttributes.AttributeUsage;
 import android.media.MediaRouter2;
 import android.os.Binder;
@@ -263,6 +264,13 @@
     private static @Nullable OnOpNotedCallback sOnOpNotedCallback;
 
     /**
+     * Whether OP_NOTED_CALLBACK_FLAG_IGNORE_ASYNC was set when sOnOpNotedCallback was registered
+     * last time.
+     */
+    @GuardedBy("sLock")
+    private static boolean sIgnoreAsyncNotedCallback;
+
+    /**
      * Sync note-ops collected from {@link #readAndLogNotedAppops(Parcel)} that have not been
      * delivered to a callback yet.
      *
@@ -1607,9 +1615,12 @@
     public static final int OP_RECEIVE_SENSITIVE_NOTIFICATIONS =
             AppProtoEnums.APP_OP_RECEIVE_SENSITIVE_NOTIFICATIONS;
 
+    /** @hide Access to read heart rate sensor. */
+    public static final int OP_READ_HEART_RATE = AppProtoEnums.APP_OP_READ_HEART_RATE;
+
     /** @hide */
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
-    public static final int _NUM_OP = 149;
+    public static final int _NUM_OP = 150;
 
     /**
      * All app ops represented as strings.
@@ -1762,6 +1773,7 @@
             OPSTR_UNARCHIVAL_CONFIRMATION,
             OPSTR_EMERGENCY_LOCATION,
             OPSTR_RECEIVE_SENSITIVE_NOTIFICATIONS,
+            OPSTR_READ_HEART_RATE,
     })
     public @interface AppOpString {}
 
@@ -2499,6 +2511,11 @@
     public static final String OPSTR_RECEIVE_SENSITIVE_NOTIFICATIONS =
             "android:receive_sensitive_notifications";
 
+    /** @hide Access to read heart rate sensor. */
+    @SystemApi
+    @FlaggedApi(Flags.FLAG_REPLACE_BODY_SENSOR_PERMISSION_ENABLED)
+    public static final String OPSTR_READ_HEART_RATE = "android:read_heart_rate";
+
     /** {@link #sAppOpsToNote} not initialized yet for this op */
     private static final byte SHOULD_COLLECT_NOTE_OP_NOT_INITIALIZED = 0;
     /** Should not collect noting of this app-op in {@link #sAppOpsToNote} */
@@ -2572,6 +2589,8 @@
             OP_NEARBY_WIFI_DEVICES,
             // Notifications
             OP_POST_NOTIFICATION,
+            // Health
+            Flags.replaceBodySensorPermissionEnabled() ? OP_READ_HEART_RATE : OP_NONE,
     };
 
     /**
@@ -2612,6 +2631,7 @@
             OP_READ_SYSTEM_GRAMMATICAL_GENDER,
     };
 
+    @SuppressWarnings("FlaggedApi")
     static final AppOpInfo[] sAppOpInfos = new AppOpInfo[]{
         new AppOpInfo.Builder(OP_COARSE_LOCATION, OPSTR_COARSE_LOCATION, "COARSE_LOCATION")
             .setPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION)
@@ -3079,6 +3099,10 @@
         new AppOpInfo.Builder(OP_RECEIVE_SENSITIVE_NOTIFICATIONS,
                 OPSTR_RECEIVE_SENSITIVE_NOTIFICATIONS, "RECEIVE_SENSITIVE_NOTIFICATIONS")
                 .setDefaultMode(MODE_IGNORED).build(),
+        new AppOpInfo.Builder(OP_READ_HEART_RATE, OPSTR_READ_HEART_RATE, "READ_HEART_RATE")
+            .setPermission(Flags.replaceBodySensorPermissionEnabled() ?
+                HealthPermissions.READ_HEART_RATE : null)
+            .setDefaultMode(AppOpsManager.MODE_ALLOWED).build(),
     };
 
     // The number of longs needed to form a full bitmask of app ops
@@ -3132,6 +3156,10 @@
             }
         }
         for (int op : RUNTIME_PERMISSION_OPS) {
+            if (op == OP_NONE) {
+                // Skip ops with a disabled feature flag.
+                continue;
+            }
             if (sAppOpInfos[op].permission != null) {
                 sPermToOp.put(sAppOpInfos[op].permission, op);
             }
@@ -10090,6 +10118,22 @@
     private static final int COLLECT_SYNC = 2;
     private static final int COLLECT_ASYNC = 3;
 
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(flag = true, prefix = { "OP_NOTED_CALLBACK_FLAG_" }, value = {
+            OP_NOTED_CALLBACK_FLAG_IGNORE_ASYNC,
+    })
+    private @interface OpNotedCallbackFlags {}
+
+    /**
+     * Ignores async op noted events.
+     *
+     * @see #setOnOpNotedCallback
+     */
+    @FlaggedApi(android.permission.flags.Flags.FLAG_SYNC_ON_OP_NOTED_API)
+    public static final int OP_NOTED_CALLBACK_FLAG_IGNORE_ASYNC = 1;
+    private static final int OP_NOTED_CALLBACK_FLAG_ALL = OP_NOTED_CALLBACK_FLAG_IGNORE_ASYNC;
+
     /**
      * Mark an app-op as noted.
      */
@@ -10235,6 +10279,12 @@
      * <p>There can only ever be one collector per process. If there currently is another callback
      * set, this will fail.
      *
+     * <p>Note that if an app has multiple processes registering for this callback, the system would
+     * fan out async op noted callbacks to each of the processes, resulting in the same data being
+     * delivered multiple times to an app, which is usually undesired. To avoid this, consider
+     * listening to async ops only in one process. See
+     * {@link #setOnOpNotedCallback(Executor, OnOpNotedCallback, int)} for how to do this.
+     *
      * @param asyncExecutor executor to execute {@link OnOpNotedCallback#onAsyncNoted} on, {@code
      * null} to unset
      * @param callback listener to set, {@code null} to unset
@@ -10243,18 +10293,62 @@
      */
     public void setOnOpNotedCallback(@Nullable @CallbackExecutor Executor asyncExecutor,
             @Nullable OnOpNotedCallback callback) {
+        setOnOpNotedCallback(asyncExecutor, callback, /* flag */ 0);
+    }
+
+    /**
+     * Set a new {@link OnOpNotedCallback}.
+     *
+     * <p>There can only ever be one collector per process. If there currently is another callback
+     * set, this will fail.
+     *
+     * <p>This API allows the caller to listen only to sync and self op noted events, and ignore
+     * async ops. This is useful in the scenario where an app has multiple processes. Consider an
+     * example where an app has two processes, A and B. The op noted events are as follows:
+     * <ul>
+     * <li>op 1: process A, sync
+     * <li>op 2: process A, async
+     * <li>op 3: process B, sync
+     * <li>op 4: process B, async
+     * Any process that listens to async op noted events gets events originating from across ALL
+     * processes (op 2 and op 4 in this example). So if both process A and B register as listeners,
+     * both of them get op 2 and 4 which is not ideal. To avoid duplicates, one of the two processes
+     * should set {@link #OP_NOTED_CALLBACK_FLAG_IGNORE_ASYNC}. For example
+     * process A sets {@link #OP_NOTED_CALLBACK_FLAG_IGNORE_ASYNC} and would then only get its own
+     * sync event (op 1). The other process would then listen to all types of events and get op 2, 3
+     * and 4.
+     *
+     * Note that even with {@link #OP_NOTED_CALLBACK_FLAG_IGNORE_ASYNC},
+     * {@link #OnOpNotedCallback.onAsyncNoted} may still be invoked. This happens for sync events
+     * that were collected before a callback is registered.
+     *
+     * @param asyncExecutor executor to execute {@link OnOpNotedCallback#onAsyncNoted} on, {@code
+     * null} to unset
+     * @param callback listener to set, {@code null} to unset
+     * @param flags additional flags to modify the callback behavior, such as
+     * {@link #OP_NOTED_CALLBACK_FLAG_IGNORE_ASYNC}
+     *
+     * @throws IllegalStateException If another callback is already registered
+     */
+    @FlaggedApi(android.permission.flags.Flags.FLAG_SYNC_ON_OP_NOTED_API)
+    public void setOnOpNotedCallback(@Nullable @CallbackExecutor Executor asyncExecutor,
+            @Nullable OnOpNotedCallback callback, @OpNotedCallbackFlags int flags) {
         Preconditions.checkState((callback == null) == (asyncExecutor == null));
+        Preconditions.checkFlagsArgument(flags, OP_NOTED_CALLBACK_FLAG_ALL);
 
         synchronized (sLock) {
             if (callback == null) {
+                Preconditions.checkFlagsArgument(flags, 0);
                 Preconditions.checkState(sOnOpNotedCallback != null,
                         "No callback is currently registered");
 
-                try {
-                    mService.stopWatchingAsyncNoted(mContext.getPackageName(),
-                            sOnOpNotedCallback.mAsyncCb);
-                } catch (RemoteException e) {
-                    e.rethrowFromSystemServer();
+                if (!sIgnoreAsyncNotedCallback) {
+                    try {
+                        mService.stopWatchingAsyncNoted(mContext.getPackageName(),
+                                sOnOpNotedCallback.mAsyncCb);
+                    } catch (RemoteException e) {
+                        e.rethrowFromSystemServer();
+                    }
                 }
 
                 sOnOpNotedCallback = null;
@@ -10264,14 +10358,17 @@
 
                 callback.mAsyncExecutor = asyncExecutor;
                 sOnOpNotedCallback = callback;
+                sIgnoreAsyncNotedCallback = (flags & OP_NOTED_CALLBACK_FLAG_IGNORE_ASYNC) != 0;
 
                 List<AsyncNotedAppOp> missedAsyncOps = null;
-                try {
-                    mService.startWatchingAsyncNoted(mContext.getPackageName(),
-                            sOnOpNotedCallback.mAsyncCb);
-                    missedAsyncOps = mService.extractAsyncOps(mContext.getPackageName());
-                } catch (RemoteException e) {
-                    e.rethrowFromSystemServer();
+                if (!sIgnoreAsyncNotedCallback) {
+                    try {
+                        mService.startWatchingAsyncNoted(mContext.getPackageName(),
+                                sOnOpNotedCallback.mAsyncCb);
+                        missedAsyncOps = mService.extractAsyncOps(mContext.getPackageName());
+                    } catch (RemoteException e) {
+                        e.rethrowFromSystemServer();
+                    }
                 }
 
                 // Copy pointer so callback can be dispatched out of lock
@@ -10284,17 +10381,15 @@
                                 () -> onOpNotedCallback.onAsyncNoted(asyncNotedAppOp));
                     }
                 }
-                synchronized (this) {
-                    int numMissedSyncOps = sUnforwardedOps.size();
-                    if (onOpNotedCallback != null) {
-                        for (int i = 0; i < numMissedSyncOps; i++) {
-                            final AsyncNotedAppOp syncNotedAppOp = sUnforwardedOps.get(i);
-                            onOpNotedCallback.getAsyncNotedExecutor().execute(
-                                    () -> onOpNotedCallback.onAsyncNoted(syncNotedAppOp));
-                        }
+                int numMissedSyncOps = sUnforwardedOps.size();
+                if (onOpNotedCallback != null) {
+                    for (int i = 0; i < numMissedSyncOps; i++) {
+                        final AsyncNotedAppOp syncNotedAppOp = sUnforwardedOps.get(i);
+                        onOpNotedCallback.getAsyncNotedExecutor().execute(
+                                () -> onOpNotedCallback.onAsyncNoted(syncNotedAppOp));
                     }
-                    sUnforwardedOps.clear();
                 }
+                sUnforwardedOps.clear();
             }
         }
     }
diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java
index 93a9489..7eacaac 100644
--- a/core/java/android/app/Instrumentation.java
+++ b/core/java/android/app/Instrumentation.java
@@ -48,6 +48,9 @@
 import android.os.TestLooperManager;
 import android.os.UserHandle;
 import android.os.UserManager;
+import android.ravenwood.annotation.RavenwoodKeep;
+import android.ravenwood.annotation.RavenwoodKeepPartialClass;
+import android.ravenwood.annotation.RavenwoodReplace;
 import android.util.AndroidRuntimeException;
 import android.util.Log;
 import android.view.Display;
@@ -80,7 +83,7 @@
  * implementation is described to the system through an AndroidManifest.xml's
  * &lt;instrumentation&gt; tag.
  */
-@android.ravenwood.annotation.RavenwoodKeepPartialClass
+@RavenwoodKeepPartialClass
 public class Instrumentation {
 
     /**
@@ -136,7 +139,7 @@
     private UiAutomation mUiAutomation;
     private final Object mAnimationCompleteLock = new Object();
 
-    @android.ravenwood.annotation.RavenwoodKeep
+    @RavenwoodKeep
     public Instrumentation() {
     }
 
@@ -147,7 +150,7 @@
      * reflection, but it will serve as noticeable discouragement from
      * doing such a thing.
      */
-    @android.ravenwood.annotation.RavenwoodKeep
+    @RavenwoodKeep
     private void checkInstrumenting(String method) {
         // Check if we have an instrumentation context, as init should only get called by
         // the system in startup processes that are being instrumented.
@@ -162,7 +165,7 @@
      *
      * @hide
      */
-    @android.ravenwood.annotation.RavenwoodKeep
+    @RavenwoodKeep
     public boolean isInstrumenting() {
         // Check if we have an instrumentation context, as init should only get called by
         // the system in startup processes that are being instrumented.
@@ -326,7 +329,7 @@
      * 
      * @see #getTargetContext
      */
-    @android.ravenwood.annotation.RavenwoodKeep
+    @RavenwoodKeep
     public Context getContext() {
         return mInstrContext;
     }
@@ -351,7 +354,7 @@
      * 
      * @see #getContext
      */
-    @android.ravenwood.annotation.RavenwoodKeep
+    @RavenwoodKeep
     public Context getTargetContext() {
         return mAppContext;
     }
@@ -2407,10 +2410,11 @@
      *
      * @hide
      */
-    @android.ravenwood.annotation.RavenwoodKeep
-    public final void basicInit(Context instrContext, Context appContext) {
+    @RavenwoodKeep
+    public final void basicInit(Context instrContext, Context appContext, UiAutomation ui) {
         mInstrContext = instrContext;
         mAppContext = appContext;
+        mUiAutomation = ui;
     }
 
     /** @hide */
@@ -2501,6 +2505,7 @@
      *
      * @see UiAutomation
      */
+    @RavenwoodKeep
     public UiAutomation getUiAutomation() {
         return getUiAutomation(0);
     }
@@ -2539,6 +2544,7 @@
      *
      * @see UiAutomation
      */
+    @RavenwoodReplace
     public UiAutomation getUiAutomation(@UiAutomationFlags int flags) {
         boolean mustCreateNewAutomation = (mUiAutomation == null) || (mUiAutomation.isDestroyed());
 
@@ -2569,11 +2575,15 @@
         return null;
     }
 
+    private UiAutomation getUiAutomation$ravenwood(@UiAutomationFlags int flags) {
+        return mUiAutomation;
+    }
+
     /**
      * Takes control of the execution of messages on the specified looper until
      * {@link TestLooperManager#release} is called.
      */
-    @android.ravenwood.annotation.RavenwoodKeep
+    @RavenwoodKeep
     public TestLooperManager acquireLooperManager(Looper looper) {
         checkInstrumenting("acquireLooperManager");
         return new TestLooperManager(looper);
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 38632bd..8b33417 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -115,6 +115,7 @@
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.ContrastColorUtil;
 import com.android.internal.util.NotificationBigTextNormalizer;
+import com.android.internal.widget.NotificationProgressModel;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -810,6 +811,11 @@
     }
 
     private static boolean isStandardLayout(int layoutId) {
+        if (Flags.apiRichOngoing()) {
+            if (layoutId == R.layout.notification_template_material_progress) {
+                return true;
+            }
+        }
         return STANDARD_LAYOUTS.contains(layoutId);
     }
 
@@ -7313,12 +7319,16 @@
          */
         @VisibleForTesting
         public static int ensureButtonFillContrast(int color, int bg) {
-            return isColorDark(bg)
-                    ? ContrastColorUtil.findContrastColorAgainstDark(color, bg, true, 1.3)
-                    : ContrastColorUtil.findContrastColor(color, bg, true, 1.3);
+            return ensureColorContrast(color, bg, 1.3);
         }
 
 
+        private static int ensureColorContrast(int color, int bg, double contrastRatio) {
+            return isColorDark(bg)
+                    ? ContrastColorUtil.findContrastColorAgainstDark(color, bg, true, contrastRatio)
+                    : ContrastColorUtil.findContrastColor(color, bg, true, contrastRatio);
+        }
+
         /**
          * @return Whether we are currently building a notification from a legacy (an app that
          *         doesn't create material notifications by itself) app.
@@ -7683,6 +7693,10 @@
             return R.layout.notification_template_material_conversation;
         }
 
+        private int getProgressLayoutResource() {
+            return R.layout.notification_template_material_progress;
+        }
+
         private int getActionLayoutResource() {
             return R.layout.notification_material_action;
         }
@@ -11640,8 +11654,58 @@
 
             return getStandardView(mBuilder.getHeadsUpBaseLayoutResource(), p, null /* result */);
         }
+        /**
+         * @hide
+         */
+        @Override
+        public RemoteViews makeBigContentView() {
+            StandardTemplateParams p = mBuilder.mParams.reset()
+                    .viewType(StandardTemplateParams.VIEW_TYPE_BIG)
+                    .allowTextWithProgress(true)
+                    .hideProgress(true)
+                    .fillTextsFrom(mBuilder);
 
-        private static @NonNull ArrayList<Bundle> getProgressSegmentsAsBundleList(
+            // Replace the text with the big text, but only if the big text is not empty.
+            RemoteViews contentView = getStandardView(mBuilder.getProgressLayoutResource(), p,
+                    null /* result */);
+
+            // Bind progress start and end icons.
+            if (mStartIcon != null) {
+                contentView.setViewVisibility(R.id.notification_progress_start_icon, View.VISIBLE);
+                contentView.setImageViewIcon(R.id.notification_progress_start_icon, mStartIcon);
+            } else {
+                contentView.setViewVisibility(R.id.notification_progress_start_icon, View.GONE);
+            }
+
+            if (mEndIcon != null) {
+                contentView.setViewVisibility(R.id.notification_progress_end_icon, View.VISIBLE);
+                contentView.setImageViewIcon(R.id.notification_progress_end_icon, mEndIcon);
+            } else {
+                contentView.setViewVisibility(R.id.notification_progress_end_icon, View.GONE);
+            }
+
+            contentView.setViewVisibility(R.id.progress, View.VISIBLE);
+
+            final int backgroundColor = mBuilder.getColors(p).getBackgroundColor();
+            final int defaultProgressColor = mBuilder.getPrimaryAccentColor(p);
+            final NotificationProgressModel model = createProgressModel(
+                    defaultProgressColor, backgroundColor);
+            contentView.setBundle(R.id.progress,
+                    "setProgressModel", model.toBundle());
+
+            if (mTrackerIcon != null) {
+                contentView.setIcon(R.id.progress,
+                        "setProgressTrackerIcon",
+                        mTrackerIcon);
+            }
+
+            return contentView;
+        }
+
+        /**
+         * @hide
+         */
+        public static @NonNull ArrayList<Bundle> getProgressSegmentsAsBundleList(
                 @Nullable List<Segment> progressSegments) {
             final ArrayList<Bundle> segments = new ArrayList<>();
             if (progressSegments != null && !progressSegments.isEmpty()) {
@@ -11663,7 +11727,10 @@
             return segments;
         }
 
-        private static @NonNull List<Segment> getProgressSegmentsFromBundleList(
+        /**
+         * @hide
+         */
+        public  static @NonNull List<Segment> getProgressSegmentsFromBundleList(
                 @Nullable List<Bundle> segmentBundleList) {
             final ArrayList<Segment> segments = new ArrayList<>();
             if (segmentBundleList != null && !segmentBundleList.isEmpty()) {
@@ -11686,8 +11753,10 @@
 
             return segments;
         }
-
-        private static @NonNull ArrayList<Bundle> getProgressPointsAsBundleList(
+        /**
+         * @hide
+         */
+        public static @NonNull ArrayList<Bundle> getProgressPointsAsBundleList(
                 @Nullable List<Point> progressPoints) {
             final ArrayList<Bundle> points = new ArrayList<>();
             if (progressPoints != null && !progressPoints.isEmpty()) {
@@ -11709,7 +11778,10 @@
             return points;
         }
 
-        private static @NonNull List<Point> getProgressPointsFromBundleList(
+        /**
+         * @hide
+         */
+        public static @NonNull List<Point> getProgressPointsFromBundleList(
                 @Nullable List<Bundle> pointBundleList) {
             final ArrayList<Point> points = new ArrayList<>();
 
@@ -11731,6 +11803,78 @@
             return points;
         }
 
+        @NonNull
+        private NotificationProgressModel createProgressModel(int defaultProgressColor,
+                int backgroundColor) {
+            final NotificationProgressModel model;
+            if (mIndeterminate) {
+                final int indeterminateColor;
+                if (!mProgressSegments.isEmpty()) {
+                    indeterminateColor = mProgressSegments.get(0).mColor;
+                } else {
+                    indeterminateColor = defaultProgressColor;
+                }
+
+                model = new NotificationProgressModel(
+                        sanitizeProgressColor(indeterminateColor,
+                                backgroundColor, defaultProgressColor));
+            } else {
+
+                // Ensure segment color contrasts.
+                final List<Segment> segments = new ArrayList<>();
+                for (Segment segment : mProgressSegments) {
+                    segments.add(sanitizeSegment(segment, backgroundColor,
+                            defaultProgressColor));
+                }
+
+                // Create default segment when no segments are provided.
+                if (segments.isEmpty()) {
+                    segments.add(sanitizeSegment(new Segment(100), backgroundColor,
+                            defaultProgressColor));
+                }
+
+                // Ensure point color contrasts.
+                final List<Point> points = new ArrayList<>();
+                for (Point point : mProgressPoints) {
+                    points.add(sanitizePoint(point, backgroundColor, defaultProgressColor));
+                }
+
+                model = new NotificationProgressModel(segments, points,
+                        mProgress, mIsStyledByProgress);
+            }
+            return model;
+        }
+
+        private Segment sanitizeSegment(@NonNull Segment segment,
+                @ColorInt int bg,
+                @ColorInt int defaultColor) {
+            return new Segment(segment.getLength())
+                    .setId(segment.getId())
+                    .setColor(sanitizeProgressColor(segment.getColor(), bg, defaultColor));
+        }
+
+        private Point sanitizePoint(@NonNull Point point,
+                @ColorInt int bg,
+                @ColorInt int defaultColor) {
+            return new Point(point.getPosition()).setId(point.getId())
+                    .setColor(sanitizeProgressColor(point.getColor(), bg, defaultColor));
+        }
+
+        /**
+         * Finds steps and points fill color with sufficient contrast over bg (1.3:1) that
+         * has the same hue as the original color, but is lightened or darkened depending on
+         * whether the background is dark or light.
+         *
+         */
+        private int sanitizeProgressColor(@ColorInt int color,
+                @ColorInt int bg,
+                @ColorInt int defaultColor) {
+            return Builder.ensureColorContrast(
+                    Color.alpha(color) == 0 ? defaultColor : color,
+                    bg,
+                    1.3);
+        }
+
         /**
          * A segment of the progress bar, which defines its length and color.
          * Segments allow for creating progress bars with multiple colors or sections
diff --git a/core/java/android/app/PendingIntent.java b/core/java/android/app/PendingIntent.java
index 3714e5d..393ec8c 100644
--- a/core/java/android/app/PendingIntent.java
+++ b/core/java/android/app/PendingIntent.java
@@ -1094,6 +1094,9 @@
             @Nullable String requiredPermission, @Nullable Bundle options)
             throws CanceledException {
         try {
+            if (intent != null) {
+                intent.collectExtraIntentKeys();
+            }
             String resolvedType = intent != null ?
                     intent.resolveTypeIfNeeded(context.getContentResolver())
                     : null;
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index c1c96ea..014e4660 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -285,6 +285,14 @@
     public static final String COMMAND_UNFREEZE = "android.wallpaper.unfreeze";
 
     /**
+     * Command for {@link #sendWallpaperCommand}: in sendWallpaperCommand put extra to this command
+     * to give the bounds of space between the bottom of notifications and the top of shortcuts
+     * @hide
+     */
+    public static final String COMMAND_LOCKSCREEN_LAYOUT_CHANGED =
+            "android.wallpaper.lockscreen_layout_changed";
+
+    /**
      * Extra passed back from setWallpaper() giving the new wallpaper's assigned ID.
      * @hide
      */
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 9be928f..102540c 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -470,16 +470,9 @@
      * that the user backed-out of provisioning or some precondition for provisioning wasn't met.
      *
      * <p>If a <a href="#roleholder">device policy management role holder</a> updater is present on
-     * the device, an internet connection attempt must be made prior to launching this intent. If
-     * an internet connection can not be established, provisioning will fail unless {@link
-     * #EXTRA_PROVISIONING_ALLOW_OFFLINE} is explicitly set to {@code true}, in which case
-     * provisioning will continue without using the
-     * <a href="#roleholder">device policy management role holder</a>. If an internet connection
-     * has been established, the <a href="#roleholder">device policy management role holder</a>
-     * updater will be launched, which may update the
-     * <a href="#roleholder">device policy management role holder</a> before continuing
-     * provisioning.
+     * the device, an internet connection attempt must be made prior to launching this intent.
      */
+    // See b/365955253 for additional behaviours of this API.
     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
     public static final String ACTION_PROVISION_MANAGED_PROFILE
         = "android.app.action.PROVISION_MANAGED_PROFILE";
@@ -960,23 +953,8 @@
      * A boolean extra indicating whether offline provisioning should be used.
      *
      * <p>The default value is {@code false}.
-     *
-     * <p>Usually during the <a href="#managedprovisioning">provisioning flow</a>, there will be
-     * an attempt to download and install the latest version of the <a href="#roleholder">device
-     * policy management role holder</a>. The platform will then
-     * delegate provisioning to the <a href="#roleholder">device
-     *      * policy management role holder</a>.
-     *
-     * <p>When this extra is set to {@code true}, the
-     * <a href="#managedprovisioning">provisioning flow</a> will always be handled by the platform
-     * and the <a href="#roleholder">device policy management role holder</a>'s part skipped.
-     *
-     * <p>On Android versions prior to {@link Build.VERSION_CODES#TIRAMISU}, when this extra is
-     * {@code false}, the <a href="#managedprovisioning">provisioning flow</a> will enforce that an
-     * internet connection is established, or otherwise fail. When this extra is {@code true}, a
-     * connection will still be attempted but when it cannot be established provisioning will
-     * continue offline.
      */
+    // See b/365955253 for detailed behaviours of this API.
     public static final String EXTRA_PROVISIONING_ALLOW_OFFLINE =
             "android.app.extra.PROVISIONING_ALLOW_OFFLINE";
 
diff --git a/core/java/android/app/appfunctions/AppFunctionManagerConfiguration.java b/core/java/android/app/appfunctions/AppFunctionManagerConfiguration.java
index fa77e79..cb21d1f 100644
--- a/core/java/android/app/appfunctions/AppFunctionManagerConfiguration.java
+++ b/core/java/android/app/appfunctions/AppFunctionManagerConfiguration.java
@@ -20,7 +20,6 @@
 
 import android.annotation.NonNull;
 import android.content.Context;
-import android.content.pm.PackageManager;
 
 /**
  * Represents the system configuration of support for the {@code AppFunctionManager} and associated
@@ -29,15 +28,13 @@
  * @hide
  */
 public class AppFunctionManagerConfiguration {
-    private final Context mContext;
-
     /**
      * Constructs a new instance of {@code AppFunctionManagerConfiguration}.
      *
      * @param context context
      */
     public AppFunctionManagerConfiguration(@NonNull final Context context) {
-        mContext = context;
+        // Context can be used to access system features, etc.
     }
 
     /**
@@ -46,7 +43,7 @@
      * @return {@code true} if supported; otherwise {@code false}
      */
     public boolean isSupported() {
-        return enableAppFunctionManager() && !isWatch();
+        return enableAppFunctionManager();
     }
 
     /**
@@ -58,8 +55,4 @@
     public static boolean isSupported(@NonNull final Context context) {
         return new AppFunctionManagerConfiguration(context).isSupported();
     }
-
-    private boolean isWatch() {
-        return mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH);
-    }
 }
diff --git a/core/java/android/app/appfunctions/AppFunctionService.java b/core/java/android/app/appfunctions/AppFunctionService.java
index 7a68a65..ceca850 100644
--- a/core/java/android/app/appfunctions/AppFunctionService.java
+++ b/core/java/android/app/appfunctions/AppFunctionService.java
@@ -29,11 +29,9 @@
 import android.content.Context;
 import android.content.Intent;
 import android.os.Binder;
-import android.os.Bundle;
+import android.os.CancellationSignal;
 import android.os.IBinder;
 import android.os.ICancellationSignal;
-import android.os.CancellationSignal;
-import android.os.RemoteCallback;
 import android.os.RemoteException;
 import android.util.Log;
 
@@ -80,6 +78,7 @@
          */
         void perform(
                 @NonNull ExecuteAppFunctionRequest request,
+                @NonNull String callingPackage,
                 @NonNull CancellationSignal cancellationSignal,
                 @NonNull Consumer<ExecuteAppFunctionResponse> callback);
     }
@@ -92,6 +91,7 @@
             @Override
             public void executeAppFunction(
                     @NonNull ExecuteAppFunctionRequest request,
+                    @NonNull String callingPackage,
                     @NonNull ICancellationCallback cancellationCallback,
                     @NonNull IExecuteAppFunctionCallback callback) {
                 if (context.checkCallingPermission(BIND_APP_FUNCTION_SERVICE)
@@ -103,6 +103,7 @@
                 try {
                     onExecuteFunction.perform(
                             request,
+                            callingPackage,
                             buildCancellationSignal(cancellationCallback),
                             safeCallback::onResult);
                 } catch (Exception ex) {
@@ -128,12 +129,11 @@
             throw e.rethrowFromSystemServer();
         }
 
-        return cancellationSignal ;
+        return cancellationSignal;
     }
 
-    private final Binder mBinder = createBinder(
-            AppFunctionService.this,
-            AppFunctionService.this::onExecuteFunction);
+    private final Binder mBinder =
+            createBinder(AppFunctionService.this, AppFunctionService.this::onExecuteFunction);
 
     @NonNull
     @Override
@@ -141,7 +141,6 @@
         return mBinder;
     }
 
-
     /**
      * Called by the system to execute a specific app function.
      *
@@ -161,7 +160,6 @@
      *
      * @param request The function execution request.
      * @param callback A callback to report back the result.
-     *
      * @deprecated Use {@link #onExecuteFunction(ExecuteAppFunctionRequest, CancellationSignal,
      *     Consumer)} instead. This method will be removed once usage references are updated.
      */
@@ -198,12 +196,50 @@
      * @param request The function execution request.
      * @param cancellationSignal A signal to cancel the execution.
      * @param callback A callback to report back the result.
+     * @deprecated Use {@link #onExecuteFunction(ExecuteAppFunctionRequest, String,
+     *     CancellationSignal, Consumer)} instead. This method will be removed once usage references
+     *     are updated.
      */
     @MainThread
+    @Deprecated
     public void onExecuteFunction(
             @NonNull ExecuteAppFunctionRequest request,
             @NonNull CancellationSignal cancellationSignal,
             @NonNull Consumer<ExecuteAppFunctionResponse> callback) {
         onExecuteFunction(request, callback);
     }
+
+    /**
+     * Called by the system to execute a specific app function.
+     *
+     * <p>This method is triggered when the system requests your AppFunctionService to handle a
+     * particular function you have registered and made available.
+     *
+     * <p>To ensure proper routing of function requests, assign a unique identifier to each
+     * function. This identifier doesn't need to be globally unique, but it must be unique within
+     * your app. For example, a function to order food could be identified as "orderFood". In most
+     * cases this identifier should come from the ID automatically generated by the AppFunctions
+     * SDK. You can determine the specific function to invoke by calling {@link
+     * ExecuteAppFunctionRequest#getFunctionIdentifier()}.
+     *
+     * <p>This method is always triggered in the main thread. You should run heavy tasks on a worker
+     * thread and dispatch the result with the given callback. You should always report back the
+     * result using the callback, no matter if the execution was successful or not.
+     *
+     * <p>This method also accepts a {@link CancellationSignal} that the app should listen to cancel
+     * the execution of function if requested by the system.
+     *
+     * @param request The function execution request.
+     * @param callingPackage The package name of the app that is requesting the execution.
+     * @param cancellationSignal A signal to cancel the execution.
+     * @param callback A callback to report back the result.
+     */
+    @MainThread
+    public void onExecuteFunction(
+            @NonNull ExecuteAppFunctionRequest request,
+            @NonNull String callingPackage,
+            @NonNull CancellationSignal cancellationSignal,
+            @NonNull Consumer<ExecuteAppFunctionResponse> callback) {
+        onExecuteFunction(request, cancellationSignal, callback);
+    }
 }
diff --git a/core/java/android/app/appfunctions/IAppFunctionService.aidl b/core/java/android/app/appfunctions/IAppFunctionService.aidl
index 291f33c..bf935d2 100644
--- a/core/java/android/app/appfunctions/IAppFunctionService.aidl
+++ b/core/java/android/app/appfunctions/IAppFunctionService.aidl
@@ -34,11 +34,13 @@
      * Called by the system to execute a specific app function.
      *
      * @param request  the function execution request.
+     * @param callingPackage The package name of the app that is requesting the execution.
      * @param cancellationCallback a callback to send back the cancellation transport.
      * @param callback a callback to report back the result.
      */
     void executeAppFunction(
         in ExecuteAppFunctionRequest request,
+        in String callingPackage,
         in ICancellationCallback cancellationCallback,
         in IExecuteAppFunctionCallback callback
     );
diff --git a/core/java/android/app/assist/AssistStructure.java b/core/java/android/app/assist/AssistStructure.java
index 508077e..1af2437 100644
--- a/core/java/android/app/assist/AssistStructure.java
+++ b/core/java/android/app/assist/AssistStructure.java
@@ -1,5 +1,6 @@
 package android.app.assist;
 
+import static android.app.assist.flags.Flags.addPlaceholderViewForNullChild;
 import static android.credentials.Constants.FAILURE_CREDMAN_SELECTOR;
 import static android.credentials.Constants.SUCCESS_CREDMAN_SELECTOR;
 import static android.service.autofill.Flags.FLAG_AUTOFILL_CREDMAN_DEV_INTEGRATION;
@@ -284,12 +285,18 @@
             mCurViewStackEntry = entry;
         }
 
-        void writeView(ViewNode child, Parcel out, PooledStringWriter pwriter, int levelAdj) {
+        void writeView(@Nullable ViewNode child, Parcel out, PooledStringWriter pwriter,
+            int levelAdj) {
             if (DEBUG_PARCEL) Log.d(TAG, "write view: at " + out.dataPosition()
                     + ", windows=" + mNumWrittenWindows
                     + ", views=" + mNumWrittenViews
                     + ", level=" + (mCurViewStackPos+levelAdj));
             out.writeInt(VALIDATE_VIEW_TOKEN);
+            if (addPlaceholderViewForNullChild() && child == null) {
+                if (DEBUG_PARCEL_TREE) Log.d(TAG, "Detected an empty child"
+                            + "; writing a placeholder for the child.");
+                child = new ViewNode();
+            }
             int flags = child.writeSelfToParcel(out, pwriter, mSanitizeOnWrite,
                     mTmpMatrix, /*willWriteChildren=*/true);
             mNumWrittenViews++;
@@ -2545,7 +2552,7 @@
             ensureData();
         }
         Log.i(TAG, "Task id: " + mTaskId);
-        Log.i(TAG, "Activity: " + (mActivityComponent != null 
+        Log.i(TAG, "Activity: " + (mActivityComponent != null
                 ? mActivityComponent.flattenToShortString()
                 : null));
         Log.i(TAG, "Sanitize on write: " + mSanitizeOnWrite);
diff --git a/core/java/android/app/assist/flags.aconfig b/core/java/android/app/assist/flags.aconfig
new file mode 100644
index 0000000..bf0aeac
--- /dev/null
+++ b/core/java/android/app/assist/flags.aconfig
@@ -0,0 +1,13 @@
+package: "android.app.assist.flags"
+container: "system"
+
+flag {
+  name: "add_placeholder_view_for_null_child"
+  namespace: "machine_learning"
+  description: "Flag to add a placeholder view when a child view is null."
+  bug: "369503426"
+  is_fixed_read_only: true
+  metadata {
+    purpose: PURPOSE_BUGFIX
+  }
+}
diff --git a/core/java/android/app/notification.aconfig b/core/java/android/app/notification.aconfig
index b139017..8014537 100644
--- a/core/java/android/app/notification.aconfig
+++ b/core/java/android/app/notification.aconfig
@@ -251,7 +251,7 @@
   name: "api_rich_ongoing"
   is_exported: true
   namespace: "systemui"
-  description: "Guards new android.app.richongoingnotification api"
+  description: "[RONs] Guards new RON-related APIs, including Notification.ProgressStyle"
   bug: "337261753"
 }
 
@@ -259,6 +259,6 @@
   name: "ui_rich_ongoing"
   is_exported: true
   namespace: "systemui"
-  description: "Guards new android.app.richongoingnotification promotion and new uis"
-  bug: "337261753"
+  description: "[RONs] Guards new promotion logic and UI, including AOD notification and Colorization"
+  bug: "367705002"
 }
diff --git a/core/java/android/app/wearable/flags.aconfig b/core/java/android/app/wearable/flags.aconfig
index b68bafe..534f461 100644
--- a/core/java/android/app/wearable/flags.aconfig
+++ b/core/java/android/app/wearable/flags.aconfig
@@ -38,4 +38,12 @@
     namespace: "machine_learning"
     description: "This flag enables the APIs related to hotword in WearableSensingManager and WearableSensingService."
     bug: "310055381"
+}
+
+flag {
+    name: "enable_concurrent_wearable_connections"
+    is_exported: true
+    namespace: "machine_learning"
+    description: "This flag enables the APIs for providing multiple concurrent connections to the WearableSensingService."
+    bug: "358133158"
 }
\ No newline at end of file
diff --git a/core/java/android/companion/AssociationInfo.java b/core/java/android/companion/AssociationInfo.java
index b4b96e2..7f30d7c 100644
--- a/core/java/android/companion/AssociationInfo.java
+++ b/core/java/android/companion/AssociationInfo.java
@@ -22,6 +22,7 @@
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
 import android.annotation.UserIdInt;
+import android.graphics.drawable.Icon;
 import android.net.MacAddress;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -86,6 +87,11 @@
     private final int mSystemDataSyncFlags;
 
     /**
+     * A device icon displayed on a selfManaged association dialog.
+     */
+    private final Icon mDeviceIcon;
+
+    /**
      * Creates a new Association.
      *
      * @hide
@@ -95,7 +101,7 @@
             @Nullable CharSequence displayName, @Nullable String deviceProfile,
             @Nullable AssociatedDevice associatedDevice, boolean selfManaged,
             boolean notifyOnDeviceNearby, boolean revoked, boolean pending, long timeApprovedMs,
-            long lastTimeConnectedMs, int systemDataSyncFlags) {
+            long lastTimeConnectedMs, int systemDataSyncFlags, @Nullable Icon deviceIcon) {
         if (id <= 0) {
             throw new IllegalArgumentException("Association ID should be greater than 0");
         }
@@ -119,6 +125,7 @@
         mTimeApprovedMs = timeApprovedMs;
         mLastTimeConnectedMs = lastTimeConnectedMs;
         mSystemDataSyncFlags = systemDataSyncFlags;
+        mDeviceIcon = deviceIcon;
     }
 
     /**
@@ -278,6 +285,20 @@
     }
 
     /**
+     * Get the device icon of the associated device. The device icon represents the device type.
+     *
+     * @return the device icon, or {@code null} if no device icon is has been set for the
+     * associated device.
+     *
+     * @see AssociationRequest.Builder#setDeviceIcon(Icon)
+     */
+    @FlaggedApi(Flags.FLAG_ASSOCIATION_DEVICE_ICON)
+    @Nullable
+    public Icon getDeviceIcon() {
+        return mDeviceIcon;
+    }
+
+    /**
      * Utility method for checking if the association represents a device with the given MAC
      * address.
      *
@@ -370,14 +391,16 @@
                 && Objects.equals(mDisplayName, that.mDisplayName)
                 && Objects.equals(mDeviceProfile, that.mDeviceProfile)
                 && Objects.equals(mAssociatedDevice, that.mAssociatedDevice)
-                && mSystemDataSyncFlags == that.mSystemDataSyncFlags;
+                && mSystemDataSyncFlags == that.mSystemDataSyncFlags
+                && (mDeviceIcon == null ? that.mDeviceIcon == null
+                : mDeviceIcon.sameAs(that.mDeviceIcon));
     }
 
     @Override
     public int hashCode() {
         return Objects.hash(mId, mUserId, mPackageName, mTag, mDeviceMacAddress, mDisplayName,
                 mDeviceProfile, mAssociatedDevice, mSelfManaged, mNotifyOnDeviceNearby, mRevoked,
-                mPending, mTimeApprovedMs, mLastTimeConnectedMs, mSystemDataSyncFlags);
+                mPending, mTimeApprovedMs, mLastTimeConnectedMs, mSystemDataSyncFlags, mDeviceIcon);
     }
 
     @Override
@@ -402,6 +425,12 @@
         dest.writeLong(mTimeApprovedMs);
         dest.writeLong(mLastTimeConnectedMs);
         dest.writeInt(mSystemDataSyncFlags);
+        if (mDeviceIcon != null) {
+            dest.writeInt(1);
+            mDeviceIcon.writeToParcel(dest, flags);
+        } else {
+            dest.writeInt(0);
+        }
     }
 
     private AssociationInfo(@NonNull Parcel in) {
@@ -420,6 +449,11 @@
         mTimeApprovedMs = in.readLong();
         mLastTimeConnectedMs = in.readLong();
         mSystemDataSyncFlags = in.readInt();
+        if (in.readInt() == 1) {
+            mDeviceIcon = Icon.CREATOR.createFromParcel(in);
+        } else {
+            mDeviceIcon = null;
+        }
     }
 
     @NonNull
@@ -459,6 +493,7 @@
         private long mTimeApprovedMs;
         private long mLastTimeConnectedMs;
         private int mSystemDataSyncFlags;
+        private Icon mDeviceIcon;
 
         /** @hide */
         @TestApi
@@ -486,6 +521,7 @@
             mTimeApprovedMs = info.mTimeApprovedMs;
             mLastTimeConnectedMs = info.mLastTimeConnectedMs;
             mSystemDataSyncFlags = info.mSystemDataSyncFlags;
+            mDeviceIcon = info.mDeviceIcon;
         }
 
         /**
@@ -510,6 +546,7 @@
             mTimeApprovedMs = info.mTimeApprovedMs;
             mLastTimeConnectedMs = info.mLastTimeConnectedMs;
             mSystemDataSyncFlags = info.mSystemDataSyncFlags;
+            mDeviceIcon = info.mDeviceIcon;
         }
 
         /** @hide */
@@ -625,6 +662,16 @@
         /** @hide */
         @TestApi
         @NonNull
+        @SuppressLint("MissingGetterMatchingBuilder")
+        @FlaggedApi(Flags.FLAG_ASSOCIATION_DEVICE_ICON)
+        public Builder setDeviceIcon(@Nullable Icon deviceIcon) {
+            mDeviceIcon = deviceIcon;
+            return this;
+        }
+
+        /** @hide */
+        @TestApi
+        @NonNull
         public AssociationInfo build() {
             if (mId <= 0) {
                 throw new IllegalArgumentException("Association ID should be greater than 0");
@@ -648,7 +695,8 @@
                     mPending,
                     mTimeApprovedMs,
                     mLastTimeConnectedMs,
-                    mSystemDataSyncFlags
+                    mSystemDataSyncFlags,
+                    mDeviceIcon
             );
         }
     }
diff --git a/core/java/android/companion/AssociationRequest.java b/core/java/android/companion/AssociationRequest.java
index 2e969f8..41a6791 100644
--- a/core/java/android/companion/AssociationRequest.java
+++ b/core/java/android/companion/AssociationRequest.java
@@ -23,12 +23,14 @@
 import static java.util.Objects.requireNonNull;
 
 import android.Manifest;
+import android.annotation.FlaggedApi;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
 import android.annotation.StringDef;
 import android.annotation.UserIdInt;
 import android.compat.annotation.UnsupportedAppUsage;
+import android.graphics.drawable.Icon;
 import android.os.Build;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -234,6 +236,13 @@
     private boolean mSkipPrompt;
 
     /**
+     * The device icon displayed in selfManaged association dialog.
+     * @hide
+     */
+    @Nullable
+    private Icon mDeviceIcon;
+
+    /**
      * Creates a new AssociationRequest.
      *
      * @param singleDevice
@@ -258,15 +267,16 @@
             @Nullable @DeviceProfile String deviceProfile,
             @Nullable CharSequence displayName,
             boolean selfManaged,
-            boolean forceConfirmation) {
+            boolean forceConfirmation,
+            @Nullable Icon deviceIcon) {
         mSingleDevice = singleDevice;
         mDeviceFilters = requireNonNull(deviceFilters);
         mDeviceProfile = deviceProfile;
         mDisplayName = displayName;
         mSelfManaged = selfManaged;
         mForceConfirmation = forceConfirmation;
-
         mCreationTime = System.currentTimeMillis();
+        mDeviceIcon = deviceIcon;
     }
 
     /**
@@ -318,6 +328,19 @@
         return mSingleDevice;
     }
 
+    /**
+     * Get the device icon of the self-managed association request.
+     *
+     * @return the device icon, or {@code null} if no device icon has been set.
+     *
+     * @see Builder#setDeviceIcon(Icon)
+     */
+    @FlaggedApi(Flags.FLAG_ASSOCIATION_DEVICE_ICON)
+    @Nullable
+    public Icon getDeviceIcon() {
+        return mDeviceIcon;
+    }
+
     /** @hide */
     public void setPackageName(@NonNull String packageName) {
         mPackageName = packageName;
@@ -365,6 +388,7 @@
         private CharSequence mDisplayName;
         private boolean mSelfManaged = false;
         private boolean mForceConfirmation = false;
+        private Icon mDeviceIcon = null;
 
         public Builder() {}
 
@@ -450,6 +474,23 @@
             return this;
         }
 
+        /**
+         * Set the device icon for the self-managed device and this icon will be
+         * displayed in the self-managed association dialog.
+         *
+         * @throws IllegalArgumentException if the icon is not exactly 24dp by 24dp
+         * or if it is {@link Icon#TYPE_URI} or {@link Icon#TYPE_URI_ADAPTIVE_BITMAP}.
+         * @see #setSelfManaged(boolean)
+         */
+        @NonNull
+        @RequiresPermission(REQUEST_COMPANION_SELF_MANAGED)
+        @FlaggedApi(Flags.FLAG_ASSOCIATION_DEVICE_ICON)
+        public Builder setDeviceIcon(@NonNull Icon deviceIcon) {
+            checkNotUsed();
+            mDeviceIcon = requireNonNull(deviceIcon);
+            return this;
+        }
+
         /** @inheritDoc */
         @NonNull
         @Override
@@ -460,7 +501,7 @@
                         + "provide the display name of the device");
             }
             return new AssociationRequest(mSingleDevice, emptyIfNull(mDeviceFilters),
-                    mDeviceProfile, mDisplayName, mSelfManaged, mForceConfirmation);
+                    mDeviceProfile, mDisplayName, mSelfManaged, mForceConfirmation, mDeviceIcon);
         }
     }
 
@@ -561,7 +602,9 @@
                 && Objects.equals(mDeviceProfilePrivilegesDescription,
                         that.mDeviceProfilePrivilegesDescription)
                 && mCreationTime == that.mCreationTime
-                && mSkipPrompt == that.mSkipPrompt;
+                && mSkipPrompt == that.mSkipPrompt
+                && (mDeviceIcon == null ? that.mDeviceIcon == null
+                : mDeviceIcon.sameAs(that.mDeviceIcon));
     }
 
     @Override
@@ -579,6 +622,8 @@
         _hash = 31 * _hash + Objects.hashCode(mDeviceProfilePrivilegesDescription);
         _hash = 31 * _hash + Long.hashCode(mCreationTime);
         _hash = 31 * _hash + Boolean.hashCode(mSkipPrompt);
+        _hash = 31 * _hash + Objects.hashCode(mDeviceIcon);
+
         return _hash;
     }
 
@@ -606,6 +651,12 @@
             dest.writeString8(mDeviceProfilePrivilegesDescription);
         }
         dest.writeLong(mCreationTime);
+        if (mDeviceIcon != null) {
+            dest.writeInt(1);
+            mDeviceIcon.writeToParcel(dest, flags);
+        } else {
+            dest.writeInt(0);
+        }
     }
 
     @Override
@@ -650,6 +701,11 @@
         this.mDeviceProfilePrivilegesDescription = deviceProfilePrivilegesDescription;
         this.mCreationTime = creationTime;
         this.mSkipPrompt = skipPrompt;
+        if (in.readInt() == 1) {
+            mDeviceIcon = Icon.CREATOR.createFromParcel(in);
+        } else {
+            mDeviceIcon = null;
+        }
     }
 
     @NonNull
diff --git a/core/java/android/companion/CompanionDeviceManager.java b/core/java/android/companion/CompanionDeviceManager.java
index 1cdf3b1..dfad6de 100644
--- a/core/java/android/companion/CompanionDeviceManager.java
+++ b/core/java/android/companion/CompanionDeviceManager.java
@@ -20,6 +20,8 @@
 import static android.Manifest.permission.REQUEST_COMPANION_PROFILE_AUTOMOTIVE_PROJECTION;
 import static android.Manifest.permission.REQUEST_COMPANION_PROFILE_COMPUTER;
 import static android.Manifest.permission.REQUEST_COMPANION_PROFILE_WATCH;
+import static android.graphics.drawable.Icon.TYPE_URI;
+import static android.graphics.drawable.Icon.TYPE_URI_ADAPTIVE_BITMAP;
 
 
 import android.annotation.CallbackExecutor;
@@ -49,6 +51,11 @@
 import android.content.Intent;
 import android.content.IntentSender;
 import android.content.pm.PackageManager;
+import android.graphics.Bitmap;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.Icon;
+import android.graphics.drawable.VectorDrawable;
 import android.net.MacAddress;
 import android.os.Binder;
 import android.os.Handler;
@@ -535,6 +542,13 @@
         Objects.requireNonNull(executor, "Executor cannot be null");
         Objects.requireNonNull(callback, "Callback cannot be null");
 
+        final Icon deviceIcon = request.getDeviceIcon();
+
+        if (deviceIcon != null && !isValidIcon(deviceIcon, mContext)) {
+            throw new IllegalArgumentException("The size of the device icon must be 24dp x 24dp to"
+                    + "ensure proper display");
+        }
+
         try {
             mService.associate(request, new AssociationRequestCallbackProxy(executor, callback),
                     mContext.getOpPackageName(), mContext.getUserId());
@@ -2027,4 +2041,34 @@
             }
         }
     }
+
+    private boolean isValidIcon(Icon icon, Context context) {
+        if (icon.getType() == TYPE_URI_ADAPTIVE_BITMAP || icon.getType() == TYPE_URI) {
+            throw new IllegalArgumentException("The URI based Icon is not supported.");
+        }
+        Drawable drawable = icon.loadDrawable(context);
+        float density = context.getResources().getDisplayMetrics().density;
+
+        if (drawable instanceof BitmapDrawable) {
+            Bitmap bitmap = ((BitmapDrawable) drawable).getBitmap();
+
+            float widthDp = bitmap.getWidth() / density;
+            float heightDp = bitmap.getHeight() / density;
+
+            if (widthDp != 24 || heightDp != 24) {
+                return false;
+            }
+        } else if (drawable instanceof VectorDrawable) {
+            VectorDrawable vectorDrawable = (VectorDrawable) drawable;
+            float widthDp = vectorDrawable.getIntrinsicWidth() / density;
+            float heightDp = vectorDrawable.getIntrinsicHeight() / density;
+
+            if (widthDp != 24 || heightDp != 24) {
+                return false;
+            }
+        } else {
+            throw new IllegalArgumentException("The format of the device icon is unsupported.");
+        }
+        return true;
+    }
 }
diff --git a/core/java/android/companion/flags.aconfig b/core/java/android/companion/flags.aconfig
index 93d62cf..2539a12 100644
--- a/core/java/android/companion/flags.aconfig
+++ b/core/java/android/companion/flags.aconfig
@@ -55,3 +55,11 @@
     description: "Enable association failure code API"
     bug: "331459560"
 }
+
+flag {
+    name: "association_device_icon"
+    is_exported: true
+    namespace: "companion"
+    description: "Enable set device icon API"
+    bug: "341057668"
+}
diff --git a/core/java/android/companion/virtual/IVirtualDevice.aidl b/core/java/android/companion/virtual/IVirtualDevice.aidl
index 6fe0a73..d3a1c25 100644
--- a/core/java/android/companion/virtual/IVirtualDevice.aidl
+++ b/core/java/android/companion/virtual/IVirtualDevice.aidl
@@ -31,6 +31,8 @@
 import android.content.IntentFilter;
 import android.graphics.Point;
 import android.graphics.PointF;
+import android.hardware.display.IVirtualDisplayCallback;
+import android.hardware.display.VirtualDisplayConfig;
 import android.hardware.input.VirtualDpadConfig;
 import android.hardware.input.VirtualKeyboardConfig;
 import android.hardware.input.VirtualKeyEvent;
@@ -93,96 +95,97 @@
      */
     boolean canCreateMirrorDisplays();
 
+    /*
+     * Turns off all trusted non-mirror displays of the virtual device.
+     */
+    void goToSleep();
+
+    /**
+     * Turns on all trusted non-mirror displays of the virtual device.
+     */
+    void wakeUp();
+
     /**
      * Closes the virtual device and frees all associated resources.
      */
-    @EnforcePermission("CREATE_VIRTUAL_DEVICE")
     void close();
 
     /**
      * Specifies a policy for this virtual device.
      */
-    @EnforcePermission("CREATE_VIRTUAL_DEVICE")
     void setDevicePolicy(int policyType, int devicePolicy);
 
     /**
      * Adds an exemption to the default activity launch policy.
      */
-    @EnforcePermission("CREATE_VIRTUAL_DEVICE")
     void addActivityPolicyExemption(in ActivityPolicyExemption exemption);
 
     /**
      * Removes an exemption to the default activity launch policy.
      */
-    @EnforcePermission("CREATE_VIRTUAL_DEVICE")
     void removeActivityPolicyExemption(in ActivityPolicyExemption exemption);
 
     /**
      * Specifies a policy for this virtual device on the given display.
      */
-    @EnforcePermission("CREATE_VIRTUAL_DEVICE")
     void setDevicePolicyForDisplay(int displayId, int policyType, int devicePolicy);
 
     /**
      * Notifies that an audio session being started.
      */
-    @EnforcePermission("CREATE_VIRTUAL_DEVICE")
     void onAudioSessionStarting(int displayId, IAudioRoutingCallback routingCallback,
             IAudioConfigChangedCallback configChangedCallback);
 
     /**
      * Notifies that an audio session has ended.
      */
-    @EnforcePermission("CREATE_VIRTUAL_DEVICE")
     void onAudioSessionEnded();
 
     /**
+     * Creates a virtual display and registers it with the display framework.
+     */
+    int createVirtualDisplay(in VirtualDisplayConfig virtualDisplayConfig,
+            in IVirtualDisplayCallback callback);
+
+    /**
      * Creates a new dpad and registers it with the input framework with the given token.
      */
-    @EnforcePermission("CREATE_VIRTUAL_DEVICE")
     void createVirtualDpad(in VirtualDpadConfig config, IBinder token);
 
     /**
      * Creates a new keyboard and registers it with the input framework with the given token.
      */
-    @EnforcePermission("CREATE_VIRTUAL_DEVICE")
     void createVirtualKeyboard(in VirtualKeyboardConfig config, IBinder token);
 
     /**
      * Creates a new mouse and registers it with the input framework with the given token.
      */
-    @EnforcePermission("CREATE_VIRTUAL_DEVICE")
     void createVirtualMouse(in VirtualMouseConfig config, IBinder token);
 
     /**
      * Creates a new touchscreen and registers it with the input framework with the given token.
      */
-    @EnforcePermission("CREATE_VIRTUAL_DEVICE")
     void createVirtualTouchscreen(in VirtualTouchscreenConfig config, IBinder token);
 
     /**
      * Creates a new navigation touchpad and registers it with the input framework with the given
      * token.
      */
-    @EnforcePermission("CREATE_VIRTUAL_DEVICE")
     void createVirtualNavigationTouchpad(in VirtualNavigationTouchpadConfig config, IBinder token);
 
     /**
      * Creates a new stylus and registers it with the input framework with the given token.
      */
-    @EnforcePermission("CREATE_VIRTUAL_DEVICE")
     void createVirtualStylus(in VirtualStylusConfig config, IBinder token);
 
     /**
      * Creates a new rotary encoder and registers it with the input framework with the given token.
      */
-    @EnforcePermission("CREATE_VIRTUAL_DEVICE")
     void createVirtualRotaryEncoder(in VirtualRotaryEncoderConfig config, IBinder token);
 
     /**
      * Removes the input device corresponding to the given token from the framework.
      */
-    @EnforcePermission("CREATE_VIRTUAL_DEVICE")
     void unregisterInputDevice(IBinder token);
 
     /**
@@ -194,67 +197,56 @@
     /**
      * Injects a key event to the virtual dpad corresponding to the given token.
      */
-    @EnforcePermission("CREATE_VIRTUAL_DEVICE")
     boolean sendDpadKeyEvent(IBinder token, in VirtualKeyEvent event);
 
     /**
      * Injects a key event to the virtual keyboard corresponding to the given token.
      */
-    @EnforcePermission("CREATE_VIRTUAL_DEVICE")
     boolean sendKeyEvent(IBinder token, in VirtualKeyEvent event);
 
     /**
      * Injects a button event to the virtual mouse corresponding to the given token.
      */
-    @EnforcePermission("CREATE_VIRTUAL_DEVICE")
     boolean sendButtonEvent(IBinder token, in VirtualMouseButtonEvent event);
 
     /**
      * Injects a relative event to the virtual mouse corresponding to the given token.
      */
-    @EnforcePermission("CREATE_VIRTUAL_DEVICE")
     boolean sendRelativeEvent(IBinder token, in VirtualMouseRelativeEvent event);
 
     /**
      * Injects a scroll event to the virtual mouse corresponding to the given token.
      */
-    @EnforcePermission("CREATE_VIRTUAL_DEVICE")
     boolean sendScrollEvent(IBinder token, in VirtualMouseScrollEvent event);
 
     /**
     * Injects a touch event to the virtual touch input device corresponding to the given token.
     */
-    @EnforcePermission("CREATE_VIRTUAL_DEVICE")
     boolean sendTouchEvent(IBinder token, in VirtualTouchEvent event);
 
     /**
      * Injects a motion event from the virtual stylus input device corresponding to the given token.
      */
-    @EnforcePermission("CREATE_VIRTUAL_DEVICE")
     boolean sendStylusMotionEvent(IBinder token, in VirtualStylusMotionEvent event);
 
     /**
      * Injects a button event from the virtual stylus input device corresponding to the given token.
      */
-    @EnforcePermission("CREATE_VIRTUAL_DEVICE")
     boolean sendStylusButtonEvent(IBinder token, in VirtualStylusButtonEvent event);
 
     /**
      * Injects a scroll event from the virtual rotary encoder corresponding to the given token.
      */
-    @EnforcePermission("CREATE_VIRTUAL_DEVICE")
     boolean sendRotaryEncoderScrollEvent(IBinder token, in VirtualRotaryEncoderScrollEvent event);
 
     /**
      * Returns all virtual sensors created for this device.
      */
-    @EnforcePermission("CREATE_VIRTUAL_DEVICE")
     List<VirtualSensor> getVirtualSensorList();
 
     /**
      * Sends an event to the virtual sensor corresponding to the given token.
      */
-    @EnforcePermission("CREATE_VIRTUAL_DEVICE")
     boolean sendSensorEvent(IBinder token, in VirtualSensorEvent event);
 
     /**
@@ -270,11 +262,9 @@
     PointF getCursorPosition(IBinder token);
 
     /** Sets whether to show or hide the cursor while this virtual device is active. */
-    @EnforcePermission("CREATE_VIRTUAL_DEVICE")
     void setShowPointerIcon(boolean showPointerIcon);
 
     /** Sets an IME policy for the given display. */
-    @EnforcePermission("CREATE_VIRTUAL_DEVICE")
     void setDisplayImePolicy(int displayId, int policy);
 
     /**
@@ -282,33 +272,28 @@
      * when matching the provided IntentFilter and calls the callback with the intercepted
      * intent.
      */
-    @EnforcePermission("CREATE_VIRTUAL_DEVICE")
     void registerIntentInterceptor(in IVirtualDeviceIntentInterceptor intentInterceptor,
             in IntentFilter filter);
 
     /**
      * Unregisters a previously registered intent interceptor.
      */
-    @EnforcePermission("CREATE_VIRTUAL_DEVICE")
     void unregisterIntentInterceptor(in IVirtualDeviceIntentInterceptor intentInterceptor);
 
     /**
      * Creates a new virtual camera and registers it with the virtual camera service.
      */
-    @EnforcePermission("CREATE_VIRTUAL_DEVICE")
     void registerVirtualCamera(in VirtualCameraConfig camera);
 
     /**
      * Destroys the virtual camera with given config and unregisters it from the virtual camera
      * service.
      */
-    @EnforcePermission("CREATE_VIRTUAL_DEVICE")
     void unregisterVirtualCamera(in VirtualCameraConfig camera);
 
     /**
      * Returns the id of the virtual camera with given config.
      */
-    @EnforcePermission("CREATE_VIRTUAL_DEVICE")
     String getVirtualCameraId(in VirtualCameraConfig camera);
 
     /**
@@ -318,7 +303,6 @@
      * This is needed for virtual devices that are created by the system, as the VirtualDeviceImpl
      * object is created before the returned VirtualDeviceInternal one.
      */
-    @EnforcePermission("CREATE_VIRTUAL_DEVICE")
     void setListeners(in IVirtualDeviceActivityListener activityListener,
             in IVirtualDeviceSoundEffectListener soundEffectListener);
 }
diff --git a/core/java/android/companion/virtual/IVirtualDeviceManager.aidl b/core/java/android/companion/virtual/IVirtualDeviceManager.aidl
index 83e18ec..c98238c 100644
--- a/core/java/android/companion/virtual/IVirtualDeviceManager.aidl
+++ b/core/java/android/companion/virtual/IVirtualDeviceManager.aidl
@@ -23,8 +23,6 @@
 import android.companion.virtual.VirtualDevice;
 import android.companion.virtual.VirtualDeviceParams;
 import android.content.AttributionSource;
-import android.hardware.display.IVirtualDisplayCallback;
-import android.hardware.display.VirtualDisplayConfig;
 
 /**
  * Interface for communication between VirtualDeviceManager and VirtualDeviceManagerService.
@@ -96,18 +94,6 @@
     int getDevicePolicy(int deviceId, int policyType);
 
     /**
-     * Creates a virtual display owned by a particular virtual device.
-     *
-     * @param virtualDisplayConfig The configuration used in creating the display
-     * @param callback A callback that receives display lifecycle events
-     * @param virtualDevice The device that will own this display
-     * @param packageName The package name of the calling app
-     */
-    int createVirtualDisplay(in VirtualDisplayConfig virtualDisplayConfig,
-            in IVirtualDisplayCallback callback, in IVirtualDevice virtualDevice,
-            String packageName);
-
-    /**
      * Returns device-specific session id for playback, or AUDIO_SESSION_ID_GENERATE
      * if there's none.
      */
diff --git a/core/java/android/companion/virtual/VirtualDeviceInternal.java b/core/java/android/companion/virtual/VirtualDeviceInternal.java
index de20a68..d63a443 100644
--- a/core/java/android/companion/virtual/VirtualDeviceInternal.java
+++ b/core/java/android/companion/virtual/VirtualDeviceInternal.java
@@ -26,7 +26,6 @@
 import android.annotation.CallbackExecutor;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.annotation.RequiresPermission;
 import android.annotation.UserIdInt;
 import android.app.PendingIntent;
 import android.companion.virtual.audio.VirtualAudioDevice;
@@ -251,6 +250,22 @@
         }
     }
 
+    void goToSleep() {
+        try {
+            mVirtualDevice.goToSleep();
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    void wakeUp() {
+        try {
+            mVirtualDevice.wakeUp();
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
     void launchPendingIntent(
             int displayId,
             @NonNull PendingIntent pendingIntent,
@@ -281,14 +296,12 @@
                 new DisplayManagerGlobal.VirtualDisplayCallback(callback, executor);
         final int displayId;
         try {
-            displayId = mService.createVirtualDisplay(config, callbackWrapper, mVirtualDevice,
-                    mContext.getPackageName());
+            displayId = mVirtualDevice.createVirtualDisplay(config, callbackWrapper);
         } catch (RemoteException ex) {
             throw ex.rethrowFromSystemServer();
         }
         DisplayManagerGlobal displayManager = DisplayManagerGlobal.getInstance();
-        return displayManager.createVirtualDisplayWrapper(config, callbackWrapper,
-                displayId);
+        return displayManager.createVirtualDisplayWrapper(config, callbackWrapper, displayId);
     }
 
     void close() {
@@ -407,7 +420,6 @@
         }
     }
 
-    @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
     @NonNull
     VirtualStylus createVirtualStylus(@NonNull VirtualStylusConfig config) {
         try {
@@ -420,7 +432,6 @@
         }
     }
 
-    @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
     @NonNull
     VirtualRotaryEncoder createVirtualRotaryEncoder(@NonNull VirtualRotaryEncoderConfig config) {
         try {
@@ -471,7 +482,6 @@
         return mVirtualAudioDevice;
     }
 
-    @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
     @NonNull
     VirtualCamera createVirtualCamera(@NonNull VirtualCameraConfig config) {
         try {
diff --git a/core/java/android/companion/virtual/VirtualDeviceManager.java b/core/java/android/companion/virtual/VirtualDeviceManager.java
index 473ab27..6ea7834 100644
--- a/core/java/android/companion/virtual/VirtualDeviceManager.java
+++ b/core/java/android/companion/virtual/VirtualDeviceManager.java
@@ -620,6 +620,43 @@
         }
 
         /**
+         * Forces all trusted non-mirror displays of the virtual device to turn off.
+         *
+         * <p>After this action, if all displays across all devices, including the default one, are
+         * off, then the physical device will be put to sleep. If the displays of this virtual
+         * device are already off, then nothing will happen.</p>
+         *
+         * <p>Overrides all the wake locks that are held. This is equivalent to pressing a "virtual
+         * power key" to turn off the screen.</p>
+         *
+         * @see #wakeUp()
+         * @see DisplayManager#VIRTUAL_DISPLAY_FLAG_TRUSTED
+         * @see DisplayManager#VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY
+         */
+        @FlaggedApi(android.companion.virtualdevice.flags.Flags.FLAG_DEVICE_AWARE_DISPLAY_POWER)
+        public void goToSleep() {
+            mVirtualDeviceInternal.goToSleep();
+        }
+
+        /**
+         * Forces all trusted non-mirror displays of the virtual device to turn on.
+         *
+         * <p>If the displays of this virtual device are turned off, then they will be turned on.
+         * Additionally, if the device is asleep it will be awoken. If the displays of this virtual
+         * device are already on, then nothing will happen.</p>
+         *
+         * <p>This is equivalent to pressing a "virtual power key" to turn on the screen.</p>
+         *
+         * @see #goToSleep()
+         * @see DisplayManager#VIRTUAL_DISPLAY_FLAG_TRUSTED
+         * @see DisplayManager#VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY
+         */
+        @FlaggedApi(android.companion.virtualdevice.flags.Flags.FLAG_DEVICE_AWARE_DISPLAY_POWER)
+        public void wakeUp() {
+            mVirtualDeviceInternal.wakeUp();
+        }
+
+        /**
          * Launches a given pending intent on the give display ID.
          *
          * @param displayId The display to launch the pending intent on. This display must be
@@ -727,7 +764,6 @@
          * Closes the virtual device, stopping and tearing down any virtual displays, associated
          * virtual audio device, and event injection that's currently in progress.
          */
-        @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
         public void close() {
             mVirtualDeviceInternal.close();
         }
@@ -746,7 +782,6 @@
          * @see VirtualDeviceParams#POLICY_TYPE_ACTIVITY
          */
         @FlaggedApi(Flags.FLAG_DYNAMIC_POLICY)
-        @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
         public void setDevicePolicy(@VirtualDeviceParams.DynamicPolicyType int policyType,
                 @VirtualDeviceParams.DevicePolicy int devicePolicy) {
             mVirtualDeviceInternal.setDevicePolicy(policyType, devicePolicy);
@@ -769,7 +804,6 @@
          * @see #setDevicePolicy
          */
         @FlaggedApi(Flags.FLAG_DYNAMIC_POLICY)
-        @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
         public void addActivityPolicyExemption(@NonNull ComponentName componentName) {
             addActivityPolicyExemption(new ActivityPolicyExemption.Builder()
                     .setComponentName(componentName)
@@ -793,7 +827,6 @@
          * @see #setDevicePolicy
          */
         @FlaggedApi(Flags.FLAG_DYNAMIC_POLICY)
-        @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
         public void removeActivityPolicyExemption(@NonNull ComponentName componentName) {
             removeActivityPolicyExemption(new ActivityPolicyExemption.Builder()
                     .setComponentName(componentName)
@@ -818,7 +851,6 @@
          * @see #setDevicePolicy
          */
         @FlaggedApi(android.companion.virtualdevice.flags.Flags.FLAG_ACTIVITY_CONTROL_API)
-        @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
         public void addActivityPolicyExemption(@NonNull ActivityPolicyExemption exemption) {
             mVirtualDeviceInternal.addActivityPolicyExemption(Objects.requireNonNull(exemption));
         }
@@ -834,7 +866,6 @@
          * @see #setDevicePolicy
          */
         @FlaggedApi(android.companion.virtualdevice.flags.Flags.FLAG_ACTIVITY_CONTROL_API)
-        @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
         public void removeActivityPolicyExemption(@NonNull ActivityPolicyExemption exemption) {
             mVirtualDeviceInternal.removeActivityPolicyExemption(Objects.requireNonNull(exemption));
         }
@@ -857,7 +888,6 @@
          * @see VirtualDeviceParams#POLICY_TYPE_ACTIVITY
          */
         @FlaggedApi(android.companion.virtualdevice.flags.Flags.FLAG_ACTIVITY_CONTROL_API)
-        @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
         public void setDevicePolicy(
                 @VirtualDeviceParams.DynamicDisplayPolicyType int policyType,
                 @VirtualDeviceParams.DevicePolicy int devicePolicy,
@@ -870,7 +900,6 @@
          *
          * @param config the configurations of the virtual dpad.
          */
-        @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
         @NonNull
         public VirtualDpad createVirtualDpad(@NonNull VirtualDpadConfig config) {
             Objects.requireNonNull(config, "config must not be null");
@@ -882,7 +911,6 @@
          *
          * @param config the configurations of the virtual keyboard.
          */
-        @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
         @NonNull
         public VirtualKeyboard createVirtualKeyboard(@NonNull VirtualKeyboardConfig config) {
             Objects.requireNonNull(config, "config must not be null");
@@ -900,7 +928,6 @@
          * @deprecated Use {@link #createVirtualKeyboard(VirtualKeyboardConfig config)} instead
          */
         @Deprecated
-        @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
         @NonNull
         public VirtualKeyboard createVirtualKeyboard(@NonNull VirtualDisplay display,
                 @NonNull String inputDeviceName, int vendorId, int productId) {
@@ -919,7 +946,6 @@
          *
          * @param config the configurations of the virtual mouse.
          */
-        @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
         @NonNull
         public VirtualMouse createVirtualMouse(@NonNull VirtualMouseConfig config) {
             Objects.requireNonNull(config, "config must not be null");
@@ -937,7 +963,6 @@
          * @deprecated Use {@link #createVirtualMouse(VirtualMouseConfig config)} instead
          */
         @Deprecated
-        @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
         @NonNull
         public VirtualMouse createVirtualMouse(@NonNull VirtualDisplay display,
                 @NonNull String inputDeviceName, int vendorId, int productId) {
@@ -956,7 +981,6 @@
          *
          * @param config the configurations of the virtual touchscreen.
          */
-        @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
         @NonNull
         public VirtualTouchscreen createVirtualTouchscreen(
                 @NonNull VirtualTouchscreenConfig config) {
@@ -976,7 +1000,6 @@
          * instead
          */
         @Deprecated
-        @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
         @NonNull
         public VirtualTouchscreen createVirtualTouchscreen(@NonNull VirtualDisplay display,
                 @NonNull String inputDeviceName, int vendorId, int productId) {
@@ -1003,7 +1026,6 @@
          * @param config the configurations of the virtual navigation touchpad.
          * @see android.view.InputDevice#SOURCE_TOUCH_NAVIGATION
          */
-        @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
         @NonNull
         public VirtualNavigationTouchpad createVirtualNavigationTouchpad(
                 @NonNull VirtualNavigationTouchpadConfig config) {
@@ -1015,7 +1037,6 @@
          *
          * @param config the touchscreen configurations for the virtual stylus.
          */
-        @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
         @NonNull
         @FlaggedApi(Flags.FLAG_VIRTUAL_STYLUS)
         public VirtualStylus createVirtualStylus(
@@ -1029,7 +1050,6 @@
          * @param config the configuration for the virtual rotary encoder.
          * @see android.view.InputDevice#SOURCE_ROTARY_ENCODER
          */
-        @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
         @NonNull
         @FlaggedApi(android.companion.virtualdevice.flags.Flags.FLAG_VIRTUAL_ROTARY)
         public VirtualRotaryEncoder createVirtualRotaryEncoder(
@@ -1057,7 +1077,6 @@
          *   applications running on virtual display is changed.
          * @return A {@link VirtualAudioDevice} instance.
          */
-        @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
         @NonNull
         public VirtualAudioDevice createVirtualAudioDevice(
                 @NonNull VirtualDisplay display,
@@ -1078,7 +1097,6 @@
          * @throws UnsupportedOperationException if virtual camera isn't supported on this device.
          * @see VirtualDeviceParams#POLICY_TYPE_CAMERA
          */
-        @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
         @NonNull
         @FlaggedApi(Flags.FLAG_VIRTUAL_CAMERA)
         public VirtualCamera createVirtualCamera(@NonNull VirtualCameraConfig config) {
@@ -1092,10 +1110,12 @@
         /**
          * Sets the visibility of the pointer icon for this VirtualDevice's associated displays.
          *
+         * <p>Only applicable to trusted displays.</p>
+         *
          * @param showPointerIcon True if the pointer should be shown; false otherwise. The default
          *   visibility is true.
+         * @see DisplayManager#VIRTUAL_DISPLAY_FLAG_TRUSTED
          */
-        @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
         public void setShowPointerIcon(boolean showPointerIcon) {
             mVirtualDeviceInternal.setShowPointerIcon(showPointerIcon);
         }
@@ -1110,7 +1130,6 @@
          * @throws SecurityException if the display is not owned by this device or is not
          *                           {@link DisplayManager#VIRTUAL_DISPLAY_FLAG_TRUSTED trusted}
          */
-        @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
         @FlaggedApi(Flags.FLAG_VDM_CUSTOM_IME)
         public void setDisplayImePolicy(int displayId, @WindowManager.DisplayImePolicy int policy) {
             if (Flags.vdmCustomIme()) {
@@ -1174,7 +1193,6 @@
          * is intercepted.
          * @see #unregisterIntentInterceptor(IntentInterceptorCallback)
          */
-        @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
         public void registerIntentInterceptor(
                 @NonNull IntentFilter interceptorFilter,
                 @CallbackExecutor @NonNull Executor executor,
@@ -1187,7 +1205,6 @@
          * Unregisters the intent interceptor previously registered with
          * {@link #registerIntentInterceptor}.
          */
-        @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
         public void unregisterIntentInterceptor(
                     @NonNull IntentInterceptorCallback interceptorCallback) {
             mVirtualDeviceInternal.unregisterIntentInterceptor(interceptorCallback);
diff --git a/core/java/android/companion/virtual/VirtualDeviceParams.java b/core/java/android/companion/virtual/VirtualDeviceParams.java
index 03b72bd..65f9cbe 100644
--- a/core/java/android/companion/virtual/VirtualDeviceParams.java
+++ b/core/java/android/companion/virtual/VirtualDeviceParams.java
@@ -159,7 +159,7 @@
      * @hide
      */
     @IntDef(prefix = "POLICY_TYPE_", value = {POLICY_TYPE_SENSORS, POLICY_TYPE_AUDIO,
-            POLICY_TYPE_RECENTS, POLICY_TYPE_ACTIVITY, POLICY_TYPE_CAMERA,
+            POLICY_TYPE_RECENTS, POLICY_TYPE_ACTIVITY, POLICY_TYPE_CLIPBOARD, POLICY_TYPE_CAMERA,
             POLICY_TYPE_BLOCKED_ACTIVITY})
     @Retention(RetentionPolicy.SOURCE)
     @Target({ElementType.TYPE_PARAMETER, ElementType.TYPE_USE})
@@ -220,11 +220,16 @@
      * Tells the activity manager how to handle recents entries for activities run on this device.
      *
      * <ul>
-     *     <li>{@link #DEVICE_POLICY_DEFAULT}: Activities launched on VirtualDisplays owned by this
+     *     <li>{@link #DEVICE_POLICY_DEFAULT}: Activities launched on trusted displays owned by this
      *     device will appear in the host device recents.
-     *     <li>{@link #DEVICE_POLICY_CUSTOM}: Activities launched on VirtualDisplays owned by this
+     *     <li>{@link #DEVICE_POLICY_CUSTOM}: Activities launched on trusted displays owned by this
      *     device will not appear in recents.
      * </ul>
+     *
+     * <p>Activities launched on untrusted displays will always show in the host device recents,
+     * regardless of the policy.</p>
+     *
+     * @see android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_TRUSTED
      */
     public static final int POLICY_TYPE_RECENTS = 2;
 
@@ -254,8 +259,10 @@
      *     not shared with other devices' clipboards, including the clipboard of the default device.
      *     <li>{@link #DEVICE_POLICY_CUSTOM}: The device's clipboard is shared with the default
      *     device's clipboard. Any clipboard operation on the virtual device is as if it was done on
-     *     the default device.
+     *     the default device. Requires all displays of the virtual device to be trusted.
      * </ul>
+     *
+     * @see android.hardware.display.DisplayManager#VIRTUAL_DISPLAY_FLAG_TRUSTED
      */
     @FlaggedApi(Flags.FLAG_CROSS_DEVICE_CLIPBOARD)
     public static final int POLICY_TYPE_CLIPBOARD = 4;
@@ -821,8 +828,8 @@
         }
 
         /**
-         * Specifies a component to be used as input method on all displays owned by this virtual
-         * device.
+         * Specifies a component to be used as input method on all trusted displays owned by this
+         * virtual device.
          *
          * @param inputMethodComponent The component name to be used as input method. Must comply to
          *   all general input method requirements described in the guide to
@@ -831,6 +838,7 @@
          *   may interact with the virtual device, then there will effectively be no IME on this
          *   device's displays for that user.
          *
+         * @see android.hardware.display.DisplayManager#VIRTUAL_DISPLAY_FLAG_TRUSTED
          * @see android.inputmethodservice.InputMethodService
          * @attr ref android.R.styleable#InputMethod_isVirtualDeviceOnly
          * @attr ref android.R.styleable#InputMethod_showInInputMethodPicker
diff --git a/core/java/android/companion/virtual/camera/VirtualCamera.java b/core/java/android/companion/virtual/camera/VirtualCamera.java
index f727589..ece048d 100644
--- a/core/java/android/companion/virtual/camera/VirtualCamera.java
+++ b/core/java/android/companion/virtual/camera/VirtualCamera.java
@@ -17,7 +17,6 @@
 package android.companion.virtual.camera;
 
 import android.annotation.FlaggedApi;
-import android.annotation.RequiresPermission;
 import android.annotation.SuppressLint;
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
@@ -94,7 +93,6 @@
     }
 
     @Override
-    @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
     public void close() {
         try {
             mVirtualDevice.unregisterVirtualCamera(mConfig);
diff --git a/core/java/android/companion/virtual/sensor/VirtualSensor.java b/core/java/android/companion/virtual/sensor/VirtualSensor.java
index 37e494b..934a1a8 100644
--- a/core/java/android/companion/virtual/sensor/VirtualSensor.java
+++ b/core/java/android/companion/virtual/sensor/VirtualSensor.java
@@ -17,7 +17,6 @@
 package android.companion.virtual.sensor;
 
 import android.annotation.NonNull;
-import android.annotation.RequiresPermission;
 import android.annotation.SuppressLint;
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
@@ -136,7 +135,6 @@
     /**
      * Send a sensor event to the system.
      */
-    @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
     public void sendEvent(@NonNull VirtualSensorEvent event) {
         try {
             mVirtualDevice.sendSensorEvent(mToken, event);
diff --git a/core/java/android/content/ClipData.java b/core/java/android/content/ClipData.java
index b421339..ff0bb25 100644
--- a/core/java/android/content/ClipData.java
+++ b/core/java/android/content/ClipData.java
@@ -1149,7 +1149,7 @@
         for (int i = 0; i < size; i++) {
             final Item item = mItems.get(i);
             if (item.mIntent != null) {
-                item.mIntent.prepareToLeaveProcess(leavingPackage);
+                item.mIntent.prepareToLeaveProcess(leavingPackage, false);
             }
             if (item.mUri != null && leavingPackage) {
                 if (StrictMode.vmFileUriExposureEnabled()) {
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 9a93ec4..0bb0027 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -12221,6 +12221,8 @@
 
     /**
      * Collects keys in the extra bundle whose value are intents.
+     * With these keys collected on the client side, the system server would only unparcel values
+     * of these keys and create IntentCreatorToken for them.
      * @hide
      */
     public void collectExtraIntentKeys() {
@@ -12583,22 +12585,29 @@
      */
     @android.ravenwood.annotation.RavenwoodThrow
     public void prepareToLeaveProcess(boolean leavingPackage) {
+        prepareToLeaveProcess(leavingPackage, true);
+    }
+
+    /**
+     * @hide
+     */
+    void prepareToLeaveProcess(boolean leavingPackage, boolean isTopLevel) {
         setAllowFds(false);
 
         if (mSelector != null) {
-            mSelector.prepareToLeaveProcess(leavingPackage);
+            mSelector.prepareToLeaveProcess(leavingPackage, false);
         }
         if (mClipData != null) {
             mClipData.prepareToLeaveProcess(leavingPackage, getFlags());
         }
         if (mOriginalIntent != null) {
-            mOriginalIntent.prepareToLeaveProcess(leavingPackage);
+            mOriginalIntent.prepareToLeaveProcess(leavingPackage, false);
         }
 
         if (mExtras != null && !mExtras.isParcelled()) {
             final Object intent = mExtras.get(Intent.EXTRA_INTENT);
             if (intent instanceof Intent) {
-                ((Intent) intent).prepareToLeaveProcess(leavingPackage);
+                ((Intent) intent).prepareToLeaveProcess(leavingPackage, false);
             }
         }
 
@@ -12672,6 +12681,10 @@
                 StrictMode.onUnsafeIntentLaunch(this);
             }
         }
+
+        if (isTopLevel) {
+            collectExtraIntentKeys();
+        }
     }
 
     /**
diff --git a/core/java/android/content/IntentSender.java b/core/java/android/content/IntentSender.java
index ca6d86a..f406927 100644
--- a/core/java/android/content/IntentSender.java
+++ b/core/java/android/content/IntentSender.java
@@ -288,6 +288,9 @@
             @Nullable Executor executor, @Nullable OnFinished onFinished)
             throws SendIntentException {
         try {
+            if (intent != null) {
+                intent.collectExtraIntentKeys();
+            }
             String resolvedType = intent != null ?
                     intent.resolveTypeIfNeeded(context.getContentResolver())
                     : null;
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index 34bea1a..cccfdb0 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -2334,9 +2334,8 @@
      * Whether an app allows its playback audio to be captured by other apps.
      *
      * @return {@code true} if the app indicates that its audio can be captured by other apps.
-     *
-     * @hide
      */
+    @FlaggedApi(Flags.FLAG_AUDIO_PLAYBACK_CAPTURE_ALLOWANCE)
     public boolean isAudioPlaybackCaptureAllowed() {
         return (privateFlags & PRIVATE_FLAG_ALLOW_AUDIO_PLAYBACK_CAPTURE) != 0;
     }
diff --git a/core/java/android/content/pm/SharedLibraryInfo.java b/core/java/android/content/pm/SharedLibraryInfo.java
index d77b2f5..f7191e6 100644
--- a/core/java/android/content/pm/SharedLibraryInfo.java
+++ b/core/java/android/content/pm/SharedLibraryInfo.java
@@ -209,6 +209,24 @@
     }
 
     /**
+     * @hide
+     * @param name
+     * @param versionMajor
+     */
+    public SharedLibraryInfo(String name, long versionMajor, int type) {
+        mPath = null;
+        mPackageName = null;
+        mName = name;
+        mVersion = versionMajor;
+        mType = type;
+        mDeclaringPackage = null;
+        mDependentPackages = null;
+        mDependencies = null;
+        mIsNative = false;
+        mOptionalDependentPackages = null;
+    }
+
+    /**
      * Gets the type of this library.
      *
      * @return The library type.
diff --git a/core/java/android/content/pm/flags.aconfig b/core/java/android/content/pm/flags.aconfig
index 300740e..c7d7dc1 100644
--- a/core/java/android/content/pm/flags.aconfig
+++ b/core/java/android/content/pm/flags.aconfig
@@ -288,6 +288,15 @@
 }
 
 flag {
+    name: "audio_playback_capture_allowance"
+    is_exported: true
+    namespace: "package_manager_service"
+    description: "Feature flag to enable the feature to retrieve info about audio playback capture allowance at manifest level."
+    bug: "362425551"
+    is_fixed_read_only: true
+}
+
+flag {
     name: "get_packages_from_launcher_apps"
     namespace: "package_manager_service"
     description: "Feature flag to provide the new methods within launcher apps class to get packages."
diff --git a/core/java/android/content/pm/multiuser.aconfig b/core/java/android/content/pm/multiuser.aconfig
index cf65539..7de7131 100644
--- a/core/java/android/content/pm/multiuser.aconfig
+++ b/core/java/android/content/pm/multiuser.aconfig
@@ -47,13 +47,6 @@
 }
 
 flag {
-    name: "start_user_before_scheduled_alarms"
-    namespace: "multiuser"
-    description: "Persist list of users with alarms scheduled and wakeup stopped users before alarms are due"
-    bug: "314907186"
-}
-
-flag {
     name: "add_ui_for_sounds_from_background_users"
     namespace: "multiuser"
     description: "Allow foreground user to dismiss sounds that are coming from background users"
@@ -75,6 +68,16 @@
 }
 
 flag {
+    name: "multiple_alarm_notifications_support"
+    namespace: "multiuser"
+    description: "Implement handling of multiple simultaneous alarms/timers on bg users"
+    bug: "367615180"
+    metadata {
+        purpose: PURPOSE_BUGFIX
+  }
+}
+
+flag {
     name: "enable_biometrics_to_unlock_private_space"
     is_exported: true
     namespace: "profile_experiences"
@@ -198,16 +201,6 @@
 }
 
 flag {
-    name: "cache_profile_parent"
-    namespace: "multiuser"
-    description: "Cache getProfileParent to avoid unnecessary binder calls"
-    bug: "350417399"
-    metadata {
-        purpose: PURPOSE_BUGFIX
-  }
-}
-
-flag {
     name: "fix_disabling_of_mu_toggle_when_restriction_applied"
     namespace: "multiuser"
     description: "When no_user_switch is set but no EnforcedAdmin is present, the toggle has to be disabled"
@@ -218,6 +211,50 @@
 }
 
 flag {
+    name: "cache_profile_parent_read_only"
+    namespace: "multiuser"
+    description: "Cache getProfileParent to avoid unnecessary binder calls"
+    bug: "350417399"
+    metadata {
+        purpose: PURPOSE_BUGFIX
+  }
+  is_fixed_read_only: true
+}
+
+flag {
+    name: "cache_profile_ids_read_only"
+    namespace: "multiuser"
+    description: "Cache getProfileIds to avoid unnecessary binder calls"
+    bug: "350421409"
+    metadata {
+        purpose: PURPOSE_BUGFIX
+  }
+  is_fixed_read_only: true
+}
+
+flag {
+    name: "cache_profile_type_read_only"
+    namespace: "multiuser"
+    description: "Cache getProfileType to avoid unnecessary binder calls"
+    bug: "350417403"
+    metadata {
+        purpose: PURPOSE_BUGFIX
+  }
+  is_fixed_read_only: true
+}
+
+flag {
+    name: "cache_profiles_read_only"
+    namespace: "multiuser"
+    description: "Cache getProfiles to avoid unnecessary binder calls"
+    bug: "350419395"
+    metadata {
+        purpose: PURPOSE_BUGFIX
+  }
+  is_fixed_read_only: true
+}
+
+flag {
     name: "cache_quiet_mode_state"
     namespace: "multiuser"
     description: "Optimise quiet mode state retrieval"
@@ -260,6 +297,17 @@
 }
 
 flag {
+    name: "invalidate_cache_on_users_changed_read_only"
+    namespace: "multiuser"
+    description: "Invalidate the cache when users are added or removed to improve caches."
+    bug: "372383485"
+    metadata {
+        purpose: PURPOSE_BUGFIX
+  }
+  is_fixed_read_only: true
+}
+
+flag {
     name: "caches_not_invalidated_at_start_read_only"
     namespace: "multiuser"
     description: "PIC need to be invalidated at start in order to work properly."
diff --git a/core/java/android/content/pm/parsing/ApkLite.java b/core/java/android/content/pm/parsing/ApkLite.java
index 74ce62c..19a13db 100644
--- a/core/java/android/content/pm/parsing/ApkLite.java
+++ b/core/java/android/content/pm/parsing/ApkLite.java
@@ -21,6 +21,7 @@
 import android.content.pm.ArchivedPackageParcel;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
+import android.content.pm.SharedLibraryInfo;
 import android.content.pm.SigningDetails;
 import android.content.pm.VerifierInfo;
 
@@ -149,6 +150,8 @@
      */
     private final @Nullable String mEmergencyInstaller;
 
+    private final @NonNull List<SharedLibraryInfo> mDeclaredLibraries;
+
     /**
      * Archival install info.
      */
@@ -165,7 +168,7 @@
             int minSdkVersion, int targetSdkVersion, int rollbackDataPolicy,
             Set<String> requiredSplitTypes, Set<String> splitTypes,
             boolean hasDeviceAdminReceiver, boolean isSdkLibrary, boolean updatableSystem,
-            String emergencyInstaller) {
+            String emergencyInstaller, List<SharedLibraryInfo> declaredLibraries) {
         mPath = path;
         mPackageName = packageName;
         mSplitName = splitName;
@@ -202,6 +205,7 @@
         mUpdatableSystem = updatableSystem;
         mEmergencyInstaller = emergencyInstaller;
         mArchivedPackage = null;
+        mDeclaredLibraries = declaredLibraries;
     }
 
     public ApkLite(String path, ArchivedPackageParcel archivedPackage) {
@@ -241,6 +245,7 @@
         mUpdatableSystem = true;
         mEmergencyInstaller = null;
         mArchivedPackage = archivedPackage;
+        mDeclaredLibraries = null;
     }
 
     /**
@@ -565,6 +570,11 @@
         return mEmergencyInstaller;
     }
 
+    @DataClass.Generated.Member
+    public @NonNull List<SharedLibraryInfo> getDeclaredLibraries() {
+        return mDeclaredLibraries;
+    }
+
     /**
      * Archival install info.
      */
@@ -574,10 +584,10 @@
     }
 
     @DataClass.Generated(
-            time = 1706896661616L,
+            time = 1728333566322L,
             codegenVersion = "1.0.23",
             sourceFile = "frameworks/base/core/java/android/content/pm/parsing/ApkLite.java",
-            inputSignatures = "private final @android.annotation.NonNull java.lang.String mPackageName\nprivate final @android.annotation.NonNull java.lang.String mPath\nprivate final @android.annotation.Nullable java.lang.String mSplitName\nprivate final @android.annotation.Nullable java.lang.String mUsesSplitName\nprivate final @android.annotation.Nullable java.lang.String mConfigForSplit\nprivate final @android.annotation.Nullable java.util.Set<java.lang.String> mRequiredSplitTypes\nprivate final @android.annotation.Nullable java.util.Set<java.lang.String> mSplitTypes\nprivate final  int mVersionCodeMajor\nprivate final  int mVersionCode\nprivate final  int mRevisionCode\nprivate final  int mInstallLocation\nprivate final  int mMinSdkVersion\nprivate final  int mTargetSdkVersion\nprivate final @android.annotation.NonNull android.content.pm.VerifierInfo[] mVerifiers\nprivate final @android.annotation.NonNull android.content.pm.SigningDetails mSigningDetails\nprivate final  boolean mFeatureSplit\nprivate final  boolean mIsolatedSplits\nprivate final  boolean mSplitRequired\nprivate final  boolean mCoreApp\nprivate final  boolean mDebuggable\nprivate final  boolean mProfileableByShell\nprivate final  boolean mMultiArch\nprivate final  boolean mUse32bitAbi\nprivate final  boolean mExtractNativeLibs\nprivate final  boolean mUseEmbeddedDex\nprivate final @android.annotation.Nullable java.lang.String mTargetPackageName\nprivate final  boolean mOverlayIsStatic\nprivate final  int mOverlayPriority\nprivate final @android.annotation.Nullable java.lang.String mRequiredSystemPropertyName\nprivate final @android.annotation.Nullable java.lang.String mRequiredSystemPropertyValue\nprivate final  int mRollbackDataPolicy\nprivate final  boolean mHasDeviceAdminReceiver\nprivate final  boolean mIsSdkLibrary\nprivate final  boolean mUpdatableSystem\nprivate final @android.annotation.Nullable java.lang.String mEmergencyInstaller\nprivate final @android.annotation.Nullable android.content.pm.ArchivedPackageParcel mArchivedPackage\npublic  long getLongVersionCode()\nprivate  boolean hasAnyRequiredSplitTypes()\nclass ApkLite extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genConstructor=false, genConstDefs=false)")
+            inputSignatures = "private final @android.annotation.NonNull java.lang.String mPackageName\nprivate final @android.annotation.NonNull java.lang.String mPath\nprivate final @android.annotation.Nullable java.lang.String mSplitName\nprivate final @android.annotation.Nullable java.lang.String mUsesSplitName\nprivate final @android.annotation.Nullable java.lang.String mConfigForSplit\nprivate final @android.annotation.Nullable java.util.Set<java.lang.String> mRequiredSplitTypes\nprivate final @android.annotation.Nullable java.util.Set<java.lang.String> mSplitTypes\nprivate final  int mVersionCodeMajor\nprivate final  int mVersionCode\nprivate final  int mRevisionCode\nprivate final  int mInstallLocation\nprivate final  int mMinSdkVersion\nprivate final  int mTargetSdkVersion\nprivate final @android.annotation.NonNull android.content.pm.VerifierInfo[] mVerifiers\nprivate final @android.annotation.NonNull android.content.pm.SigningDetails mSigningDetails\nprivate final  boolean mFeatureSplit\nprivate final  boolean mIsolatedSplits\nprivate final  boolean mSplitRequired\nprivate final  boolean mCoreApp\nprivate final  boolean mDebuggable\nprivate final  boolean mProfileableByShell\nprivate final  boolean mMultiArch\nprivate final  boolean mUse32bitAbi\nprivate final  boolean mExtractNativeLibs\nprivate final  boolean mUseEmbeddedDex\nprivate final @android.annotation.Nullable java.lang.String mTargetPackageName\nprivate final  boolean mOverlayIsStatic\nprivate final  int mOverlayPriority\nprivate final @android.annotation.Nullable java.lang.String mRequiredSystemPropertyName\nprivate final @android.annotation.Nullable java.lang.String mRequiredSystemPropertyValue\nprivate final  int mRollbackDataPolicy\nprivate final  boolean mHasDeviceAdminReceiver\nprivate final  boolean mIsSdkLibrary\nprivate final  boolean mUpdatableSystem\nprivate final @android.annotation.Nullable java.lang.String mEmergencyInstaller\nprivate final @android.annotation.NonNull java.util.List<android.content.pm.SharedLibraryInfo> mDeclaredLibraries\nprivate final @android.annotation.Nullable android.content.pm.ArchivedPackageParcel mArchivedPackage\npublic  long getLongVersionCode()\nprivate  boolean hasAnyRequiredSplitTypes()\nclass ApkLite extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genConstructor=false, genConstDefs=false)")
     @Deprecated
     private void __metadata() {}
 
diff --git a/core/java/android/content/pm/parsing/ApkLiteParseUtils.java b/core/java/android/content/pm/parsing/ApkLiteParseUtils.java
index ffb69c0..1a7f628 100644
--- a/core/java/android/content/pm/parsing/ApkLiteParseUtils.java
+++ b/core/java/android/content/pm/parsing/ApkLiteParseUtils.java
@@ -24,6 +24,7 @@
 import android.app.admin.DeviceAdminReceiver;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
+import android.content.pm.SharedLibraryInfo;
 import android.content.pm.SigningDetails;
 import android.content.pm.VerifierInfo;
 import android.content.pm.parsing.result.ParseInput;
@@ -92,6 +93,8 @@
     private static final String[] SDK_CODENAMES = Build.VERSION.ACTIVE_CODENAMES;
     private static final String TAG_PROCESSES = "processes";
     private static final String TAG_PROCESS = "process";
+    private static final String TAG_STATIC_LIBRARY = "static-library";
+    private static final String TAG_LIBRARY = "library";
 
     /**
      * Parse only lightweight details about the package at the given location.
@@ -457,6 +460,7 @@
         boolean hasDeviceAdminReceiver = false;
 
         boolean isSdkLibrary = false;
+        List<SharedLibraryInfo> declaredLibraries = new ArrayList<>();
 
         // Only search the tree when the tag is the direct child of <manifest> tag
         int type;
@@ -521,6 +525,51 @@
                             break;
                         case TAG_SDK_LIBRARY:
                             isSdkLibrary = true;
+                            // Mirrors ParsingPackageUtils#parseSdkLibrary until lite and full
+                            // parsing are combined
+                            String sdkLibName = parser.getAttributeValue(
+                                    ANDROID_RES_NAMESPACE, "name");
+                            int sdkLibVersionMajor = parser.getAttributeIntValue(
+                                        ANDROID_RES_NAMESPACE, "versionMajor", -1);
+                            if (sdkLibName == null || sdkLibVersionMajor < 0) {
+                                return input.error(
+                                        PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+                                        "Bad uses-sdk-library declaration name: " + sdkLibName
+                                                + " version: " + sdkLibVersionMajor);
+                            }
+                            declaredLibraries.add(new SharedLibraryInfo(
+                                    sdkLibName, sdkLibVersionMajor,
+                                    SharedLibraryInfo.TYPE_SDK_PACKAGE));
+                            break;
+                        case TAG_STATIC_LIBRARY:
+                            // Mirrors ParsingPackageUtils#parseStaticLibrary until lite and full
+                            // parsing are combined
+                            String staticLibName = parser.getAttributeValue(
+                                    ANDROID_RES_NAMESPACE, "name");
+                            int staticLibVersion = parser.getAttributeIntValue(
+                                    ANDROID_RES_NAMESPACE, "version", -1);
+                            int staticLibVersionMajor = parser.getAttributeIntValue(
+                                    ANDROID_RES_NAMESPACE, "versionMajor", 0);
+                            if (staticLibName == null || staticLibVersion < 0) {
+                                return input.error("Bad static-library declaration name: "
+                                        + staticLibName + " version: " + staticLibVersion);
+                            }
+                            declaredLibraries.add(new SharedLibraryInfo(staticLibName,
+                                    PackageInfo.composeLongVersionCode(staticLibVersionMajor,
+                                            staticLibVersion), SharedLibraryInfo.TYPE_STATIC));
+                            break;
+                        case TAG_LIBRARY:
+                            // Mirrors ParsingPackageUtils#parseLibrary until lite and full parsing
+                            // are combined
+                            String libName = parser.getAttributeValue(
+                                    ANDROID_RES_NAMESPACE, "name");
+                            if (libName == null) {
+                                return input.error("Bad library declaration name: null");
+                            }
+                            libName = libName.intern();
+                            declaredLibraries.add(new SharedLibraryInfo(libName,
+                                    SharedLibraryInfo.VERSION_UNDEFINED,
+                                    SharedLibraryInfo.TYPE_DYNAMIC));
                             break;
                         case TAG_PROCESSES:
                             final int processesDepth = parser.getDepth();
@@ -645,7 +694,8 @@
                         overlayIsStatic, overlayPriority, requiredSystemPropertyName,
                         requiredSystemPropertyValue, minSdkVersion, targetSdkVersion,
                         rollbackDataPolicy, requiredSplitTypes.first, requiredSplitTypes.second,
-                        hasDeviceAdminReceiver, isSdkLibrary, updatableSystem, emergencyInstaller));
+                        hasDeviceAdminReceiver, isSdkLibrary, updatableSystem, emergencyInstaller,
+                        declaredLibraries));
     }
 
     private static boolean isDeviceAdminReceiver(
diff --git a/core/java/android/content/pm/parsing/PackageLite.java b/core/java/android/content/pm/parsing/PackageLite.java
index 116dd1f..9a2ee7f 100644
--- a/core/java/android/content/pm/parsing/PackageLite.java
+++ b/core/java/android/content/pm/parsing/PackageLite.java
@@ -20,6 +20,7 @@
 import android.annotation.Nullable;
 import android.content.pm.ArchivedPackageParcel;
 import android.content.pm.PackageInfo;
+import android.content.pm.SharedLibraryInfo;
 import android.content.pm.SigningDetails;
 import android.content.pm.VerifierInfo;
 
@@ -114,6 +115,8 @@
      */
     private final boolean mIsSdkLibrary;
 
+    private final @NonNull List<SharedLibraryInfo> mDeclaredLibraries;
+
     /**
      * Archival install info.
      */
@@ -154,6 +157,7 @@
         mSplitApkPaths = splitApkPaths;
         mSplitRevisionCodes = splitRevisionCodes;
         mTargetSdk = targetSdk;
+        mDeclaredLibraries = baseApk.getDeclaredLibraries();
         mArchivedPackage = baseApk.getArchivedPackage();
     }
 
@@ -433,6 +437,11 @@
         return mIsSdkLibrary;
     }
 
+    @DataClass.Generated.Member
+    public @NonNull List<SharedLibraryInfo> getDeclaredLibraries() {
+        return mDeclaredLibraries;
+    }
+
     /**
      * Archival install info.
      */
@@ -442,10 +451,10 @@
     }
 
     @DataClass.Generated(
-            time = 1694792176268L,
+            time = 1728333569917L,
             codegenVersion = "1.0.23",
             sourceFile = "frameworks/base/core/java/android/content/pm/parsing/PackageLite.java",
-            inputSignatures = "private final @android.annotation.NonNull java.lang.String mPackageName\nprivate final @android.annotation.NonNull java.lang.String mPath\nprivate final @android.annotation.NonNull java.lang.String mBaseApkPath\nprivate final @android.annotation.Nullable java.lang.String[] mSplitApkPaths\nprivate final @android.annotation.Nullable java.lang.String[] mSplitNames\nprivate final @android.annotation.Nullable java.lang.String[] mUsesSplitNames\nprivate final @android.annotation.Nullable java.lang.String[] mConfigForSplit\nprivate final @android.annotation.Nullable java.util.Set<java.lang.String> mBaseRequiredSplitTypes\nprivate final @android.annotation.Nullable java.util.Set<java.lang.String>[] mRequiredSplitTypes\nprivate final @android.annotation.Nullable java.util.Set<java.lang.String>[] mSplitTypes\nprivate final  int mVersionCodeMajor\nprivate final  int mVersionCode\nprivate final  int mTargetSdk\nprivate final  int mBaseRevisionCode\nprivate final @android.annotation.Nullable int[] mSplitRevisionCodes\nprivate final  int mInstallLocation\nprivate final @android.annotation.NonNull android.content.pm.VerifierInfo[] mVerifiers\nprivate final @android.annotation.NonNull android.content.pm.SigningDetails mSigningDetails\nprivate final @android.annotation.Nullable boolean[] mIsFeatureSplits\nprivate final  boolean mIsolatedSplits\nprivate final  boolean mSplitRequired\nprivate final  boolean mCoreApp\nprivate final  boolean mDebuggable\nprivate final  boolean mMultiArch\nprivate final  boolean mUse32bitAbi\nprivate final  boolean mExtractNativeLibs\nprivate final  boolean mProfileableByShell\nprivate final  boolean mUseEmbeddedDex\nprivate final  boolean mIsSdkLibrary\nprivate final @android.annotation.Nullable android.content.pm.ArchivedPackageParcel mArchivedPackage\npublic  java.util.List<java.lang.String> getAllApkPaths()\npublic  long getLongVersionCode()\nprivate  boolean hasAnyRequiredSplitTypes()\nclass PackageLite extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genConstructor=false, genConstDefs=false)")
+            inputSignatures = "private final @android.annotation.NonNull java.lang.String mPackageName\nprivate final @android.annotation.NonNull java.lang.String mPath\nprivate final @android.annotation.NonNull java.lang.String mBaseApkPath\nprivate final @android.annotation.Nullable java.lang.String[] mSplitApkPaths\nprivate final @android.annotation.Nullable java.lang.String[] mSplitNames\nprivate final @android.annotation.Nullable java.lang.String[] mUsesSplitNames\nprivate final @android.annotation.Nullable java.lang.String[] mConfigForSplit\nprivate final @android.annotation.Nullable java.util.Set<java.lang.String> mBaseRequiredSplitTypes\nprivate final @android.annotation.Nullable java.util.Set<java.lang.String>[] mRequiredSplitTypes\nprivate final @android.annotation.Nullable java.util.Set<java.lang.String>[] mSplitTypes\nprivate final  int mVersionCodeMajor\nprivate final  int mVersionCode\nprivate final  int mTargetSdk\nprivate final  int mBaseRevisionCode\nprivate final @android.annotation.Nullable int[] mSplitRevisionCodes\nprivate final  int mInstallLocation\nprivate final @android.annotation.NonNull android.content.pm.VerifierInfo[] mVerifiers\nprivate final @android.annotation.NonNull android.content.pm.SigningDetails mSigningDetails\nprivate final @android.annotation.Nullable boolean[] mIsFeatureSplits\nprivate final  boolean mIsolatedSplits\nprivate final  boolean mSplitRequired\nprivate final  boolean mCoreApp\nprivate final  boolean mDebuggable\nprivate final  boolean mMultiArch\nprivate final  boolean mUse32bitAbi\nprivate final  boolean mExtractNativeLibs\nprivate final  boolean mProfileableByShell\nprivate final  boolean mUseEmbeddedDex\nprivate final  boolean mIsSdkLibrary\nprivate final @android.annotation.NonNull java.util.List<android.content.pm.SharedLibraryInfo> mDeclaredLibraries\nprivate final @android.annotation.Nullable android.content.pm.ArchivedPackageParcel mArchivedPackage\npublic  java.util.List<java.lang.String> getAllApkPaths()\npublic  long getLongVersionCode()\nprivate  boolean hasAnyRequiredSplitTypes()\nclass PackageLite extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genConstructor=false, genConstDefs=false)")
     @Deprecated
     private void __metadata() {}
 
diff --git a/core/java/android/hardware/DisplayLuts.java b/core/java/android/hardware/DisplayLuts.java
new file mode 100644
index 0000000..b162ad6
--- /dev/null
+++ b/core/java/android/hardware/DisplayLuts.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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;
+
+import android.annotation.NonNull;
+import android.util.IntArray;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @hide
+ */
+public final class DisplayLuts {
+    private IntArray mOffsets;
+    private int mTotalLength;
+
+    private List<float[]> mLutBuffers;
+    private IntArray mLutDimensions;
+    private IntArray mLutSizes;
+    private IntArray mLutSamplingKeys;
+    private static final int LUT_LENGTH_LIMIT = 100000;
+
+    public DisplayLuts() {
+        mOffsets = new IntArray();
+        mTotalLength = 0;
+
+        mLutBuffers = new ArrayList<>();
+        mLutDimensions = new IntArray();
+        mLutSizes = new IntArray();
+        mLutSamplingKeys = new IntArray();
+    }
+
+    /**
+     * Add the lut to be applied.
+     *
+     * @param buffer
+     * @param dimension either 1D or 3D
+     * @param size
+     * @param samplingKey
+     */
+    public void addLut(@NonNull float[] buffer, @LutProperties.Dimension int dimension,
+                       int size, @LutProperties.SamplingKey int samplingKey) {
+
+        int lutLength = 0;
+        if (dimension == LutProperties.ONE_DIMENSION) {
+            lutLength = size;
+        } else if (dimension == LutProperties.THREE_DIMENSION) {
+            lutLength = size * size * size;
+        } else {
+            clear();
+            throw new IllegalArgumentException("The dimension is either 1D or 3D!");
+        }
+
+        if (lutLength >= LUT_LENGTH_LIMIT) {
+            clear();
+            throw new IllegalArgumentException("The lut length is too big to handle!");
+        }
+
+        mOffsets.add(mTotalLength);
+        mTotalLength += lutLength;
+
+        mLutBuffers.add(buffer);
+        mLutDimensions.add(dimension);
+        mLutSizes.add(size);
+        mLutSamplingKeys.add(samplingKey);
+    }
+
+    private void clear() {
+        mTotalLength = 0;
+        mOffsets.clear();
+        mLutBuffers.clear();
+        mLutDimensions.clear();
+        mLutSamplingKeys.clear();
+    }
+
+    /**
+     * @return the array of Lut buffers
+     */
+    public float[] getLutBuffers() {
+        float[] buffer = new float[mTotalLength];
+
+        for (int i = 0; i < mLutBuffers.size(); i++) {
+            float[] lutBuffer = mLutBuffers.get(i);
+            System.arraycopy(lutBuffer, 0, buffer, mOffsets.get(i), lutBuffer.length);
+        }
+        return buffer;
+    }
+
+    /**
+     * @return the starting point of each lut memory region of the lut buffer
+     */
+    public int[] getOffsets() {
+        return mOffsets.toArray();
+    }
+
+    /**
+     * @return the array of Lut size
+     */
+    public int[] getLutSizes() {
+        return mLutSizes.toArray();
+    }
+
+    /**
+     * @return the array of Lut dimension
+     */
+    public int[] getLutDimensions() {
+        return mLutDimensions.toArray();
+    }
+
+    /**
+     * @return the array of sampling key
+     */
+    public int[] getLutSamplingKeys() {
+        return mLutSamplingKeys.toArray();
+    }
+}
diff --git a/core/java/android/hardware/LutProperties.java b/core/java/android/hardware/LutProperties.java
new file mode 100644
index 0000000..57f8a4e
--- /dev/null
+++ b/core/java/android/hardware/LutProperties.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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;
+
+import android.annotation.IntDef;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Lut properties class.
+ *
+ * A Lut (Look-Up Table) is a pre-calculated table for color transformation.
+ *
+ * @hide
+ */
+public final class LutProperties {
+    private final @Dimension int mDimension;
+    private final long mSize;
+    private final @SamplingKey int[] mSamplingKeys;
+
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = {"SAMPLING_KEY_"}, value = {
+        SAMPLING_KEY_RGB,
+        SAMPLING_KEY_MAX_RGB
+    })
+    public @interface SamplingKey {
+    }
+
+    /** use r,g,b channel as the gain value of a Lut */
+    public static final int SAMPLING_KEY_RGB = 0;
+
+    /** use max of r,g,b channel as the gain value of a Lut */
+    public static final int SAMPLING_KEY_MAX_RGB = 1;
+
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(value = {
+        ONE_DIMENSION,
+        THREE_DIMENSION
+    })
+    public @interface Dimension {
+    }
+
+    /** The Lut is one dimensional */
+    public static final int ONE_DIMENSION = 1;
+
+    /** The Lut is three dimensional */
+    public static final int THREE_DIMENSION = 3;
+
+    public @Dimension int getDimension() {
+        return mDimension;
+    }
+
+    /**
+     * @return the size of the Lut.
+     */
+    public long getSize() {
+        return mSize;
+    }
+
+    /**
+     * @return the list of sampling keys
+     */
+    public @SamplingKey int[] getSamplingKeys() {
+        if (mSamplingKeys.length == 0) {
+            throw new IllegalStateException("no sampling key!");
+        }
+        return mSamplingKeys;
+    }
+
+    /* use in the native code */
+    private LutProperties(@Dimension int dimension, long size, @SamplingKey int[] samplingKeys) {
+        if (dimension != ONE_DIMENSION || dimension != THREE_DIMENSION) {
+            throw new IllegalArgumentException("The dimension is either 1 or 3!");
+        }
+        mDimension = dimension;
+        mSize = size;
+        mSamplingKeys = samplingKeys;
+    }
+}
diff --git a/core/java/android/hardware/OWNERS b/core/java/android/hardware/OWNERS
index 43d3f54..f11625e 100644
--- a/core/java/android/hardware/OWNERS
+++ b/core/java/android/hardware/OWNERS
@@ -19,3 +19,6 @@
 
 # OverlayProperties
 per-file OverlayProperties* = file:/graphics/java/android/graphics/OWNERS
+
+# Lut related files
+per-file *Lut* = file:/graphics/java/android/graphics/OWNERS
\ No newline at end of file
diff --git a/core/java/android/hardware/OverlayProperties.java b/core/java/android/hardware/OverlayProperties.java
index 7b452a8..24cfc1b 100644
--- a/core/java/android/hardware/OverlayProperties.java
+++ b/core/java/android/hardware/OverlayProperties.java
@@ -50,6 +50,8 @@
     // Invoked on destruction
     private Runnable mCloser;
 
+    private LutProperties[] mLutProperties;
+
     private OverlayProperties(long nativeObject) {
         if (nativeObject != 0) {
             mCloser = sRegistry.registerNativeAllocation(this, nativeObject);
@@ -70,6 +72,20 @@
     }
 
     /**
+     * Gets the lut properties of the display.
+     * @hide
+     */
+    public LutProperties[] getLutProperties() {
+        if (mNativeObject == 0) {
+            return null;
+        }
+        if (mLutProperties == null) {
+            mLutProperties = nGetLutProperties(mNativeObject);
+        }
+        return mLutProperties;
+    }
+
+    /**
      * Indicates that hardware composition of a buffer encoded with the provided {@link DataSpace}
      * and {@link HardwareBuffer.Format} is supported on the device.
      *
@@ -140,4 +156,5 @@
             long nativeObject, int dataspace, int format);
     private static native void nWriteOverlayPropertiesToParcel(long nativeObject, Parcel dest);
     private static native long nReadOverlayPropertiesFromParcel(Parcel in);
-}
+    private static native LutProperties[] nGetLutProperties(long nativeObject);
+}
\ No newline at end of file
diff --git a/core/java/android/hardware/camera2/CameraManager.java b/core/java/android/hardware/camera2/CameraManager.java
index 9e3a9b3..b785630 100644
--- a/core/java/android/hardware/camera2/CameraManager.java
+++ b/core/java/android/hardware/camera2/CameraManager.java
@@ -19,6 +19,7 @@
 import static android.companion.virtual.VirtualDeviceParams.DEVICE_POLICY_DEFAULT;
 import static android.companion.virtual.VirtualDeviceParams.POLICY_TYPE_CAMERA;
 import static android.content.Context.DEVICE_ID_DEFAULT;
+import static android.content.Context.DEVICE_ID_INVALID;
 
 import android.annotation.CallbackExecutor;
 import android.annotation.FlaggedApi;
@@ -36,6 +37,7 @@
 import android.compat.annotation.ChangeId;
 import android.compat.annotation.EnabledSince;
 import android.compat.annotation.Overridable;
+import android.content.AttributionSource;
 import android.content.AttributionSourceState;
 import android.content.Context;
 import android.content.pm.PackageManager;
@@ -676,8 +678,8 @@
         }
         try {
             for (String physicalCameraId : physicalCameraIds) {
-                AttributionSourceState clientAttribution = getClientAttribution();
-                clientAttribution.deviceId = DEVICE_ID_DEFAULT;
+                AttributionSourceState clientAttribution = getClientAttribution(DEVICE_ID_DEFAULT,
+                        /* useContextAttributionSource= */ false);
                 CameraMetadataNative physicalCameraInfo =
                         cameraService.getCameraCharacteristics(
                                 physicalCameraId,
@@ -974,27 +976,58 @@
     }
 
     /**
-     * Constructs an AttributionSourceState with only the uid, pid, and deviceId fields set
+     * Retrieves the AttributionSourceState to pass to the CameraService.
      *
-     * <p>This method is a temporary stopgap in the transition to using AttributionSource. Currently
-     * AttributionSourceState is only used as a vehicle for passing deviceId, uid, and pid
-     * arguments.</p>
+     * @param deviceIdOverride An override of the AttributionSource's deviceId, if not equal to
+     *   DEVICE_ID_INVALID
+     * @param useContextAttributionSource Whether to return the full attribution source provided by
+     *   the Context.
+     *
+     * @hide
+     */
+    public AttributionSourceState getClientAttribution(int deviceIdOverride,
+            boolean useContextAttributionSource) {
+        AttributionSource contextAttributionSource = mContext.getAttributionSource();
+        if (deviceIdOverride != DEVICE_ID_INVALID) {
+            contextAttributionSource = contextAttributionSource.withDeviceId(deviceIdOverride);
+        }
+        AttributionSourceState contextAttributionSourceState =
+                contextAttributionSource.asState();
+
+        if (Flags.useContextAttributionSource() && useContextAttributionSource) {
+            return contextAttributionSourceState;
+        } else {
+            AttributionSourceState clientAttribution =
+                    new AttributionSourceState();
+            clientAttribution.uid = USE_CALLING_UID;
+            clientAttribution.pid = USE_CALLING_PID;
+            clientAttribution.deviceId = contextAttributionSourceState.deviceId;
+            clientAttribution.packageName = mContext.getOpPackageName();
+            clientAttribution.attributionTag = mContext.getAttributionTag();
+            clientAttribution.next = new AttributionSourceState[0];
+            return clientAttribution;
+        }
+    }
+
+    /**
+     * Retrieves the AttributionSourceState to pass to the CameraService.
+     *
+     * @param useContextAttributionSource Whether to return the full attribution source provided by
+     *   the Context.
+     *
+     * @hide
+     */
+    public AttributionSourceState getClientAttribution(boolean useContextAttributionSource) {
+        return getClientAttribution(DEVICE_ID_INVALID, useContextAttributionSource);
+    }
+
+    /**
+     * Retrieves the AttributionSourceState to pass to the CameraService.
      *
      * @hide
      */
     public AttributionSourceState getClientAttribution() {
-        // TODO: Send the full contextAttribution over aidl, remove USE_CALLING_*
-        AttributionSourceState contextAttribution =
-                mContext.getAttributionSource().asState();
-        AttributionSourceState clientAttribution =
-                new AttributionSourceState();
-        clientAttribution.uid = USE_CALLING_UID;
-        clientAttribution.pid = USE_CALLING_PID;
-        clientAttribution.deviceId = contextAttribution.deviceId;
-        clientAttribution.packageName = mContext.getOpPackageName();
-        clientAttribution.attributionTag = mContext.getAttributionTag();
-        clientAttribution.next = new AttributionSourceState[0];
-        return clientAttribution;
+        return getClientAttribution(DEVICE_ID_INVALID, /* useContextAttributionSource= */ false);
     }
 
     /**
@@ -1049,7 +1082,7 @@
                 }
 
                 AttributionSourceState clientAttribution =
-                        getClientAttribution();
+                        getClientAttribution(/* useContextAttributionSource= */ true);
                 cameraUser =
                         cameraService.connectDevice(
                                 callbacks,
diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java
index a69a371..acb48f3 100644
--- a/core/java/android/hardware/camera2/CameraMetadata.java
+++ b/core/java/android/hardware/camera2/CameraMetadata.java
@@ -2270,7 +2270,17 @@
      * {@link CaptureRequest#SENSOR_FRAME_DURATION android.sensor.frameDuration} are ignored. The
      * application has control over the various
      * android.flash.* fields.</p>
+     * <p>If the device supports manual flash strength control, i.e.,
+     * if {@link CameraCharacteristics#FLASH_SINGLE_STRENGTH_MAX_LEVEL android.flash.singleStrengthMaxLevel} and
+     * {@link CameraCharacteristics#FLASH_TORCH_STRENGTH_MAX_LEVEL android.flash.torchStrengthMaxLevel} are greater than 1, then
+     * the auto-exposure (AE) precapture metering sequence should be
+     * triggered for the configured flash mode and strength to avoid
+     * the image being incorrectly exposed at different
+     * {@link CaptureRequest#FLASH_STRENGTH_LEVEL android.flash.strengthLevel}.</p>
      *
+     * @see CameraCharacteristics#FLASH_SINGLE_STRENGTH_MAX_LEVEL
+     * @see CaptureRequest#FLASH_STRENGTH_LEVEL
+     * @see CameraCharacteristics#FLASH_TORCH_STRENGTH_MAX_LEVEL
      * @see CaptureRequest#SENSOR_EXPOSURE_TIME
      * @see CaptureRequest#SENSOR_FRAME_DURATION
      * @see CaptureRequest#SENSOR_SENSITIVITY
diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java
index 3f5ae91..a193ee1 100644
--- a/core/java/android/hardware/camera2/CaptureRequest.java
+++ b/core/java/android/hardware/camera2/CaptureRequest.java
@@ -1358,6 +1358,13 @@
      * camera device auto-exposure routine for the overridden
      * fields for a given capture will be available in its
      * CaptureResult.</p>
+     * <p>When {@link CaptureRequest#CONTROL_AE_MODE android.control.aeMode} is AE_MODE_ON and if the device
+     * supports manual flash strength control, i.e.,
+     * if {@link CameraCharacteristics#FLASH_SINGLE_STRENGTH_MAX_LEVEL android.flash.singleStrengthMaxLevel} and
+     * {@link CameraCharacteristics#FLASH_TORCH_STRENGTH_MAX_LEVEL android.flash.torchStrengthMaxLevel} are greater than 1, then
+     * the auto-exposure (AE) precapture metering sequence should be
+     * triggered to avoid the image being incorrectly exposed at
+     * different {@link CaptureRequest#FLASH_STRENGTH_LEVEL android.flash.strengthLevel}.</p>
      * <p><b>Possible values:</b></p>
      * <ul>
      *   <li>{@link #CONTROL_AE_MODE_OFF OFF}</li>
@@ -1373,9 +1380,13 @@
      * <p>This key is available on all devices.</p>
      *
      * @see CameraCharacteristics#CONTROL_AE_AVAILABLE_MODES
+     * @see CaptureRequest#CONTROL_AE_MODE
      * @see CaptureRequest#CONTROL_MODE
      * @see CameraCharacteristics#FLASH_INFO_AVAILABLE
      * @see CaptureRequest#FLASH_MODE
+     * @see CameraCharacteristics#FLASH_SINGLE_STRENGTH_MAX_LEVEL
+     * @see CaptureRequest#FLASH_STRENGTH_LEVEL
+     * @see CameraCharacteristics#FLASH_TORCH_STRENGTH_MAX_LEVEL
      * @see CaptureRequest#SENSOR_EXPOSURE_TIME
      * @see CaptureRequest#SENSOR_FRAME_DURATION
      * @see CaptureRequest#SENSOR_SENSITIVITY
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
index a18a634..e5ca46a 100644
--- a/core/java/android/hardware/camera2/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -759,6 +759,13 @@
      * camera device auto-exposure routine for the overridden
      * fields for a given capture will be available in its
      * CaptureResult.</p>
+     * <p>When {@link CaptureRequest#CONTROL_AE_MODE android.control.aeMode} is AE_MODE_ON and if the device
+     * supports manual flash strength control, i.e.,
+     * if {@link CameraCharacteristics#FLASH_SINGLE_STRENGTH_MAX_LEVEL android.flash.singleStrengthMaxLevel} and
+     * {@link CameraCharacteristics#FLASH_TORCH_STRENGTH_MAX_LEVEL android.flash.torchStrengthMaxLevel} are greater than 1, then
+     * the auto-exposure (AE) precapture metering sequence should be
+     * triggered to avoid the image being incorrectly exposed at
+     * different {@link CaptureRequest#FLASH_STRENGTH_LEVEL android.flash.strengthLevel}.</p>
      * <p><b>Possible values:</b></p>
      * <ul>
      *   <li>{@link #CONTROL_AE_MODE_OFF OFF}</li>
@@ -774,9 +781,13 @@
      * <p>This key is available on all devices.</p>
      *
      * @see CameraCharacteristics#CONTROL_AE_AVAILABLE_MODES
+     * @see CaptureRequest#CONTROL_AE_MODE
      * @see CaptureRequest#CONTROL_MODE
      * @see CameraCharacteristics#FLASH_INFO_AVAILABLE
      * @see CaptureRequest#FLASH_MODE
+     * @see CameraCharacteristics#FLASH_SINGLE_STRENGTH_MAX_LEVEL
+     * @see CaptureRequest#FLASH_STRENGTH_LEVEL
+     * @see CameraCharacteristics#FLASH_TORCH_STRENGTH_MAX_LEVEL
      * @see CaptureRequest#SENSOR_EXPOSURE_TIME
      * @see CaptureRequest#SENSOR_FRAME_DURATION
      * @see CaptureRequest#SENSOR_SENSITIVITY
diff --git a/core/java/android/hardware/devicestate/DeviceStateInfo.java b/core/java/android/hardware/devicestate/DeviceStateInfo.java
index 28561ec..fd6f0b8 100644
--- a/core/java/android/hardware/devicestate/DeviceStateInfo.java
+++ b/core/java/android/hardware/devicestate/DeviceStateInfo.java
@@ -28,7 +28,6 @@
 import java.util.Objects;
 import java.util.concurrent.Executor;
 
-
 /**
  * Information about the state of the device.
  *
@@ -63,11 +62,13 @@
      * ignoring any override requests made through a call to {@link DeviceStateManager#requestState(
      * DeviceStateRequest, Executor, DeviceStateRequest.Callback)}.
      */
+    @NonNull
     public final DeviceState baseState;
 
     /**
      * The state of the device.
      */
+    @NonNull
     public final DeviceState currentState;
 
     /**
@@ -78,8 +79,9 @@
      */
     // Using the specific types to avoid virtual method calls in binder transactions
     @SuppressWarnings("NonApiType")
-    public DeviceStateInfo(@NonNull ArrayList<DeviceState> supportedStates, DeviceState baseState,
-            DeviceState state) {
+    public DeviceStateInfo(@NonNull ArrayList<DeviceState> supportedStates,
+            @NonNull DeviceState baseState,
+            @NonNull DeviceState state) {
         this.supportedStates = supportedStates;
         this.baseState = baseState;
         this.currentState = state;
@@ -97,7 +99,7 @@
     public boolean equals(@Nullable Object other) {
         if (this == other) return true;
         if (other == null || (getClass() != other.getClass())) return false;
-        DeviceStateInfo that = (DeviceStateInfo) other;
+        final DeviceStateInfo that = (DeviceStateInfo) other;
         return baseState.equals(that.baseState)
                 &&  currentState.equals(that.currentState)
                 && Objects.equals(supportedStates, that.supportedStates);
@@ -126,8 +128,16 @@
         return diff;
     }
 
+    // Parcelable implementation
+
     @Override
-    public void writeToParcel(Parcel dest, int flags) {
+    public int describeContents() {
+        return 0;
+    }
+
+    /** Writes to Parcel. */
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
         dest.writeInt(supportedStates.size());
         for (int i = 0; i < supportedStates.size(); i++) {
             dest.writeTypedObject(supportedStates.get(i).getConfiguration(), flags);
@@ -137,28 +147,27 @@
         dest.writeTypedObject(currentState.getConfiguration(), flags);
     }
 
-    @Override
-    public int describeContents() {
-        return 0;
+    /** Reads from Parcel. */
+    private DeviceStateInfo(@NonNull Parcel in) {
+        final int numberOfSupportedStates = in.readInt();
+        final ArrayList<DeviceState> supportedStates = new ArrayList<>(numberOfSupportedStates);
+        for (int i = 0; i < numberOfSupportedStates; i++) {
+            final DeviceState.Configuration configuration =
+                    Objects.requireNonNull(in.readTypedObject(DeviceState.Configuration.CREATOR));
+            supportedStates.add(i, new DeviceState(configuration));
+        }
+        this.supportedStates = supportedStates;
+
+        this.baseState = new DeviceState(
+                Objects.requireNonNull(in.readTypedObject(DeviceState.Configuration.CREATOR)));
+        this.currentState = new DeviceState(
+                Objects.requireNonNull(in.readTypedObject(DeviceState.Configuration.CREATOR)));
     }
 
     public static final @NonNull Creator<DeviceStateInfo> CREATOR = new Creator<>() {
         @Override
-        public DeviceStateInfo createFromParcel(Parcel source) {
-            final int numberOfSupportedStates = source.readInt();
-            final ArrayList<DeviceState> supportedStates = new ArrayList<>(numberOfSupportedStates);
-            for (int i = 0; i < numberOfSupportedStates; i++) {
-                DeviceState.Configuration configuration = source.readTypedObject(
-                        DeviceState.Configuration.CREATOR);
-                supportedStates.add(i, new DeviceState(configuration));
-            }
-
-            final DeviceState baseState = new DeviceState(
-                    source.readTypedObject(DeviceState.Configuration.CREATOR));
-            final DeviceState currentState = new DeviceState(
-                    source.readTypedObject(DeviceState.Configuration.CREATOR));
-
-            return new DeviceStateInfo(supportedStates, baseState, currentState);
+        public DeviceStateInfo createFromParcel(@NonNull Parcel in) {
+            return new DeviceStateInfo(in);
         }
 
         @Override
diff --git a/core/java/android/hardware/devicestate/DeviceStateManagerGlobal.java b/core/java/android/hardware/devicestate/DeviceStateManagerGlobal.java
index 0c84019..739dbe1 100644
--- a/core/java/android/hardware/devicestate/DeviceStateManagerGlobal.java
+++ b/core/java/android/hardware/devicestate/DeviceStateManagerGlobal.java
@@ -32,6 +32,7 @@
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.annotations.VisibleForTesting.Visibility;
+import com.android.window.flags.Flags;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -46,6 +47,8 @@
  */
 @VisibleForTesting(visibility = Visibility.PACKAGE)
 public final class DeviceStateManagerGlobal {
+    @Nullable
+    @GuardedBy("DeviceStateManagerGlobal.class")
     private static DeviceStateManagerGlobal sInstance;
     private static final String TAG = "DeviceStateManagerGlobal";
     private static final boolean DEBUG = Build.IS_DEBUGGABLE;
@@ -58,7 +61,7 @@
     public static DeviceStateManagerGlobal getInstance() {
         synchronized (DeviceStateManagerGlobal.class) {
             if (sInstance == null) {
-                IBinder b = ServiceManager.getService(Context.DEVICE_STATE_SERVICE);
+                final IBinder b = ServiceManager.getService(Context.DEVICE_STATE_SERVICE);
                 if (b != null) {
                     sInstance = new DeviceStateManagerGlobal(IDeviceStateManager
                             .Stub.asInterface(b));
@@ -83,10 +86,12 @@
     @GuardedBy("mLock")
     private DeviceStateInfo mLastReceivedInfo;
 
+    // Constructor should be called while holding the lock.
+    // @GuardedBy("DeviceStateManagerGlobal.class") can't be used on constructors.
     @VisibleForTesting
     public DeviceStateManagerGlobal(@NonNull IDeviceStateManager deviceStateManager) {
         mDeviceStateManager = deviceStateManager;
-        registerCallbackIfNeededLocked();
+        registerCallbackLocked();
     }
 
     /**
@@ -94,6 +99,7 @@
      *
      * @see DeviceStateManager#getSupportedDeviceStates()
      */
+    @NonNull
     public List<DeviceState> getSupportedDeviceStates() {
         synchronized (mLock) {
             final DeviceStateInfo currentInfo;
@@ -126,8 +132,8 @@
             conditional = true)
     public void requestState(@NonNull DeviceStateRequest request,
             @Nullable Executor executor, @Nullable DeviceStateRequest.Callback callback) {
-        DeviceStateRequestWrapper requestWrapper = new DeviceStateRequestWrapper(request, callback,
-                executor);
+        final DeviceStateRequestWrapper requestWrapper =
+                new DeviceStateRequestWrapper(request, callback, executor);
         synchronized (mLock) {
             if (findRequestTokenLocked(request) != null) {
                 // This request has already been submitted.
@@ -136,7 +142,7 @@
             // Add the request wrapper to the mRequests array before requesting the state as the
             // callback could be triggered immediately if the mDeviceStateManager IBinder is in the
             // same process as this instance.
-            IBinder token = new Binder();
+            final IBinder token = new Binder();
             mRequests.put(token, requestWrapper);
 
             try {
@@ -176,8 +182,8 @@
     @RequiresPermission(android.Manifest.permission.CONTROL_DEVICE_STATE)
     public void requestBaseStateOverride(@NonNull DeviceStateRequest request,
             @Nullable Executor executor, @Nullable DeviceStateRequest.Callback callback) {
-        DeviceStateRequestWrapper requestWrapper = new DeviceStateRequestWrapper(request, callback,
-                executor);
+        final DeviceStateRequestWrapper requestWrapper =
+                new DeviceStateRequestWrapper(request, callback, executor);
         synchronized (mLock) {
             if (findRequestTokenLocked(request) != null) {
                 // This request has already been submitted.
@@ -186,7 +192,7 @@
             // Add the request wrapper to the mRequests array before requesting the state as the
             // callback could be triggered immediately if the mDeviceStateManager IBinder is in the
             // same process as this instance.
-            IBinder token = new Binder();
+            final IBinder token = new Binder();
             mRequests.put(token, requestWrapper);
 
             try {
@@ -225,7 +231,7 @@
     public void registerDeviceStateCallback(@NonNull DeviceStateCallback callback,
             @NonNull Executor executor) {
         synchronized (mLock) {
-            int index = findCallbackLocked(callback);
+            final int index = findCallbackLocked(callback);
             if (index != -1) {
                 // This callback is already registered.
                 return;
@@ -233,7 +239,8 @@
             // Add the callback wrapper to the mCallbacks array after registering the callback as
             // the callback could be triggered immediately if the mDeviceStateManager IBinder is in
             // the same process as this instance.
-            DeviceStateCallbackWrapper wrapper = new DeviceStateCallbackWrapper(callback, executor);
+            final DeviceStateCallbackWrapper wrapper =
+                    new DeviceStateCallbackWrapper(callback, executor);
             mCallbacks.add(wrapper);
 
             if (mLastReceivedInfo != null) {
@@ -253,7 +260,7 @@
     @VisibleForTesting(visibility = Visibility.PACKAGE)
     public void unregisterDeviceStateCallback(@NonNull DeviceStateCallback callback) {
         synchronized (mLock) {
-            int indexToRemove = findCallbackLocked(callback);
+            final int indexToRemove = findCallbackLocked(callback);
             if (indexToRemove != -1) {
                 mCallbacks.remove(indexToRemove);
             }
@@ -276,15 +283,20 @@
         }
     }
 
-    private void registerCallbackIfNeededLocked() {
-        if (mCallback == null) {
-            mCallback = new DeviceStateManagerCallback();
-            try {
+    @GuardedBy("DeviceStateManagerGlobal.class")
+    private void registerCallbackLocked() {
+        mCallback = new DeviceStateManagerCallback();
+        try {
+            if (Flags.wlinfoOncreate()) {
+                synchronized (mLock) {
+                    mLastReceivedInfo = mDeviceStateManager.registerCallback(mCallback);
+                }
+            } else {
                 mDeviceStateManager.registerCallback(mCallback);
-            } catch (RemoteException ex) {
-                mCallback = null;
-                throw ex.rethrowFromSystemServer();
             }
+        } catch (RemoteException ex) {
+            mCallback = null;
+            throw ex.rethrowFromSystemServer();
         }
     }
 
@@ -298,6 +310,7 @@
     }
 
     @Nullable
+    @GuardedBy("mLock")
     private IBinder findRequestTokenLocked(@NonNull DeviceStateRequest request) {
         for (int i = 0; i < mRequests.size(); i++) {
             if (mRequests.valueAt(i).mRequest.equals(request)) {
@@ -309,8 +322,8 @@
 
     /** Handles a call from the server that the device state info has changed. */
     private void handleDeviceStateInfoChanged(@NonNull DeviceStateInfo info) {
-        ArrayList<DeviceStateCallbackWrapper> callbacks;
-        DeviceStateInfo oldInfo;
+        final ArrayList<DeviceStateCallbackWrapper> callbacks;
+        final DeviceStateInfo oldInfo;
         synchronized (mLock) {
             oldInfo = mLastReceivedInfo;
             mLastReceivedInfo = info;
@@ -335,8 +348,8 @@
      * Handles a call from the server that a request for the supplied {@code token} has become
      * active.
      */
-    private void handleRequestActive(IBinder token) {
-        DeviceStateRequestWrapper request;
+    private void handleRequestActive(@NonNull IBinder token) {
+        final DeviceStateRequestWrapper request;
         synchronized (mLock) {
             request = mRequests.get(token);
         }
@@ -349,8 +362,8 @@
      * Handles a call from the server that a request for the supplied {@code token} has become
      * canceled.
      */
-    private void handleRequestCanceled(IBinder token) {
-        DeviceStateRequestWrapper request;
+    private void handleRequestCanceled(@NonNull IBinder token) {
+        final DeviceStateRequestWrapper request;
         synchronized (mLock) {
             request = mRequests.remove(token);
         }
@@ -361,17 +374,17 @@
 
     private final class DeviceStateManagerCallback extends IDeviceStateManagerCallback.Stub {
         @Override
-        public void onDeviceStateInfoChanged(DeviceStateInfo info) {
+        public void onDeviceStateInfoChanged(@NonNull DeviceStateInfo info) {
             handleDeviceStateInfoChanged(info);
         }
 
         @Override
-        public void onRequestActive(IBinder token) {
+        public void onRequestActive(@NonNull IBinder token) {
             handleRequestActive(token);
         }
 
         @Override
-        public void onRequestCanceled(IBinder token) {
+        public void onRequestCanceled(@NonNull IBinder token) {
             handleRequestCanceled(token);
         }
     }
@@ -388,7 +401,8 @@
             mExecutor = executor;
         }
 
-        void notifySupportedDeviceStatesChanged(List<DeviceState> newSupportedDeviceStates) {
+        void notifySupportedDeviceStatesChanged(
+                @NonNull List<DeviceState> newSupportedDeviceStates) {
             mExecutor.execute(() ->
                     mDeviceStateCallback.onSupportedStatesChanged(newSupportedDeviceStates));
         }
@@ -398,7 +412,7 @@
                     () -> mDeviceStateCallback.onDeviceStateChanged(newDeviceState));
         }
 
-        private void execute(String traceName, Runnable r) {
+        private void execute(@NonNull String traceName, @NonNull Runnable r) {
             mExecutor.execute(() -> {
                 if (DEBUG) {
                     Trace.beginSection(
@@ -416,6 +430,7 @@
     }
 
     private static final class DeviceStateRequestWrapper {
+        @NonNull
         private final DeviceStateRequest mRequest;
         @Nullable
         private final DeviceStateRequest.Callback mCallback;
diff --git a/core/java/android/hardware/devicestate/IDeviceStateManager.aidl b/core/java/android/hardware/devicestate/IDeviceStateManager.aidl
index ea4fe26..50d0623 100644
--- a/core/java/android/hardware/devicestate/IDeviceStateManager.aidl
+++ b/core/java/android/hardware/devicestate/IDeviceStateManager.aidl
@@ -32,16 +32,24 @@
     DeviceStateInfo getDeviceStateInfo();
 
     /**
-     * Registers a callback to receive notifications from the device state manager. Only one
-     * callback can be registered per-process.
+     * Registers a callback to receive notifications from the device state manager and returns the
+     * current {@link DeviceStateInfo}. Only one callback can be registered per-process.
      * <p>
      * As the callback mechanism is used to alert the caller of changes to request status a callback
      * <b>MUST</b> be registered before calling {@link #requestState(IBinder, int, int)} or
      * {@link #cancelRequest(IBinder)}, otherwise an exception will be thrown.
+     * <p>
+     * Upon successful registration, this method returns the committed {@link DeviceStateInfo} if
+     * available, ensuring the availability of the device state after the callback is registered.
+     * This guarantees that the client will have access to the latest device state immediately upon
+     * completion of the two-way IPC call.
      *
+     * @param callback the callback to register for device state notifications.
+     * @return DeviceStateInfo the current device state information including the committed state
+     *         or null if no state has been committed by the {@link DeviceStateProvider} yet.
      * @throws SecurityException if a callback is already registered for the calling process.
      */
-    void registerCallback(in IDeviceStateManagerCallback callback);
+    @nullable DeviceStateInfo registerCallback(in IDeviceStateManagerCallback callback);
 
     /**
      * Requests that the device enter the supplied {@code state}. A callback <b>MUST</b> have been
diff --git a/core/java/android/hardware/display/DisplayManagerInternal.java b/core/java/android/hardware/display/DisplayManagerInternal.java
index 6c1aa90..75ffcc3 100644
--- a/core/java/android/hardware/display/DisplayManagerInternal.java
+++ b/core/java/android/hardware/display/DisplayManagerInternal.java
@@ -461,6 +461,16 @@
     public abstract void stylusGestureStarted(long eventTime);
 
     /**
+     * Called by {@link com.android.server.wm.ContentRecorder} to verify whether
+     * the display is allowed to mirror primary display's content.
+     * @param displayId the id of the display where we mirror to.
+     * @return true if the mirroring dialog is confirmed (display is enabled), or
+     * {@link com.android.server.display.ExternalDisplayPolicy#ENABLE_ON_CONNECT}
+     * system property is enabled.
+     */
+    public abstract boolean isDisplayReadyForMirroring(int displayId);
+
+    /**
      * Describes the requested power state of the display.
      *
      * This object is intended to describe the general characteristics of the
diff --git a/core/java/android/hardware/input/InputSettings.java b/core/java/android/hardware/input/InputSettings.java
index 177ee6f..897ce4a 100644
--- a/core/java/android/hardware/input/InputSettings.java
+++ b/core/java/android/hardware/input/InputSettings.java
@@ -24,6 +24,8 @@
 import static com.android.hardware.input.Flags.keyboardA11ySlowKeysFlag;
 import static com.android.hardware.input.Flags.keyboardA11yStickyKeysFlag;
 import static com.android.hardware.input.Flags.keyboardA11yMouseKeys;
+import static com.android.hardware.input.Flags.mouseReverseVerticalScrolling;
+import static com.android.hardware.input.Flags.mouseSwapPrimaryButton;
 import static com.android.hardware.input.Flags.touchpadTapDragging;
 import static com.android.hardware.input.Flags.touchpadVisualizer;
 import static com.android.input.flags.Flags.enableInputFilterRustImpl;
@@ -363,6 +365,22 @@
     }
 
     /**
+     * Returns true if the feature flag for mouse reverse vertical scrolling is enabled.
+     * @hide
+     */
+    public static boolean isMouseReverseVerticalScrollingFeatureFlagEnabled() {
+        return mouseReverseVerticalScrolling();
+    }
+
+    /**
+     * Returns true if the feature flag for mouse swap primary button is enabled.
+     * @hide
+     */
+    public static boolean isMouseSwapPrimaryButtonFeatureFlagEnabled() {
+        return mouseSwapPrimaryButton();
+    }
+
+    /**
      * Returns true if the touchpad visualizer is allowed to appear.
      *
      * @param context The application context.
@@ -501,6 +519,86 @@
     }
 
     /**
+     * Whether mouse vertical scrolling is enabled, this applies only to connected mice.
+     *
+     * @param context The application context.
+     * @return Whether the mouse will have its vertical scrolling reversed
+     * (scroll down to move up).
+     *
+     * @hide
+     */
+    public static boolean isMouseReverseVerticalScrollingEnabled(@NonNull Context context) {
+        if (!isMouseReverseVerticalScrollingFeatureFlagEnabled()) {
+            return false;
+        }
+
+        return Settings.System.getIntForUser(context.getContentResolver(),
+                Settings.System.MOUSE_REVERSE_VERTICAL_SCROLLING, 0, UserHandle.USER_CURRENT)
+                != 0;
+    }
+
+    /**
+     * Sets whether the connected mouse will have its vertical scrolling reversed.
+     *
+     * @param context The application context.
+     * @param reverseScrolling Whether reverse scrolling is enabled.
+     *
+     * @hide
+     */
+    @RequiresPermission(Manifest.permission.WRITE_SETTINGS)
+    public static void setMouseReverseVerticalScrolling(@NonNull Context context,
+            boolean reverseScrolling) {
+        if (!isMouseReverseVerticalScrollingFeatureFlagEnabled()) {
+            return;
+        }
+
+        Settings.System.putIntForUser(context.getContentResolver(),
+                Settings.System.MOUSE_REVERSE_VERTICAL_SCROLLING, reverseScrolling ? 1 : 0,
+                UserHandle.USER_CURRENT);
+    }
+
+    /**
+     * Whether the primary mouse button is swapped on connected mice.
+     *
+     * @param context The application context.
+     * @return Whether mice will have their primary buttons swapped, so that left clicking will
+     * perform the secondary action (e.g. show menu) and right clicking will perform the primary
+     * action.
+     *
+     * @hide
+     */
+    public static boolean isMouseSwapPrimaryButtonEnabled(@NonNull Context context) {
+        if (!isMouseSwapPrimaryButtonFeatureFlagEnabled()) {
+            return false;
+        }
+
+        return Settings.System.getIntForUser(context.getContentResolver(),
+                Settings.System.MOUSE_SWAP_PRIMARY_BUTTON, 0, UserHandle.USER_CURRENT)
+                != 0;
+    }
+
+    /**
+     * Sets whether mice will have their primary buttons swapped between left and right
+     * clicks.
+     *
+     * @param context The application context.
+     * @param swapPrimaryButton Whether swapping the primary button is enabled.
+     *
+     * @hide
+     */
+    @RequiresPermission(Manifest.permission.WRITE_SETTINGS)
+    public static void setMouseSwapPrimaryButton(@NonNull Context context,
+            boolean swapPrimaryButton) {
+        if (!isMouseSwapPrimaryButtonFeatureFlagEnabled()) {
+            return;
+        }
+
+        Settings.System.putIntForUser(context.getContentResolver(),
+                Settings.System.MOUSE_SWAP_PRIMARY_BUTTON, swapPrimaryButton ? 1 : 0,
+                UserHandle.USER_CURRENT);
+    }
+
+    /**
      * Whether Accessibility bounce keys feature is enabled.
      *
      * <p>
diff --git a/core/java/android/hardware/input/VirtualDpad.java b/core/java/android/hardware/input/VirtualDpad.java
index 5985c39..5b08a0e 100644
--- a/core/java/android/hardware/input/VirtualDpad.java
+++ b/core/java/android/hardware/input/VirtualDpad.java
@@ -17,7 +17,6 @@
 package android.hardware.input;
 
 import android.annotation.NonNull;
-import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
 import android.companion.virtual.IVirtualDevice;
 import android.os.IBinder;
@@ -72,7 +71,6 @@
      *
      * @param event the event to send
      */
-    @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
     public void sendKeyEvent(@NonNull VirtualKeyEvent event) {
         try {
             if (!mSupportedKeyCodes.contains(event.getKeyCode())) {
diff --git a/core/java/android/hardware/input/VirtualInputDevice.java b/core/java/android/hardware/input/VirtualInputDevice.java
index affa4ed..8e4e097 100644
--- a/core/java/android/hardware/input/VirtualInputDevice.java
+++ b/core/java/android/hardware/input/VirtualInputDevice.java
@@ -16,7 +16,6 @@
 
 package android.hardware.input;
 
-import android.annotation.RequiresPermission;
 import android.companion.virtual.IVirtualDevice;
 import android.os.IBinder;
 import android.os.RemoteException;
@@ -68,7 +67,6 @@
     }
 
     @Override
-    @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
     public void close() {
         Log.d(TAG, "Closing virtual input device " + mConfig.getInputDeviceName());
         try {
diff --git a/core/java/android/hardware/input/VirtualInputDeviceConfig.java b/core/java/android/hardware/input/VirtualInputDeviceConfig.java
index e8ef8cd..3b74d7f 100644
--- a/core/java/android/hardware/input/VirtualInputDeviceConfig.java
+++ b/core/java/android/hardware/input/VirtualInputDeviceConfig.java
@@ -163,7 +163,6 @@
             return self();
         }
 
-
         /**
          * Sets the product id of the device, uniquely identifying the device within the address
          * space of a given vendor, identified by the device's vendor id.
@@ -179,6 +178,10 @@
          *
          * <p>The input device is restricted to the display with the given ID and may not send
          * events to any other display.</p>
+         * <p>The corresponding display must be trusted or mirror display.</p>
+         *
+         * @see android.hardware.display.DisplayManager#VIRTUAL_DISPLAY_FLAG_TRUSTED
+         * @see android.hardware.display.DisplayManager#VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR
          */
         @NonNull
         public T setAssociatedDisplayId(int displayId) {
diff --git a/core/java/android/hardware/input/VirtualKeyboard.java b/core/java/android/hardware/input/VirtualKeyboard.java
index 6a7d195..9664004 100644
--- a/core/java/android/hardware/input/VirtualKeyboard.java
+++ b/core/java/android/hardware/input/VirtualKeyboard.java
@@ -17,7 +17,6 @@
 package android.hardware.input;
 
 import android.annotation.NonNull;
-import android.annotation.RequiresPermission;
 import android.annotation.SuppressLint;
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
@@ -31,8 +30,8 @@
  * A virtual keyboard representing a key input mechanism on a remote device, such as a built-in
  * keyboard on a laptop, a software keyboard on a tablet, or a keypad on a TV remote control.
  *
- * This registers an InputDevice that is interpreted like a physically-connected device and
- * dispatches received events to it.
+ * <p>This registers an InputDevice that is interpreted like a physically-connected device and
+ * dispatches received events to it.</p>
  *
  * @hide
  */
@@ -52,7 +51,6 @@
      *
      * @param event the event to send
      */
-    @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
     public void sendKeyEvent(@NonNull VirtualKeyEvent event) {
         try {
             if (mUnsupportedKeyCode == event.getKeyCode()) {
diff --git a/core/java/android/hardware/input/VirtualMouse.java b/core/java/android/hardware/input/VirtualMouse.java
index fb0f700..f2d113c 100644
--- a/core/java/android/hardware/input/VirtualMouse.java
+++ b/core/java/android/hardware/input/VirtualMouse.java
@@ -17,7 +17,6 @@
 package android.hardware.input;
 
 import android.annotation.NonNull;
-import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
 import android.companion.virtual.IVirtualDevice;
 import android.graphics.PointF;
@@ -30,8 +29,8 @@
  * A virtual mouse representing a relative input mechanism on a remote device, such as a mouse or
  * trackpad.
  *
- * This registers an InputDevice that is interpreted like a physically-connected device and
- * dispatches received events to it.
+ * <p>This registers an InputDevice that is interpreted like a physically-connected device and
+ * dispatches received events to it.</p>
  *
  * @hide
  */
@@ -50,7 +49,6 @@
      * @throws IllegalStateException if the display this mouse is associated with is not currently
      * targeted
      */
-    @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
     public void sendButtonEvent(@NonNull VirtualMouseButtonEvent event) {
         try {
             if (!mVirtualDevice.sendButtonEvent(mToken, event)) {
@@ -70,7 +68,6 @@
      * @throws IllegalStateException if the display this mouse is associated with is not currently
      * targeted
      */
-    @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
     public void sendScrollEvent(@NonNull VirtualMouseScrollEvent event) {
         try {
             if (!mVirtualDevice.sendScrollEvent(mToken, event)) {
@@ -89,7 +86,6 @@
      * @throws IllegalStateException if the display this mouse is associated with is not currently
      * targeted
      */
-    @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
     public void sendRelativeEvent(@NonNull VirtualMouseRelativeEvent event) {
         try {
             if (!mVirtualDevice.sendRelativeEvent(mToken, event)) {
@@ -108,7 +104,6 @@
      * @throws IllegalStateException if the display this mouse is associated with is not currently
      * targeted
      */
-    @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
     public @NonNull PointF getCursorPosition() {
         try {
             return mVirtualDevice.getCursorPosition(mToken);
diff --git a/core/java/android/hardware/input/VirtualNavigationTouchpad.java b/core/java/android/hardware/input/VirtualNavigationTouchpad.java
index 3dbb385..94e2151 100644
--- a/core/java/android/hardware/input/VirtualNavigationTouchpad.java
+++ b/core/java/android/hardware/input/VirtualNavigationTouchpad.java
@@ -17,7 +17,6 @@
 package android.hardware.input;
 
 import android.annotation.NonNull;
-import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
 import android.companion.virtual.IVirtualDevice;
 import android.os.IBinder;
@@ -51,7 +50,6 @@
      *
      * @param event the event to send
      */
-    @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
     public void sendTouchEvent(@NonNull VirtualTouchEvent event) {
         try {
             if (!mVirtualDevice.sendTouchEvent(mToken, event)) {
diff --git a/core/java/android/hardware/input/VirtualRotaryEncoder.java b/core/java/android/hardware/input/VirtualRotaryEncoder.java
index bc131df..47c92c8 100644
--- a/core/java/android/hardware/input/VirtualRotaryEncoder.java
+++ b/core/java/android/hardware/input/VirtualRotaryEncoder.java
@@ -18,7 +18,6 @@
 
 import android.annotation.FlaggedApi;
 import android.annotation.NonNull;
-import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
 import android.companion.virtual.IVirtualDevice;
 import android.companion.virtualdevice.flags.Flags;
@@ -48,7 +47,6 @@
      *
      * @param event the event to send
      */
-    @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
     public void sendScrollEvent(@NonNull VirtualRotaryEncoderScrollEvent event) {
         try {
             if (!mVirtualDevice.sendRotaryEncoderScrollEvent(mToken, event)) {
diff --git a/core/java/android/hardware/input/VirtualStylus.java b/core/java/android/hardware/input/VirtualStylus.java
index c763f740..4b79bc4 100644
--- a/core/java/android/hardware/input/VirtualStylus.java
+++ b/core/java/android/hardware/input/VirtualStylus.java
@@ -18,7 +18,6 @@
 
 import android.annotation.FlaggedApi;
 import android.annotation.NonNull;
-import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
 import android.companion.virtual.IVirtualDevice;
 import android.companion.virtual.flags.Flags;
@@ -30,8 +29,8 @@
  * A virtual stylus which can be used to inject input into the framework that represents a stylus
  * on a remote device.
  *
- * This registers an {@link android.view.InputDevice} that is interpreted like a
- * physically-connected device and dispatches received events to it.
+ * <p>This registers an {@link android.view.InputDevice} that is interpreted like a
+ * physically-connected device and dispatches received events to it.</p>
  *
  * @hide
  */
@@ -49,7 +48,6 @@
      *
      * @param event the event to send
      */
-    @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
     public void sendMotionEvent(@NonNull VirtualStylusMotionEvent event) {
         try {
             if (!mVirtualDevice.sendStylusMotionEvent(mToken, event)) {
@@ -66,7 +64,6 @@
      *
      * @param event the event to send
      */
-    @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
     public void sendButtonEvent(@NonNull VirtualStylusButtonEvent event) {
         try {
             if (!mVirtualDevice.sendStylusButtonEvent(mToken, event)) {
diff --git a/core/java/android/hardware/input/VirtualTouchscreen.java b/core/java/android/hardware/input/VirtualTouchscreen.java
index 2c800aa..d0537f0 100644
--- a/core/java/android/hardware/input/VirtualTouchscreen.java
+++ b/core/java/android/hardware/input/VirtualTouchscreen.java
@@ -17,7 +17,6 @@
 package android.hardware.input;
 
 import android.annotation.NonNull;
-import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
 import android.companion.virtual.IVirtualDevice;
 import android.os.IBinder;
@@ -27,8 +26,8 @@
 /**
  * A virtual touchscreen representing a touch-based display input mechanism on a remote device.
  *
- * This registers an InputDevice that is interpreted like a physically-connected device and
- * dispatches received events to it.
+ * <p>This registers an InputDevice that is interpreted like a physically-connected device and
+ * dispatches received events to it.</p>
  *
  * @hide
  */
@@ -45,7 +44,6 @@
      *
      * @param event the event to send
      */
-    @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
     public void sendTouchEvent(@NonNull VirtualTouchEvent event) {
         try {
             if (!mVirtualDevice.sendTouchEvent(mToken, event)) {
diff --git a/core/java/android/os/OWNERS b/core/java/android/os/OWNERS
index 7d3076d..a1b75034 100644
--- a/core/java/android/os/OWNERS
+++ b/core/java/android/os/OWNERS
@@ -115,3 +115,10 @@
 # MessageQueue
 per-file MessageQueue.java = mfasheh@google.com, shayba@google.com
 per-file Message.java = mfasheh@google.com, shayba@google.com
+
+# Stats
+per-file IStatsBootstrapAtomService.aidl = file:/services/core/java/com/android/server/stats/OWNERS
+per-file StatsBootstrapAtom.aidl = file:/services/core/java/com/android/server/stats/OWNERS
+per-file StatsBootstrapAtomValue.aidl = file:/services/core/java/com/android/server/stats/OWNERS
+per-file StatsBootstrapAtomService.java = file:/services/core/java/com/android/server/stats/OWNERS
+per-file StatsServiceManager.java = file:/services/core/java/com/android/server/stats/OWNERS
diff --git a/core/java/android/os/RemoteCallbackList.java b/core/java/android/os/RemoteCallbackList.java
index 769cbdd..f82c822 100644
--- a/core/java/android/os/RemoteCallbackList.java
+++ b/core/java/android/os/RemoteCallbackList.java
@@ -16,11 +16,18 @@
 
 package android.os;
 
+import android.annotation.FlaggedApi;
+import android.annotation.IntDef;
+import android.annotation.NonNull;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.util.ArrayMap;
 import android.util.Slog;
 
 import java.io.PrintWriter;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.Queue;
+import java.util.concurrent.ConcurrentLinkedQueue;
 import java.util.function.BiConsumer;
 import java.util.function.Consumer;
 
@@ -30,7 +37,7 @@
  * {@link android.app.Service} to its clients.  In particular, this:
  *
  * <ul>
- * <li> Keeps track of a set of registered {@link IInterface} callbacks,
+ * <li> Keeps track of a set of registered {@link IInterface} objects,
  * taking care to identify them through their underlying unique {@link IBinder}
  * (by calling {@link IInterface#asBinder IInterface.asBinder()}.
  * <li> Attaches a {@link IBinder.DeathRecipient IBinder.DeathRecipient} to
@@ -47,7 +54,7 @@
  * the registered clients, use {@link #beginBroadcast},
  * {@link #getBroadcastItem}, and {@link #finishBroadcast}.
  *
- * <p>If a registered callback's process goes away, this class will take
+ * <p>If a registered interface's process goes away, this class will take
  * care of automatically removing it from the list.  If you want to do
  * additional work in this situation, you can create a subclass that
  * implements the {@link #onCallbackDied} method.
@@ -56,78 +63,310 @@
 public class RemoteCallbackList<E extends IInterface> {
     private static final String TAG = "RemoteCallbackList";
 
+    private static final int DEFAULT_MAX_QUEUE_SIZE = 1000;
+
+
+    /**
+     * @hide
+     */
+    @IntDef(prefix = {"FROZEN_CALLEE_POLICY_"}, value = {
+            FROZEN_CALLEE_POLICY_UNSET,
+            FROZEN_CALLEE_POLICY_ENQUEUE_ALL,
+            FROZEN_CALLEE_POLICY_ENQUEUE_MOST_RECENT,
+            FROZEN_CALLEE_POLICY_DROP,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    @interface FrozenCalleePolicy {
+    }
+
+    /**
+     * Callbacks are invoked immediately regardless of the frozen state of the target process.
+     *
+     * Not recommended. Only exists for backward-compatibility. This represents the behavior up to
+     * SDK 35. Starting with SDK 36, clients should set a policy to govern callback invocations when
+     * recipients are frozen.
+     */
+    @FlaggedApi(Flags.FLAG_BINDER_FROZEN_STATE_CHANGE_CALLBACK)
+    public static final int FROZEN_CALLEE_POLICY_UNSET = 0;
+
+    /**
+     * When the callback recipient's process is frozen, callbacks are enqueued so they're invoked
+     * after the recipient is unfrozen.
+     *
+     * This is commonly used when the recipient wants to receive all callbacks without losing any
+     * history, e.g. the recipient maintains a running count of events that occurred.
+     *
+     * Queued callbacks are invoked in the order they were originally broadcasted.
+     */
+    @FlaggedApi(Flags.FLAG_BINDER_FROZEN_STATE_CHANGE_CALLBACK)
+    public static final int FROZEN_CALLEE_POLICY_ENQUEUE_ALL = 1;
+
+    /**
+     * When the callback recipient's process is frozen, only the most recent callback is enqueued,
+     * which is later invoked after the recipient is unfrozen.
+     *
+     * This can be used when only the most recent state matters, for instance when clients are
+     * listening to screen brightness changes.
+     */
+    @FlaggedApi(Flags.FLAG_BINDER_FROZEN_STATE_CHANGE_CALLBACK)
+    public static final int FROZEN_CALLEE_POLICY_ENQUEUE_MOST_RECENT = 2;
+
+    /**
+     * When the callback recipient's process is frozen, callbacks are suppressed as if they never
+     * happened.
+     *
+     * This could be useful in the case where the recipient wishes to react to callbacks only when
+     * they occur while the recipient is not frozen. For example, certain network events are only
+     * worth responding to if the response can be immediate. Another example is recipients having
+     * another way of getting the latest state once it's unfrozen. Therefore there is no need to
+     * save callbacks that happened while the recipient was frozen.
+     */
+    @FlaggedApi(Flags.FLAG_BINDER_FROZEN_STATE_CHANGE_CALLBACK)
+    public static final int FROZEN_CALLEE_POLICY_DROP = 3;
+
     @UnsupportedAppUsage
-    /*package*/ ArrayMap<IBinder, Callback> mCallbacks
-            = new ArrayMap<IBinder, Callback>();
+    /*package*/ ArrayMap<IBinder, Interface> mInterfaces = new ArrayMap<IBinder, Interface>();
     private Object[] mActiveBroadcast;
     private int mBroadcastCount = -1;
     private boolean mKilled = false;
     private StringBuilder mRecentCallers;
 
-    private final class Callback implements IBinder.DeathRecipient {
-        final E mCallback;
-        final Object mCookie;
+    private final @FrozenCalleePolicy int mFrozenCalleePolicy;
+    private final int mMaxQueueSize;
 
-        Callback(E callback, Object cookie) {
-            mCallback = callback;
+    private final class Interface implements IBinder.DeathRecipient,
+            IBinder.FrozenStateChangeCallback {
+        final IBinder mBinder;
+        final E mInterface;
+        final Object mCookie;
+        final Queue<Consumer<E>> mCallbackQueue;
+        int mCurrentState = IBinder.FrozenStateChangeCallback.STATE_UNFROZEN;
+
+        Interface(E callbackInterface, Object cookie) {
+            mBinder = callbackInterface.asBinder();
+            mInterface = callbackInterface;
             mCookie = cookie;
+            mCallbackQueue = mFrozenCalleePolicy == FROZEN_CALLEE_POLICY_ENQUEUE_ALL
+                || mFrozenCalleePolicy == FROZEN_CALLEE_POLICY_ENQUEUE_MOST_RECENT
+                ? new ConcurrentLinkedQueue<>() : null;
+        }
+
+        @Override
+        public synchronized void onFrozenStateChanged(@NonNull IBinder who, int state) {
+            if (state == STATE_UNFROZEN && mCallbackQueue != null) {
+                while (!mCallbackQueue.isEmpty()) {
+                    Consumer<E> callback = mCallbackQueue.poll();
+                    callback.accept(mInterface);
+                }
+            }
+            mCurrentState = state;
+        }
+
+        void addCallback(@NonNull Consumer<E> callback) {
+            if (mFrozenCalleePolicy == FROZEN_CALLEE_POLICY_UNSET) {
+                callback.accept(mInterface);
+                return;
+            }
+            synchronized (this) {
+                if (mCurrentState == STATE_UNFROZEN) {
+                    callback.accept(mInterface);
+                    return;
+                }
+                switch (mFrozenCalleePolicy) {
+                    case FROZEN_CALLEE_POLICY_ENQUEUE_ALL:
+                        if (mCallbackQueue.size() >= mMaxQueueSize) {
+                            mCallbackQueue.poll();
+                        }
+                        mCallbackQueue.offer(callback);
+                        break;
+                    case FROZEN_CALLEE_POLICY_ENQUEUE_MOST_RECENT:
+                        mCallbackQueue.clear();
+                        mCallbackQueue.offer(callback);
+                        break;
+                    case FROZEN_CALLEE_POLICY_DROP:
+                        // Do nothing. Just ignore the callback.
+                        break;
+                    case FROZEN_CALLEE_POLICY_UNSET:
+                        // Do nothing. Should have returned at the start of the method.
+                        break;
+                }
+            }
+        }
+
+        public void maybeSubscribeToFrozenCallback() throws RemoteException {
+            if (mFrozenCalleePolicy != FROZEN_CALLEE_POLICY_UNSET) {
+                mBinder.addFrozenStateChangeCallback(this);
+            }
+        }
+
+        public void maybeUnsubscribeFromFrozenCallback() {
+            if (mFrozenCalleePolicy != FROZEN_CALLEE_POLICY_UNSET) {
+                mBinder.removeFrozenStateChangeCallback(this);
+            }
         }
 
         public void binderDied() {
-            synchronized (mCallbacks) {
-                mCallbacks.remove(mCallback.asBinder());
+            synchronized (mInterfaces) {
+                mInterfaces.remove(mBinder);
+                maybeUnsubscribeFromFrozenCallback();
             }
-            onCallbackDied(mCallback, mCookie);
+            onCallbackDied(mInterface, mCookie);
         }
     }
 
     /**
+     * Builder for {@link RemoteCallbackList}.
+     *
+     * @param <E> The remote callback interface type.
+     */
+    @FlaggedApi(Flags.FLAG_BINDER_FROZEN_STATE_CHANGE_CALLBACK)
+    public static final class Builder<E extends IInterface> {
+        private @FrozenCalleePolicy int mFrozenCalleePolicy;
+        private int mMaxQueueSize = DEFAULT_MAX_QUEUE_SIZE;
+
+        /**
+         * Creates a Builder for {@link RemoteCallbackList}.
+         *
+         * @param frozenCalleePolicy When the callback recipient's process is frozen, this parameter
+         * specifies when/whether callbacks are invoked. It's important to choose a strategy that's
+         * right for the use case. Leaving the policy unset with {@link #FROZEN_CALLEE_POLICY_UNSET}
+         * is not recommended as it allows callbacks to be invoked while the recipient is frozen.
+         */
+        public Builder(@FrozenCalleePolicy int frozenCalleePolicy) {
+            mFrozenCalleePolicy = frozenCalleePolicy;
+        }
+
+        /**
+         * Sets the max queue size.
+         *
+         * @param maxQueueSize The max size limit on the queue that stores callbacks added when the
+         * recipient's process is frozen. Once the limit is reached, the oldest callback is dropped
+         * to keep the size under the limit. Should only be called for
+         * {@link #FROZEN_CALLEE_POLICY_ENQUEUE_ALL}.
+         *
+         * @return This builder.
+         * @throws IllegalArgumentException if the maxQueueSize is not positive.
+         * @throws UnsupportedOperationException if frozenCalleePolicy is not
+         * {@link #FROZEN_CALLEE_POLICY_ENQUEUE_ALL}.
+         */
+        public @NonNull Builder setMaxQueueSize(int maxQueueSize) {
+            if (maxQueueSize <= 0) {
+                throw new IllegalArgumentException("maxQueueSize must be positive");
+            }
+            if (mFrozenCalleePolicy != FROZEN_CALLEE_POLICY_ENQUEUE_ALL) {
+                throw new UnsupportedOperationException(
+                        "setMaxQueueSize can only be called for FROZEN_CALLEE_POLICY_ENQUEUE_ALL");
+            }
+            mMaxQueueSize = maxQueueSize;
+            return this;
+        }
+
+        /**
+         * Builds and returns a {@link RemoteCallbackList}.
+         *
+         * @return The built {@link RemoteCallbackList} object.
+         */
+        public @NonNull RemoteCallbackList<E> build() {
+            return new RemoteCallbackList<E>(mFrozenCalleePolicy, mMaxQueueSize);
+        }
+    }
+
+    /**
+     * Returns the frozen callee policy.
+     *
+     * @return The frozen callee policy.
+     */
+    @FlaggedApi(Flags.FLAG_BINDER_FROZEN_STATE_CHANGE_CALLBACK)
+    public @FrozenCalleePolicy int getFrozenCalleePolicy() {
+        return mFrozenCalleePolicy;
+    }
+
+    /**
+     * Returns the max queue size.
+     *
+     * @return The max queue size.
+     */
+    @FlaggedApi(Flags.FLAG_BINDER_FROZEN_STATE_CHANGE_CALLBACK)
+    public int getMaxQueueSize() {
+        return mMaxQueueSize;
+    }
+
+    /**
+     * Creates a RemoteCallbackList with {@link #FROZEN_CALLEE_POLICY_UNSET}. This is equivalent to
+     * <pre>
+     * new RemoteCallbackList.Build(RemoteCallbackList.FROZEN_CALLEE_POLICY_UNSET).build()
+     * </pre>
+     */
+    public RemoteCallbackList() {
+        this(FROZEN_CALLEE_POLICY_UNSET, DEFAULT_MAX_QUEUE_SIZE);
+    }
+
+    /**
+     * Creates a RemoteCallbackList with the specified frozen callee policy.
+     *
+     * @param frozenCalleePolicy When the callback recipient's process is frozen, this parameter
+     * specifies when/whether callbacks are invoked. It's important to choose a strategy that's
+     * right for the use case. Leaving the policy unset with {@link #FROZEN_CALLEE_POLICY_UNSET}
+     * is not recommended as it allows callbacks to be invoked while the recipient is frozen.
+     *
+     * @param maxQueueSize The max size limit on the queue that stores callbacks added when the
+     * recipient's process is frozen. Once the limit is reached, the oldest callbacks would be
+     * dropped to keep the size under limit. Ignored except for
+     * {@link #FROZEN_CALLEE_POLICY_ENQUEUE_ALL}.
+     */
+    private RemoteCallbackList(@FrozenCalleePolicy int frozenCalleePolicy, int maxQueueSize) {
+        mFrozenCalleePolicy = frozenCalleePolicy;
+        mMaxQueueSize = maxQueueSize;
+    }
+
+    /**
      * Simple version of {@link RemoteCallbackList#register(E, Object)}
      * that does not take a cookie object.
      */
-    public boolean register(E callback) {
-        return register(callback, null);
+    public boolean register(E callbackInterface) {
+        return register(callbackInterface, null);
     }
 
     /**
-     * Add a new callback to the list.  This callback will remain in the list
+     * Add a new interface to the list.  This interface will remain in the list
      * until a corresponding call to {@link #unregister} or its hosting process
-     * goes away. If the callback was already registered (determined by
-     * checking to see if the {@link IInterface#asBinder callback.asBinder()}
-     * object is already in the list), then it will be replaced with the new callback.
+     * goes away.  If the interface was already registered (determined by
+     * checking to see if the {@link IInterface#asBinder callbackInterface.asBinder()}
+     * object is already in the list), then it will be replaced with the new interface.
      * Registrations are not counted; a single call to {@link #unregister}
-     * will remove a callback after any number calls to register it.
+     * will remove an interface after any number calls to register it.
      *
-     * @param callback The callback interface to be added to the list.  Must
+     * @param callbackInterface The callback interface to be added to the list.  Must
      * not be null -- passing null here will cause a NullPointerException.
      * Most services will want to check for null before calling this with
      * an object given from a client, so that clients can't crash the
      * service with bad data.
      *
      * @param cookie Optional additional data to be associated with this
-     * callback.
+     * interface.
      *
-     * @return Returns true if the callback was successfully added to the list.
+     * @return Returns true if the interface was successfully added to the list.
      * Returns false if it was not added, either because {@link #kill} had
-     * previously been called or the callback's process has gone away.
+     * previously been called or the interface's process has gone away.
      *
      * @see #unregister
      * @see #kill
      * @see #onCallbackDied
      */
-    public boolean register(E callback, Object cookie) {
-        synchronized (mCallbacks) {
+    public boolean register(E callbackInterface, Object cookie) {
+        synchronized (mInterfaces) {
             if (mKilled) {
                 return false;
             }
             // Flag unusual case that could be caused by a leak. b/36778087
-            logExcessiveCallbacks();
-            IBinder binder = callback.asBinder();
+            logExcessiveInterfaces();
+            IBinder binder = callbackInterface.asBinder();
             try {
-                Callback cb = new Callback(callback, cookie);
-                unregister(callback);
-                binder.linkToDeath(cb, 0);
-                mCallbacks.put(binder, cb);
+                Interface i = new Interface(callbackInterface, cookie);
+                unregister(callbackInterface);
+                binder.linkToDeath(i, 0);
+                i.maybeSubscribeToFrozenCallback();
+                mInterfaces.put(binder, i);
                 return true;
             } catch (RemoteException e) {
                 return false;
@@ -136,27 +375,28 @@
     }
 
     /**
-     * Remove from the list a callback that was previously added with
+     * Remove from the list an interface that was previously added with
      * {@link #register}.  This uses the
-     * {@link IInterface#asBinder callback.asBinder()} object to correctly
+     * {@link IInterface#asBinder callbackInterface.asBinder()} object to correctly
      * find the previous registration.
      * Registrations are not counted; a single unregister call will remove
-     * a callback after any number calls to {@link #register} for it.
+     * an interface after any number calls to {@link #register} for it.
      *
-     * @param callback The callback to be removed from the list.  Passing
+     * @param callbackInterface The interface to be removed from the list.  Passing
      * null here will cause a NullPointerException, so you will generally want
      * to check for null before calling.
      *
-     * @return Returns true if the callback was found and unregistered.  Returns
-     * false if the given callback was not found on the list.
+     * @return Returns true if the interface was found and unregistered.  Returns
+     * false if the given interface was not found on the list.
      *
      * @see #register
      */
-    public boolean unregister(E callback) {
-        synchronized (mCallbacks) {
-            Callback cb = mCallbacks.remove(callback.asBinder());
-            if (cb != null) {
-                cb.mCallback.asBinder().unlinkToDeath(cb, 0);
+    public boolean unregister(E callbackInterface) {
+        synchronized (mInterfaces) {
+            Interface i = mInterfaces.remove(callbackInterface.asBinder());
+            if (i != null) {
+                i.mInterface.asBinder().unlinkToDeath(i, 0);
+                i.maybeUnsubscribeFromFrozenCallback();
                 return true;
             }
             return false;
@@ -164,20 +404,21 @@
     }
 
     /**
-     * Disable this callback list.  All registered callbacks are unregistered,
+     * Disable this interface list.  All registered interfaces are unregistered,
      * and the list is disabled so that future calls to {@link #register} will
      * fail.  This should be used when a Service is stopping, to prevent clients
-     * from registering callbacks after it is stopped.
+     * from registering interfaces after it is stopped.
      *
      * @see #register
      */
     public void kill() {
-        synchronized (mCallbacks) {
-            for (int cbi=mCallbacks.size()-1; cbi>=0; cbi--) {
-                Callback cb = mCallbacks.valueAt(cbi);
-                cb.mCallback.asBinder().unlinkToDeath(cb, 0);
+        synchronized (mInterfaces) {
+            for (int cbi = mInterfaces.size() - 1; cbi >= 0; cbi--) {
+                Interface i = mInterfaces.valueAt(cbi);
+                i.mInterface.asBinder().unlinkToDeath(i, 0);
+                i.maybeUnsubscribeFromFrozenCallback();
             }
-            mCallbacks.clear();
+            mInterfaces.clear();
             mKilled = true;
         }
     }
@@ -186,15 +427,15 @@
      * Old version of {@link #onCallbackDied(E, Object)} that
      * does not provide a cookie.
      */
-    public void onCallbackDied(E callback) {
+    public void onCallbackDied(E callbackInterface) {
     }
     
     /**
-     * Called when the process hosting a callback in the list has gone away.
+     * Called when the process hosting an interface in the list has gone away.
      * The default implementation calls {@link #onCallbackDied(E)}
      * for backwards compatibility.
      * 
-     * @param callback The callback whose process has died.  Note that, since
+     * @param callbackInterface The interface whose process has died.  Note that, since
      * its process has died, you can not make any calls on to this interface.
      * You can, however, retrieve its IBinder and compare it with another
      * IBinder to see if it is the same object.
@@ -203,13 +444,15 @@
      * 
      * @see #register
      */
-    public void onCallbackDied(E callback, Object cookie) {
-        onCallbackDied(callback);
+    public void onCallbackDied(E callbackInterface, Object cookie) {
+        onCallbackDied(callbackInterface);
     }
 
     /**
-     * Prepare to start making calls to the currently registered callbacks.
-     * This creates a copy of the callback list, which you can retrieve items
+     * Use {@link #broadcast(Consumer)} instead to ensure proper handling of frozen processes.
+     *
+     * Prepare to start making calls to the currently registered interfaces.
+     * This creates a copy of the interface list, which you can retrieve items
      * from using {@link #getBroadcastItem}.  Note that only one broadcast can
      * be active at a time, so you must be sure to always call this from the
      * same thread (usually by scheduling with {@link Handler}) or
@@ -219,44 +462,56 @@
      * <p>A typical loop delivering a broadcast looks like this:
      *
      * <pre>
-     * int i = callbacks.beginBroadcast();
+     * int i = interfaces.beginBroadcast();
      * while (i &gt; 0) {
      *     i--;
      *     try {
-     *         callbacks.getBroadcastItem(i).somethingHappened();
+     *         interfaces.getBroadcastItem(i).somethingHappened();
      *     } catch (RemoteException e) {
      *         // The RemoteCallbackList will take care of removing
      *         // the dead object for us.
      *     }
      * }
-     * callbacks.finishBroadcast();</pre>
+     * interfaces.finishBroadcast();</pre>
      *
-     * @return Returns the number of callbacks in the broadcast, to be used
+     * Note that this method is only supported for {@link #FROZEN_CALLEE_POLICY_UNSET}. For other
+     * policies use {@link #broadcast(Consumer)} instead.
+     *
+     * @return Returns the number of interfaces in the broadcast, to be used
      * with {@link #getBroadcastItem} to determine the range of indices you
      * can supply.
      *
+     * @throws UnsupportedOperationException if an frozen callee policy is set.
+     *
      * @see #getBroadcastItem
      * @see #finishBroadcast
      */
     public int beginBroadcast() {
-        synchronized (mCallbacks) {
+        if (mFrozenCalleePolicy != FROZEN_CALLEE_POLICY_UNSET) {
+            throw new UnsupportedOperationException();
+        }
+        return beginBroadcastInternal();
+    }
+
+    private int beginBroadcastInternal() {
+        synchronized (mInterfaces) {
             if (mBroadcastCount > 0) {
                 throw new IllegalStateException(
                         "beginBroadcast() called while already in a broadcast");
             }
             
-            final int N = mBroadcastCount = mCallbacks.size();
-            if (N <= 0) {
+            final int n = mBroadcastCount = mInterfaces.size();
+            if (n <= 0) {
                 return 0;
             }
             Object[] active = mActiveBroadcast;
-            if (active == null || active.length < N) {
-                mActiveBroadcast = active = new Object[N];
+            if (active == null || active.length < n) {
+                mActiveBroadcast = active = new Object[n];
             }
-            for (int i=0; i<N; i++) {
-                active[i] = mCallbacks.valueAt(i);
+            for (int i = 0; i < n; i++) {
+                active[i] = mInterfaces.valueAt(i);
             }
-            return N;
+            return n;
         }
     }
 
@@ -267,24 +522,23 @@
      * calling {@link #finishBroadcast}.
      *
      * <p>Note that it is possible for the process of one of the returned
-     * callbacks to go away before you call it, so you will need to catch
+     * interfaces to go away before you call it, so you will need to catch
      * {@link RemoteException} when calling on to the returned object.
-     * The callback list itself, however, will take care of unregistering
+     * The interface list itself, however, will take care of unregistering
      * these objects once it detects that it is no longer valid, so you can
      * handle such an exception by simply ignoring it.
      *
-     * @param index Which of the registered callbacks you would like to
+     * @param index Which of the registered interfaces you would like to
      * retrieve.  Ranges from 0 to {@link #beginBroadcast}-1, inclusive.
      *
-     * @return Returns the callback interface that you can call.  This will
-     * always be non-null.
+     * @return Returns the interface that you can call.  This will always be non-null.
      *
      * @see #beginBroadcast
      */
     public E getBroadcastItem(int index) {
-        return ((Callback)mActiveBroadcast[index]).mCallback;
+        return ((Interface) mActiveBroadcast[index]).mInterface;
     }
-    
+
     /**
      * Retrieve the cookie associated with the item
      * returned by {@link #getBroadcastItem(int)}.
@@ -292,7 +546,7 @@
      * @see #getBroadcastItem
      */
     public Object getBroadcastCookie(int index) {
-        return ((Callback)mActiveBroadcast[index]).mCookie;
+        return ((Interface) mActiveBroadcast[index]).mCookie;
     }
 
     /**
@@ -303,7 +557,7 @@
      * @see #beginBroadcast
      */
     public void finishBroadcast() {
-        synchronized (mCallbacks) {
+        synchronized (mInterfaces) {
             if (mBroadcastCount < 0) {
                 throw new IllegalStateException(
                         "finishBroadcast() called outside of a broadcast");
@@ -322,16 +576,18 @@
     }
 
     /**
-     * Performs {@code action} on each callback, calling
-     * {@link #beginBroadcast()}/{@link #finishBroadcast()} before/after looping
+     * Performs {@code callback} on each registered interface.
      *
-     * @hide
+     * This is equivalent to #beginBroadcast, followed by iterating over the items using
+     * #getBroadcastItem and then @finishBroadcast, except that this method supports
+     * frozen callee policies.
      */
-    public void broadcast(Consumer<E> action) {
-        int itemCount = beginBroadcast();
+    @FlaggedApi(Flags.FLAG_BINDER_FROZEN_STATE_CHANGE_CALLBACK)
+    public void broadcast(@NonNull Consumer<E> callback) {
+        int itemCount = beginBroadcastInternal();
         try {
             for (int i = 0; i < itemCount; i++) {
-                action.accept(getBroadcastItem(i));
+                ((Interface) mActiveBroadcast[i]).addCallback(callback);
             }
         } finally {
             finishBroadcast();
@@ -339,16 +595,16 @@
     }
 
     /**
-     * Performs {@code action} for each cookie associated with a callback, calling
+     * Performs {@code callback} for each cookie associated with an interface, calling
      * {@link #beginBroadcast()}/{@link #finishBroadcast()} before/after looping
      *
      * @hide
      */
-    public <C> void broadcastForEachCookie(Consumer<C> action) {
+    public <C> void broadcastForEachCookie(Consumer<C> callback) {
         int itemCount = beginBroadcast();
         try {
             for (int i = 0; i < itemCount; i++) {
-                action.accept((C) getBroadcastCookie(i));
+                callback.accept((C) getBroadcastCookie(i));
             }
         } finally {
             finishBroadcast();
@@ -356,16 +612,16 @@
     }
 
     /**
-     * Performs {@code action} on each callback and associated cookie, calling {@link
+     * Performs {@code callback} on each interface and associated cookie, calling {@link
      * #beginBroadcast()}/{@link #finishBroadcast()} before/after looping.
      *
      * @hide
      */
-    public <C> void broadcast(BiConsumer<E, C> action) {
+    public <C> void broadcast(BiConsumer<E, C> callback) {
         int itemCount = beginBroadcast();
         try {
             for (int i = 0; i < itemCount; i++) {
-                action.accept(getBroadcastItem(i), (C) getBroadcastCookie(i));
+                callback.accept(getBroadcastItem(i), (C) getBroadcastCookie(i));
             }
         } finally {
             finishBroadcast();
@@ -373,10 +629,10 @@
     }
 
     /**
-     * Returns the number of registered callbacks. Note that the number of registered
-     * callbacks may differ from the value returned by {@link #beginBroadcast()} since
-     * the former returns the number of callbacks registered at the time of the call
-     * and the second the number of callback to which the broadcast will be delivered.
+     * Returns the number of registered interfaces. Note that the number of registered
+     * interfaces may differ from the value returned by {@link #beginBroadcast()} since
+     * the former returns the number of interfaces registered at the time of the call
+     * and the second the number of interfaces to which the broadcast will be delivered.
      * <p>
      * This function is useful to decide whether to schedule a broadcast if this
      * requires doing some work which otherwise would not be performed.
@@ -385,39 +641,39 @@
      * @return The size.
      */
     public int getRegisteredCallbackCount() {
-        synchronized (mCallbacks) {
+        synchronized (mInterfaces) {
             if (mKilled) {
                 return 0;
             }
-            return mCallbacks.size();
+            return mInterfaces.size();
         }
     }
 
     /**
-     * Return a currently registered callback.  Note that this is
+     * Return a currently registered interface.  Note that this is
      * <em>not</em> the same as {@link #getBroadcastItem} and should not be used
-     * interchangeably with it.  This method returns the registered callback at the given
+     * interchangeably with it.  This method returns the registered interface at the given
      * index, not the current broadcast state.  This means that it is not itself thread-safe:
      * any call to {@link #register} or {@link #unregister} will change these indices, so you
      * must do your own thread safety between these to protect from such changes.
      *
-     * @param index Index of which callback registration to return, from 0 to
+     * @param index Index of which interface registration to return, from 0 to
      * {@link #getRegisteredCallbackCount()} - 1.
      *
-     * @return Returns whatever callback is associated with this index, or null if
+     * @return Returns whatever interface is associated with this index, or null if
      * {@link #kill()} has been called.
      */
     public E getRegisteredCallbackItem(int index) {
-        synchronized (mCallbacks) {
+        synchronized (mInterfaces) {
             if (mKilled) {
                 return null;
             }
-            return mCallbacks.valueAt(index).mCallback;
+            return mInterfaces.valueAt(index).mInterface;
         }
     }
 
     /**
-     * Return any cookie associated with a currently registered callback.  Note that this is
+     * Return any cookie associated with a currently registered interface.  Note that this is
      * <em>not</em> the same as {@link #getBroadcastCookie} and should not be used
      * interchangeably with it.  This method returns the current cookie registered at the given
      * index, not the current broadcast state.  This means that it is not itself thread-safe:
@@ -431,25 +687,25 @@
      * {@link #kill()} has been called.
      */
     public Object getRegisteredCallbackCookie(int index) {
-        synchronized (mCallbacks) {
+        synchronized (mInterfaces) {
             if (mKilled) {
                 return null;
             }
-            return mCallbacks.valueAt(index).mCookie;
+            return mInterfaces.valueAt(index).mCookie;
         }
     }
 
     /** @hide */
     public void dump(PrintWriter pw, String prefix) {
-        synchronized (mCallbacks) {
-            pw.print(prefix); pw.print("callbacks: "); pw.println(mCallbacks.size());
+        synchronized (mInterfaces) {
+            pw.print(prefix); pw.print("callbacks: "); pw.println(mInterfaces.size());
             pw.print(prefix); pw.print("killed: "); pw.println(mKilled);
             pw.print(prefix); pw.print("broadcasts count: "); pw.println(mBroadcastCount);
         }
     }
 
-    private void logExcessiveCallbacks() {
-        final long size = mCallbacks.size();
+    private void logExcessiveInterfaces() {
+        final long size = mInterfaces.size();
         final long TOO_MANY = 3000;
         final long MAX_CHARS = 1000;
         if (size >= TOO_MANY) {
diff --git a/core/java/android/os/StatsBootstrapAtomValue.aidl b/core/java/android/os/StatsBootstrapAtomValue.aidl
index a90dfa4..b59bc06 100644
--- a/core/java/android/os/StatsBootstrapAtomValue.aidl
+++ b/core/java/android/os/StatsBootstrapAtomValue.aidl
@@ -26,4 +26,5 @@
     float floatValue;
     String stringValue;
     byte[] bytesValue;
+    String[] stringArrayValue;
 }
\ No newline at end of file
diff --git a/core/java/android/os/SystemClock.java b/core/java/android/os/SystemClock.java
index dfc591b..8ef62e3 100644
--- a/core/java/android/os/SystemClock.java
+++ b/core/java/android/os/SystemClock.java
@@ -62,7 +62,7 @@
  *     sleep (CPU off, display dark, device waiting for external input),
  *     but is not affected by clock scaling, idle, or other power saving
  *     mechanisms.  This is the basis for most interval timing
- *     such as {@link Thread#sleep(long) Thread.sleep(millls)},
+ *     such as {@link Thread#sleep(long) Thread.sleep(millis)},
  *     {@link Object#wait(long) Object.wait(millis)}, and
  *     {@link System#nanoTime System.nanoTime()}.  This clock is guaranteed
  *     to be monotonic, and is suitable for interval timing when the
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 3ae9511..bd3da0d 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -66,6 +66,7 @@
 import android.util.AndroidException;
 import android.util.ArraySet;
 import android.util.Log;
+import android.util.Pair;
 import android.view.WindowManager.LayoutParams;
 
 import com.android.internal.R;
@@ -3908,11 +3909,57 @@
             android.Manifest.permission.INTERACT_ACROSS_USERS}, conditional = true)
     public @NonNull UserProperties getUserProperties(@NonNull UserHandle userHandle) {
         final int userId = userHandle.getIdentifier();
-        // Avoid calling into system server for invalid user ids.
-        if (android.multiuser.Flags.fixGetUserPropertyCache() && userId < 0) {
+
+        if (userId < 0 && android.multiuser.Flags.fixGetUserPropertyCache()) {
+            // Avoid calling into system server for invalid user ids.
             throw new IllegalArgumentException("Cannot access properties for user " + userId);
         }
-        return mUserPropertiesCache.query(userId);
+
+        if (!android.multiuser.Flags.cacheUserPropertiesCorrectlyReadOnly() || userId < 0) {
+            // This is the historical code path, when all flags are false.
+            try {
+                return mService.getUserPropertiesCopy(userId);
+            } catch (RemoteException re) {
+                throw re.rethrowFromSystemServer();
+            }
+        }
+
+        final int callingUid = Binder.getCallingUid();
+        final int processUid = Process.myUid();
+        if (Build.isDebuggable() && callingUid != processUid) {
+            Log.w(TAG, "Uid " + processUid + " is fetching a copy of UserProperties on"
+                            + " behalf of callingUid " + callingUid + ". Possibly"
+                            + " it should carefully first clearCallingIdentity or perhaps use"
+                            + " UserManagerInternal.getUserProperties() instead?",
+                    new Throwable());
+        }
+
+        return getUserPropertiesFromQuery(new QueryUserId(userId));
+    }
+
+    /** @hide */
+    public static final void invalidateUserPropertiesCache() {
+        UserManagerCache.invalidateUserPropertiesFromQuery();
+    }
+
+    /**
+     * Cachable version of {@link #getUserProperties(UserHandle)}, caching the UserProperties
+     * corresponding to the given QueryUserId. The cached copy depends on both the queried userId as
+     * well as the Binder caller querying it, since the result depends on the caller's permissions.
+     */
+    @CachedProperty()
+    private @NonNull UserProperties getUserPropertiesFromQuery(QueryUserId query) {
+        return ((UserManagerCache) mIpcDataCache).getUserPropertiesFromQuery(
+                (QueryUserId q) -> mService.getUserPropertiesCopy(q.getUserId()), query);
+    }
+
+    /** Class keeping track of a userId, as well as the callingUid that is asking about it. */
+    /** @hide */
+    static final class QueryUserId extends Pair<Integer, Integer> {
+        public QueryUserId(@UserIdInt int userId) {
+            super(Binder.getCallingUid(), userId);
+        }
+        public @UserIdInt int getUserId() { return second; }
     }
 
     /**
@@ -6368,8 +6415,12 @@
                 Settings.Global.DEVICE_DEMO_MODE, 0) > 0;
     }
 
-    /** @hide */
-    public static final void invalidateUserSerialNumberCache() {
+
+    /**
+     * This method is used to invalidate caches, when user was added or removed.
+     * @hide
+     */
+    public static final void invalidateCacheOnUserListChange() {
         UserManagerCache.invalidateUserSerialNumber();
     }
 
@@ -6382,7 +6433,7 @@
      * @hide
      */
     @UnsupportedAppUsage
-    @CachedProperty(modsFlagOnOrNone = {})
+    @CachedProperty(modsFlagOnOrNone = {}, api = "user_manager_users")
     public int getUserSerialNumber(@UserIdInt int userId) {
         // Read only flag should is to fix early access to this API
         // cacheUserSerialNumber to be removed after the
@@ -6652,34 +6703,6 @@
         PropertyInvalidatedCache.invalidateCache(CACHE_KEY_STATIC_USER_PROPERTIES);
     }
 
-    /* Cache key for UserProperties object. */
-    private static final String CACHE_KEY_USER_PROPERTIES =
-        PropertyInvalidatedCache.createPropertyName(
-            PropertyInvalidatedCache.MODULE_SYSTEM, "user_properties");
-
-    // TODO: It would be better to somehow have this as static, so that it can work cross-context.
-    private final PropertyInvalidatedCache<Integer, UserProperties> mUserPropertiesCache =
-            new PropertyInvalidatedCache<Integer, UserProperties>(16, CACHE_KEY_USER_PROPERTIES) {
-                @Override
-                public UserProperties recompute(Integer userId) {
-                    try {
-                        // If the userId doesn't exist, this will throw rather than cache garbage.
-                        return mService.getUserPropertiesCopy(userId);
-                    } catch (RemoteException re) {
-                        throw re.rethrowFromSystemServer();
-                    }
-                }
-                @Override
-                public boolean bypass(Integer query) {
-                    return query < 0;
-                }
-            };
-
-    /** @hide */
-    public static final void invalidateUserPropertiesCache() {
-        PropertyInvalidatedCache.invalidateCache(CACHE_KEY_USER_PROPERTIES);
-    }
-
     /**
      * @hide
      * User that enforces a restriction.
diff --git a/core/java/android/os/VibrationEffect.java b/core/java/android/os/VibrationEffect.java
index 64a2dbc..ffc58c5 100644
--- a/core/java/android/os/VibrationEffect.java
+++ b/core/java/android/os/VibrationEffect.java
@@ -40,6 +40,7 @@
 import android.os.vibrator.RampSegment;
 import android.os.vibrator.StepSegment;
 import android.os.vibrator.VibrationEffectSegment;
+import android.os.vibrator.VibratorFrequencyProfileLegacy;
 import android.util.MathUtils;
 
 import com.android.internal.util.Preconditions;
@@ -1761,7 +1762,7 @@
          * new value as fast as possible.
          *
          * <p>Vibration parameter values will be truncated to conform to the device capabilities
-         * according to the {@link android.os.vibrator.VibratorFrequencyProfile}.
+         * according to the {@link VibratorFrequencyProfileLegacy}.
          *
          * @param duration        The length of time this transition should take. Value must be
          *                        non-negative and will be truncated to milliseconds.
@@ -1792,7 +1793,7 @@
          * new values as fast as possible.
          *
          * <p>Vibration parameters values will be truncated to conform to the device capabilities
-         * according to the {@link android.os.vibrator.VibratorFrequencyProfile}.
+         * according to the {@link VibratorFrequencyProfileLegacy}.
          *
          * @param duration         The length of time this transition should take. Value must be
          *                         non-negative and will be truncated to milliseconds.
diff --git a/core/java/android/os/Vibrator.java b/core/java/android/os/Vibrator.java
index 84325b7..c4c4580 100644
--- a/core/java/android/os/Vibrator.java
+++ b/core/java/android/os/Vibrator.java
@@ -22,6 +22,7 @@
 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;
@@ -34,6 +35,7 @@
 import android.os.vibrator.Flags;
 import android.os.vibrator.VibrationConfig;
 import android.os.vibrator.VibratorFrequencyProfile;
+import android.os.vibrator.VibratorFrequencyProfileLegacy;
 import android.util.Log;
 import android.view.HapticFeedbackConstants;
 
@@ -290,12 +292,36 @@
      * @hide
      */
     @TestApi
+    @SuppressLint("UnflaggedApi")
+    @Nullable
+    public VibratorFrequencyProfileLegacy getFrequencyProfileLegacy() {
+        VibratorInfo.FrequencyProfileLegacy frequencyProfile =
+                getInfo().getFrequencyProfileLegacy();
+        if (frequencyProfile.isEmpty()) {
+            return null;
+        }
+        return new VibratorFrequencyProfileLegacy(frequencyProfile);
+    }
+
+    /**
+     * Gets the profile that describes the vibrator output across the supported frequency range.
+     *
+     * <p>The profile describes the output acceleration that the device can reach when it
+     * vibrates at different frequencies.
+     *
+     * @return The frequency profile for this vibrator, or null if the vibrator does not have
+     * frequency control. If this vibrator is a composite of multiple physical devices then this
+     * will return a profile supported in all devices, or null if the intersection is empty or not
+     * available.
+     */
+    @FlaggedApi(Flags.FLAG_NORMALIZED_PWLE_EFFECTS)
     @Nullable
     public VibratorFrequencyProfile getFrequencyProfile() {
         VibratorInfo.FrequencyProfile frequencyProfile = getInfo().getFrequencyProfile();
         if (frequencyProfile.isEmpty()) {
             return null;
         }
+
         return new VibratorFrequencyProfile(frequencyProfile);
     }
 
diff --git a/core/java/android/os/VibratorInfo.java b/core/java/android/os/VibratorInfo.java
index 5378295e..9419032 100644
--- a/core/java/android/os/VibratorInfo.java
+++ b/core/java/android/os/VibratorInfo.java
@@ -20,8 +20,10 @@
 import android.annotation.Nullable;
 import android.hardware.vibrator.Braking;
 import android.hardware.vibrator.IVibrator;
+import android.os.vibrator.Flags;
 import android.util.IndentingPrintWriter;
 import android.util.MathUtils;
+import android.util.Pair;
 import android.util.Range;
 import android.util.SparseBooleanArray;
 import android.util.SparseIntArray;
@@ -30,8 +32,11 @@
 
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Comparator;
 import java.util.List;
+import java.util.Map;
 import java.util.Objects;
+import java.util.TreeMap;
 
 /**
  * A VibratorInfo describes the capabilities of a {@link Vibrator}.
@@ -59,6 +64,7 @@
     private final int mPwlePrimitiveDurationMax;
     private final int mPwleSizeMax;
     private final float mQFactor;
+    private final FrequencyProfileLegacy mFrequencyProfileLegacy;
     private final FrequencyProfile mFrequencyProfile;
     private final int mMaxEnvelopeEffectSize;
     private final int mMinEnvelopeEffectControlPointDurationMillis;
@@ -75,6 +81,7 @@
         mPwlePrimitiveDurationMax = in.readInt();
         mPwleSizeMax = in.readInt();
         mQFactor = in.readFloat();
+        mFrequencyProfileLegacy = FrequencyProfileLegacy.CREATOR.createFromParcel(in);
         mFrequencyProfile = FrequencyProfile.CREATOR.createFromParcel(in);
         mMaxEnvelopeEffectSize = in.readInt();
         mMinEnvelopeEffectControlPointDurationMillis = in.readInt();
@@ -86,8 +93,8 @@
                 baseVibratorInfo.mSupportedBraking, baseVibratorInfo.mSupportedPrimitives,
                 baseVibratorInfo.mPrimitiveDelayMax, baseVibratorInfo.mCompositionSizeMax,
                 baseVibratorInfo.mPwlePrimitiveDurationMax, baseVibratorInfo.mPwleSizeMax,
-                baseVibratorInfo.mQFactor, baseVibratorInfo.mFrequencyProfile,
-                baseVibratorInfo.mMaxEnvelopeEffectSize,
+                baseVibratorInfo.mQFactor, baseVibratorInfo.mFrequencyProfileLegacy,
+                baseVibratorInfo.mFrequencyProfile, baseVibratorInfo.mMaxEnvelopeEffectSize,
                 baseVibratorInfo.mMinEnvelopeEffectControlPointDurationMillis,
                 baseVibratorInfo.mMaxEnvelopeEffectControlPointDurationMillis);
     }
@@ -112,18 +119,31 @@
      * @param pwleSizeMax              The maximum number of primitives supported by a PWLE
      *                                 composition.
      * @param qFactor                  The vibrator quality factor.
-     * @param frequencyProfile         The description of the vibrator supported frequencies and max
+     * @param frequencyProfileLegacy   The description of the vibrator supported frequencies and max
      *                                 amplitude mappings.
+     * @param frequencyProfile       The description of the vibrator supported frequencies and
+     *                                 output acceleration mappings.
+     * @param maxEnvelopeEffectSize    The maximum number of control points supported for an
+     *                                 envelope effect.
+     * @param minEnvelopeEffectControlPointDurationMillis   The minimum duration supported
+     *                                                      between two control points within an
+     *                                                      envelope effect.
+     * @param maxEnvelopeEffectControlPointDurationMillis   The maximum duration supported
+     *                                                      between two control points within an
+     *                                                      envelope effect.
+     *
      * @hide
      */
     public VibratorInfo(int id, long capabilities, @Nullable SparseBooleanArray supportedEffects,
             @Nullable SparseBooleanArray supportedBraking,
             @NonNull SparseIntArray supportedPrimitives, int primitiveDelayMax,
             int compositionSizeMax, int pwlePrimitiveDurationMax, int pwleSizeMax,
-            float qFactor, @NonNull FrequencyProfile frequencyProfile,
-            int maxEnvelopeEffectSize, int minEnvelopeEffectControlPointDurationMillis,
+            float qFactor, @NonNull FrequencyProfileLegacy frequencyProfileLegacy,
+            @NonNull FrequencyProfile frequencyProfile, int maxEnvelopeEffectSize,
+            int minEnvelopeEffectControlPointDurationMillis,
             int maxEnvelopeEffectControlPointDurationMillis) {
         Preconditions.checkNotNull(supportedPrimitives);
+        Preconditions.checkNotNull(frequencyProfileLegacy);
         Preconditions.checkNotNull(frequencyProfile);
         mId = id;
         mCapabilities = capabilities;
@@ -135,6 +155,7 @@
         mPwlePrimitiveDurationMax = pwlePrimitiveDurationMax;
         mPwleSizeMax = pwleSizeMax;
         mQFactor = qFactor;
+        mFrequencyProfileLegacy = frequencyProfileLegacy;
         mFrequencyProfile = frequencyProfile;
         mMaxEnvelopeEffectSize = maxEnvelopeEffectSize;
         mMinEnvelopeEffectControlPointDurationMillis =
@@ -155,6 +176,7 @@
         dest.writeInt(mPwlePrimitiveDurationMax);
         dest.writeInt(mPwleSizeMax);
         dest.writeFloat(mQFactor);
+        mFrequencyProfileLegacy.writeToParcel(dest, flags);
         mFrequencyProfile.writeToParcel(dest, flags);
         dest.writeInt(mMaxEnvelopeEffectSize);
         dest.writeInt(mMinEnvelopeEffectControlPointDurationMillis);
@@ -205,6 +227,7 @@
                 && Objects.equals(mSupportedEffects, that.mSupportedEffects)
                 && Objects.equals(mSupportedBraking, that.mSupportedBraking)
                 && Objects.equals(mQFactor, that.mQFactor)
+                && Objects.equals(mFrequencyProfileLegacy, that.mFrequencyProfileLegacy)
                 && Objects.equals(mFrequencyProfile, that.mFrequencyProfile)
                 && mMaxEnvelopeEffectSize == that.mMaxEnvelopeEffectSize
                 && mMinEnvelopeEffectControlPointDurationMillis
@@ -216,7 +239,7 @@
     @Override
     public int hashCode() {
         int hashCode = Objects.hash(mId, mCapabilities, mSupportedEffects, mSupportedBraking,
-                mQFactor, mFrequencyProfile);
+                mQFactor, mFrequencyProfileLegacy, mFrequencyProfile);
         for (int i = 0; i < mSupportedPrimitives.size(); i++) {
             hashCode = 31 * hashCode + mSupportedPrimitives.keyAt(i);
             hashCode = 31 * hashCode + mSupportedPrimitives.valueAt(i);
@@ -238,6 +261,7 @@
                 + ", mPwlePrimitiveDurationMax=" + mPwlePrimitiveDurationMax
                 + ", mPwleSizeMax=" + mPwleSizeMax
                 + ", mQFactor=" + mQFactor
+                + ", mFrequencyProfileLegacy=" + mFrequencyProfileLegacy
                 + ", mFrequencyProfile=" + mFrequencyProfile
                 + ", mMaxEnvelopeEffectSize=" + mMaxEnvelopeEffectSize
                 + ", mMinEnvelopeEffectControlPointDurationMillis="
@@ -262,6 +286,7 @@
         pw.println("pwlePrimitiveDurationMax = " + mPwlePrimitiveDurationMax);
         pw.println("pwleSizeMax = " + mPwleSizeMax);
         pw.println("q-factor = " + mQFactor);
+        pw.println("frequencyProfileLegacy = " + mFrequencyProfileLegacy);
         pw.println("frequencyProfile = " + mFrequencyProfile);
         pw.println("mMaxEnvelopeEffectSize = " + mMaxEnvelopeEffectSize);
         pw.println("mMinEnvelopeEffectControlPointDurationMillis = "
@@ -517,7 +542,10 @@
      * this vibrator is a composite of multiple physical devices.
      */
     public float getResonantFrequencyHz() {
-        return mFrequencyProfile.mResonantFrequencyHz;
+        if (Flags.normalizedPwleEffects()) {
+            return mFrequencyProfile.mResonantFrequencyHz;
+        }
+        return mFrequencyProfileLegacy.mResonantFrequencyHz;
     }
 
     /**
@@ -537,6 +565,17 @@
      * <p>If the devices does not have frequency control then the profile should be empty.
      */
     @NonNull
+    public FrequencyProfileLegacy getFrequencyProfileLegacy() {
+        return mFrequencyProfileLegacy;
+    }
+
+    /**
+     * Gets the profile of supported frequencies, including the measurements of maximum
+     * output acceleration for supported vibration frequencies.
+     *
+     * <p>If the devices does not have frequency control then the profile should be empty.
+     */
+    @NonNull
     public FrequencyProfile getFrequencyProfile() {
         return mFrequencyProfile;
     }
@@ -623,6 +662,304 @@
     }
 
     /**
+     * Describes the maximum output acceleration that can be achieved for each supported
+     * frequency in a specific vibrator.
+     *
+     * @hide
+     */
+    public static final class FrequencyProfile implements Parcelable {
+
+        private final float[] mFrequenciesHz;
+        private final float[] mOutputAccelerationsGs;
+        private final float mResonantFrequencyHz;
+        private final float mMaxOutputAccelerationGs;
+        private final float mMinFrequencyHz;
+        private final float mMaxFrequencyHz;
+
+        public FrequencyProfile(Parcel in) {
+            this(in.readFloat(), in.createFloatArray(), in.createFloatArray());
+        }
+
+        /**
+         * Default constructor.
+         *
+         * @param resonantFrequencyHz   The vibrator resonant frequency, in hertz.
+         * @param frequenciesHz         The supported vibration frequencies, in hertz.
+         * @param outputAccelerationsGs The maximum achievable output acceleration (in Gs) the
+         *                              device can reach at the supported frequencies.
+         */
+        public FrequencyProfile(float resonantFrequencyHz, float[] frequenciesHz,
+                float[] outputAccelerationsGs) {
+
+            mResonantFrequencyHz = resonantFrequencyHz;
+
+            boolean isValid = !Float.isNaN(resonantFrequencyHz)
+                    && (resonantFrequencyHz > 0)
+                    && (frequenciesHz != null && outputAccelerationsGs != null)
+                    && (frequenciesHz.length == outputAccelerationsGs.length)
+                    && (frequenciesHz.length > 0);
+
+            if (!isValid) {
+                mFrequenciesHz = null;
+                mOutputAccelerationsGs = null;
+                mMinFrequencyHz = Float.NaN;
+                mMaxFrequencyHz = Float.NaN;
+                mMaxOutputAccelerationGs = Float.NaN;
+                return;
+            }
+
+            TreeMap<Float, Float> frequencyToOutputAccelerationMap = new TreeMap<>();
+
+            for (int i = 0; i < frequenciesHz.length; i++) {
+                frequencyToOutputAccelerationMap.putIfAbsent(frequenciesHz[i],
+                        outputAccelerationsGs[i]);
+            }
+
+            float[] frequencies = new float[frequencyToOutputAccelerationMap.size()];
+            float[] accelerations = new float[frequencyToOutputAccelerationMap.size()];
+            float maxOutputAccelerationGs = 0;
+            int i = 0;
+            for (Map.Entry<Float, Float> entry : frequencyToOutputAccelerationMap.entrySet()) {
+                frequencies[i] = entry.getKey();
+                accelerations[i] = entry.getValue();
+                maxOutputAccelerationGs = Math.max(maxOutputAccelerationGs, entry.getValue());
+                i++;
+            }
+
+            mFrequenciesHz = frequencies;
+            mOutputAccelerationsGs = accelerations;
+            mMinFrequencyHz = mFrequenciesHz[0];
+            mMaxFrequencyHz = mFrequenciesHz[mFrequenciesHz.length - 1];
+            mMaxOutputAccelerationGs = maxOutputAccelerationGs;
+        }
+
+        /** Returns true if the supported frequency range is null. */
+        public boolean isEmpty() {
+            return mFrequenciesHz == null;
+        }
+
+        /**
+         * Returns a list of available frequencies.
+         */
+        @Nullable
+        public float[] getFrequenciesHz() {
+            return mFrequenciesHz;
+        }
+
+        /** Returns the list of available output accelerations */
+        @Nullable
+        public float[] getOutputAccelerationsGs() {
+            return mOutputAccelerationsGs;
+        }
+
+        /** Maximum output acceleration reachable in Gs when amplitude is 1.0f. */
+        public float getMaxOutputAccelerationGs() {
+            return mMaxOutputAccelerationGs;
+        }
+
+        /**
+         * Calculates the maximum output acceleration for a given frequency using linear
+         * interpolation.
+         *
+         * @param frequencyHz frequency, in hertz, for query.
+         * @return the maximum output acceleration for the given frequency.
+         */
+        public float getOutputAccelerationGs(float frequencyHz) {
+            if (mFrequenciesHz == null) {
+                return Float.NaN;
+            }
+
+            if (frequencyHz < mMinFrequencyHz || frequencyHz > mMaxFrequencyHz) {
+                // Outside supported frequency range, not able to vibrate at this frequency.
+                return 0;
+            }
+
+            int idx = Arrays.binarySearch(mFrequenciesHz, frequencyHz);
+            if (idx >= 0) {
+                return mOutputAccelerationsGs[idx];
+            }
+
+            // This indicates that the value was not found in the list. Adjust index of the
+            // insertion point to be at the lower bound.
+            idx = -idx - 2;
+
+            // Linearly interpolate the output acceleration based on the frequency.
+            return MathUtils.constrainedMap(
+                    mOutputAccelerationsGs[idx], mOutputAccelerationsGs[idx + 1],
+                    mFrequenciesHz[idx], mFrequenciesHz[idx + 1],
+                    frequencyHz);
+        }
+
+        /** The minimum frequency supported, in hertz. */
+        public float getMinFrequencyHz() {
+            return mMinFrequencyHz;
+        }
+
+        /** The maximum frequency supported, in hertz. */
+        public float getMaxFrequencyHz() {
+            return mMaxFrequencyHz;
+        }
+
+        /**
+         * Returns the frequency range that supports the specified minimum output
+         * acceleration.
+         *
+         * @return The frequency range, or null if the specified acceleration
+         *         is not achievable on the device.
+         */
+        @Nullable
+        public Range<Float> getFrequencyRangeHz(float minOutputAcceleration) {
+            if (mFrequenciesHz == null || mOutputAccelerationsGs == null
+                    || minOutputAcceleration > mMaxOutputAccelerationGs) {
+                return null; // No frequency range available
+            }
+
+            if (minOutputAcceleration <= 0) {
+                return new Range<>(mMinFrequencyHz, mMaxFrequencyHz);
+            }
+
+            float minFrequency = Float.NaN;
+            float maxFrequency = Float.NaN;
+            int lowerFrequencyBoundIndex = 0;
+            // Find the lower frequency bound
+            for (int i = 0; i < mOutputAccelerationsGs.length; i++) {
+                if (mOutputAccelerationsGs[i] >= minOutputAcceleration) {
+                    if (i == 0) {
+                        minFrequency = mMinFrequencyHz;
+                    } else {
+                        minFrequency = MathUtils.constrainedMap(
+                                mFrequenciesHz[i - 1], mFrequenciesHz[i],
+                                mOutputAccelerationsGs[i - 1], mOutputAccelerationsGs[i],
+                                minOutputAcceleration);
+                    }
+                    lowerFrequencyBoundIndex = i;
+                    break; // Found the lower bound
+                }
+            }
+
+            if (Float.isNaN(minFrequency)) {
+                // Lower bound was not found
+                return null;
+            }
+
+            // Find the upper frequency bound
+            for (int i = lowerFrequencyBoundIndex; i < mOutputAccelerationsGs.length; i++) {
+                if (mOutputAccelerationsGs[i] <= minOutputAcceleration) {
+                    maxFrequency = MathUtils.constrainedMap(
+                            mFrequenciesHz[i - 1], mFrequenciesHz[i],
+                            mOutputAccelerationsGs[i - 1], mOutputAccelerationsGs[i],
+                            minOutputAcceleration);
+                    break; // Found the upper bound
+                }
+            }
+
+            if (Float.isNaN(maxFrequency)) {
+                // If the upper bound was not found, the specified output acceleration is
+                // achievable at all remaining frequencies.
+                maxFrequency = mMaxFrequencyHz;
+            }
+
+            return new Range<>(minFrequency, maxFrequency);
+        }
+
+        @Override
+        public void writeToParcel(Parcel dest, int flags) {
+            dest.writeFloat(mResonantFrequencyHz);
+            dest.writeFloatArray(mFrequenciesHz);
+            dest.writeFloatArray(mOutputAccelerationsGs);
+        }
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) {
+                return true;
+            }
+            if (!(o instanceof FrequencyProfile that)) {
+                return false;
+            }
+            return Float.compare(mResonantFrequencyHz, that.mResonantFrequencyHz) == 0
+                    && Arrays.equals(mFrequenciesHz, that.mFrequenciesHz)
+                    && Arrays.equals(mOutputAccelerationsGs, that.mOutputAccelerationsGs);
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(mResonantFrequencyHz, Arrays.hashCode(mFrequenciesHz),
+                    Arrays.hashCode(mOutputAccelerationsGs));
+        }
+
+        @Override
+        public String toString() {
+            return "FrequencyProfile{"
+                    + "mResonantFrequency=" + mResonantFrequencyHz
+                    + ", mFrequenciesHz=" + Arrays.toString(mFrequenciesHz)
+                    + ", mOutputAccelerationsGs=" + Arrays.toString(mOutputAccelerationsGs)
+                    + ", mMinFrequencyHz=" + mMinFrequencyHz
+                    + ", mMaxFrequencyHz=" + mMaxFrequencyHz
+                    + ", mMaxOutputAccelerationGs=" + mMaxOutputAccelerationGs
+                    + '}';
+        }
+
+        @NonNull
+        public static final Creator<FrequencyProfile> CREATOR =
+                new Creator<FrequencyProfile>() {
+                    @Override
+                    public FrequencyProfile createFromParcel(Parcel in) {
+                        return new FrequencyProfile(in);
+                    }
+
+                    @Override
+                    public FrequencyProfile[] newArray(int size) {
+                        return new FrequencyProfile[size];
+                    }
+                };
+
+        private static void deduplicateAndSortList(List<Pair<Float, Float>> list) {
+            if (list == null || list.size() < 2) {
+                return; // Nothing to dedupe
+            }
+
+            list.sort(Comparator.comparing(pair -> pair.first));
+
+            // Remove duplicates from the list
+            int writeIndex = 1;
+            for (int i = 1; i < list.size(); i++) {
+                Pair<Float, Float> currentPair = list.get(i);
+                Pair<Float, Float> previousPair = list.get(writeIndex - 1);
+
+                if (currentPair.first.compareTo(previousPair.first) != 0) {
+                    list.set(writeIndex++, currentPair);
+                }
+            }
+            list.subList(writeIndex, list.size()).clear();
+        }
+
+        private static ArrayList<Pair<Float, Float>> extractFrequencyToOutputAccelerationData(
+                float[] frequencies, float[] outputAccelerations) {
+
+            if (frequencies == null || outputAccelerations == null
+                    || frequencies.length == 0
+                    || frequencies.length != outputAccelerations.length) {
+                return new ArrayList<>(); // Return empty list for invalid or mismatched data
+            }
+
+            ArrayList<Pair<Float, Float>> frequencyToOutputAccelerationList = new ArrayList<>(
+                    frequencies.length);
+            for (int i = 0; i < frequencies.length; i++) {
+                frequencyToOutputAccelerationList.add(
+                        new Pair<>(frequencies[i], outputAccelerations[i]));
+            }
+
+            return frequencyToOutputAccelerationList;
+        }
+    }
+
+    /**
      * Describes the maximum relative output acceleration that can be achieved for each supported
      * frequency in a specific vibrator.
      *
@@ -640,7 +977,7 @@
      *
      * @hide
      */
-    public static final class FrequencyProfile implements Parcelable {
+    public static final class FrequencyProfileLegacy implements Parcelable {
         @Nullable
         private final Range<Float> mFrequencyRangeHz;
         private final float mMinFrequencyHz;
@@ -648,7 +985,7 @@
         private final float mFrequencyResolutionHz;
         private final float[] mMaxAmplitudes;
 
-        FrequencyProfile(Parcel in) {
+        FrequencyProfileLegacy(Parcel in) {
             this(in.readFloat(), in.readFloat(), in.readFloat(), in.createFloatArray());
         }
 
@@ -664,7 +1001,7 @@
          *                              resolution.
          * @hide
          */
-        public FrequencyProfile(float resonantFrequencyHz, float minFrequencyHz,
+        public FrequencyProfileLegacy(float resonantFrequencyHz, float minFrequencyHz,
                 float frequencyResolutionHz, float[] maxAmplitudes) {
             mMinFrequencyHz = minFrequencyHz;
             mResonantFrequencyHz = resonantFrequencyHz;
@@ -776,10 +1113,10 @@
             if (this == o) {
                 return true;
             }
-            if (!(o instanceof FrequencyProfile)) {
+            if (!(o instanceof FrequencyProfileLegacy)) {
                 return false;
             }
-            FrequencyProfile that = (FrequencyProfile) o;
+            FrequencyProfileLegacy that = (FrequencyProfileLegacy) o;
             return Float.compare(mMinFrequencyHz, that.mMinFrequencyHz) == 0
                     && Float.compare(mResonantFrequencyHz, that.mResonantFrequencyHz) == 0
                     && Float.compare(mFrequencyResolutionHz, that.mFrequencyResolutionHz) == 0
@@ -796,7 +1133,7 @@
 
         @Override
         public String toString() {
-            return "FrequencyProfile{"
+            return "FrequencyProfileLegacy{"
                     + "mFrequencyRange=" + mFrequencyRangeHz
                     + ", mMinFrequency=" + mMinFrequencyHz
                     + ", mResonantFrequency=" + mResonantFrequencyHz
@@ -806,16 +1143,16 @@
         }
 
         @NonNull
-        public static final Creator<FrequencyProfile> CREATOR =
-                new Creator<FrequencyProfile>() {
+        public static final Creator<FrequencyProfileLegacy> CREATOR =
+                new Creator<FrequencyProfileLegacy>() {
                     @Override
-                    public FrequencyProfile createFromParcel(Parcel in) {
-                        return new FrequencyProfile(in);
+                    public FrequencyProfileLegacy createFromParcel(Parcel in) {
+                        return new FrequencyProfileLegacy(in);
                     }
 
                     @Override
-                    public FrequencyProfile[] newArray(int size) {
-                        return new FrequencyProfile[size];
+                    public FrequencyProfileLegacy[] newArray(int size) {
+                        return new FrequencyProfileLegacy[size];
                     }
                 };
     }
@@ -832,8 +1169,10 @@
         private int mPwlePrimitiveDurationMax;
         private int mPwleSizeMax;
         private float mQFactor = Float.NaN;
-        private FrequencyProfile mFrequencyProfile =
-                new FrequencyProfile(Float.NaN, Float.NaN, Float.NaN, null);
+        private FrequencyProfileLegacy mFrequencyProfileLegacy =
+                new FrequencyProfileLegacy(Float.NaN, Float.NaN, Float.NaN, null);
+        private FrequencyProfile mFrequencyProfile = new FrequencyProfile(Float.NaN, null,
+                null);
         private int mMaxEnvelopeEffectSize;
         private int mMinEnvelopeEffectControlPointDurationMillis;
         private int mMaxEnvelopeEffectControlPointDurationMillis;
@@ -908,6 +1247,16 @@
 
         /** Configure the vibrator frequency information like resonant frequency and bandwidth. */
         @NonNull
+        public Builder setFrequencyProfileLegacy(@NonNull FrequencyProfileLegacy frequencyProfile) {
+            mFrequencyProfileLegacy = frequencyProfile;
+            return this;
+        }
+
+        /**
+         * Configure the vibrator frequency information like resonant frequency and frequency to
+         * output acceleration data.
+         */
+        @NonNull
         public Builder setFrequencyProfile(@NonNull FrequencyProfile frequencyProfile) {
             mFrequencyProfile = frequencyProfile;
             return this;
@@ -950,8 +1299,9 @@
         public VibratorInfo build() {
             return new VibratorInfo(mId, mCapabilities, mSupportedEffects, mSupportedBraking,
                     mSupportedPrimitives, mPrimitiveDelayMax, mCompositionSizeMax,
-                    mPwlePrimitiveDurationMax, mPwleSizeMax, mQFactor, mFrequencyProfile,
-                    mMaxEnvelopeEffectSize, mMinEnvelopeEffectControlPointDurationMillis,
+                    mPwlePrimitiveDurationMax, mPwleSizeMax, mQFactor, mFrequencyProfileLegacy,
+                    mFrequencyProfile, mMaxEnvelopeEffectSize,
+                    mMinEnvelopeEffectControlPointDurationMillis,
                     mMaxEnvelopeEffectControlPointDurationMillis);
         }
 
diff --git a/core/java/android/os/flags.aconfig b/core/java/android/os/flags.aconfig
index a1bfe39..c7cc653 100644
--- a/core/java/android/os/flags.aconfig
+++ b/core/java/android/os/flags.aconfig
@@ -2,87 +2,7 @@
 container: "system"
 container: "system"
 
-flag {
-    name: "android_os_build_vanilla_ice_cream"
-    is_exported: true
-    namespace: "build"
-    description: "Feature flag for adding the VANILLA_ICE_CREAM constant."
-    bug: "264658905"
-}
-
-flag {
-    name: "state_of_health_public"
-    is_exported: true
-    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."
-    bug: "276752881"
-}
-
-flag {
-    name: "remove_app_profiler_pss_collection"
-    is_exported: true
-    namespace: "backstage_power"
-    description: "Replaces background PSS collection in AppProfiler with RSS"
-    bug: "297542292"
-}
-
-flag {
-    name: "allow_thermal_headroom_thresholds"
-    is_exported: true
-    namespace: "game"
-    description: "Enable thermal headroom thresholds API"
-    bug: "288119641"
-}
-
-# This flag guards the private space feature, its APIs, and some of the feature implementations. The flag android.multiuser.Flags.enable_private_space_features exclusively guards all the implementations.
-flag {
-    name: "allow_private_profile"
-    is_exported: true
-    namespace: "profile_experiences"
-    description: "Guards a new Private Profile type in UserManager - everything from its setup to config to deletion."
-    bug: "299069460"
-    is_exported: true
-}
-
-flag {
-    name: "adpf_prefer_power_efficiency"
-    is_exported: true
-    namespace: "game"
-    description: "Guards the ADPF power efficiency API"
-    bug: "288117936"
-}
-
-flag {
-    name: "security_state_service"
-    is_exported: true
-    namespace: "dynamic_spl"
-    description: "Guards the Security State API."
-    bug: "302189431"
-}
-
-flag {
-    name: "ordered_broadcast_multiple_permissions"
-    is_exported: true
-    namespace: "bluetooth"
-    description: "Guards the Context.sendOrderedBroadcastMultiplePermissions API"
-    bug: "345802719"
-}
-
-flag {
-    name: "battery_saver_supported_check_api"
-    is_exported: true
-    namespace: "backstage_power"
-    description: "Guards a new API in PowerManager to check if battery saver is supported or not."
-    bug: "305067031"
-}
-
+# keep-sorted start block=yes newline_separated=yes
 flag {
     name: "adpf_gpu_report_actual_work_duration"
     is_exported: true
@@ -92,21 +12,6 @@
 }
 
 flag {
-    name: "adpf_use_fmq_channel"
-    namespace: "game"
-    description: "Guards use of the FMQ channel for ADPF"
-    bug: "315894228"
-}
-
-flag {
-    name: "adpf_use_fmq_channel_fixed"
-    namespace: "game"
-    description: "Guards use of the FMQ channel for ADPF with a readonly flag"
-    is_fixed_read_only: true
-    bug: "315894228"
-}
-
-flag {
     name: "adpf_hwui_gpu"
     namespace: "game"
     description: "Guards use of the FMQ channel for ADPF"
@@ -115,6 +20,13 @@
 }
 
 flag {
+    name: "adpf_measure_during_input_event_boost"
+    namespace: "game"
+    description: "Guards use of a boost when view measures during input events"
+    bug: "256549451"
+}
+
+flag {
     name: "adpf_obtainview_boost"
     namespace: "game"
     description: "Guards use of a boost in response to HWUI obtainView"
@@ -131,41 +43,67 @@
 }
 
 flag {
-    name: "adpf_measure_during_input_event_boost"
-    namespace: "game"
-    description: "Guards use of a boost when view measures during input events"
-    bug: "256549451"
-}
-
-flag {
-    name: "battery_service_support_current_adb_command"
-    namespace: "backstage_power"
-    description: "Whether or not BatteryService supports adb commands for Current values."
-    is_fixed_read_only: true
-    bug: "315037695"
-}
-
-flag {
-    name: "strict_mode_restricted_network"
-    namespace: "backstage_power"
-    description: "Guards StrictMode APIs for detecting restricted network access."
-    bug: "317250784"
-}
-
-flag {
-    name: "binder_frozen_state_change_callback"
+    name: "adpf_prefer_power_efficiency"
     is_exported: true
-    namespace: "system_performance"
-    description: "Guards the frozen state change callback API."
-    bug: "361157077"
+    namespace: "game"
+    description: "Guards the ADPF power efficiency API"
+    bug: "288117936"
 }
 
 flag {
-    name: "message_queue_tail_tracking"
-    namespace: "system_performance"
-    description: "track tail of message queue."
-    bug: "305311707"
+    name: "adpf_use_fmq_channel"
+    namespace: "game"
+    description: "Guards use of the FMQ channel for ADPF"
+    bug: "315894228"
+}
+
+flag {
+    name: "adpf_use_fmq_channel_fixed"
+    namespace: "game"
+    description: "Guards use of the FMQ channel for ADPF with a readonly flag"
     is_fixed_read_only: true
+    bug: "315894228"
+}
+
+flag {
+    name: "allow_consentless_bugreport_delegated_consent"
+    namespace: "crumpet"
+    description: "Allow privileged apps to call bugreport generation without enforcing user consent and delegate it to the calling app instead"
+    bug: "324046728"
+}
+
+# This flag guards the private space feature, its APIs, and some of the feature implementations. The flag android.multiuser.Flags.enable_private_space_features exclusively guards all the implementations.
+flag {
+    name: "allow_private_profile"
+    is_exported: true
+    namespace: "profile_experiences"
+    description: "Guards a new Private Profile type in UserManager - everything from its setup to config to deletion."
+    bug: "299069460"
+    is_exported: true
+}
+
+flag {
+    name: "allow_thermal_headroom_thresholds"
+    is_exported: true
+    namespace: "game"
+    description: "Enable thermal headroom thresholds API"
+    bug: "288119641"
+}
+
+flag {
+    name: "android_os_build_vanilla_ice_cream"
+    is_exported: true
+    namespace: "build"
+    description: "Feature flag for adding the VANILLA_ICE_CREAM constant."
+    bug: "264658905"
+}
+
+flag {
+    name: "api_for_backported_fixes"
+    namespace: "media_reliability"
+    description: "Public API app developers use to check if a known issue is fixed on a device."
+    bug: "308461809"
+    is_exported: true
 }
 
 flag {
@@ -178,35 +116,42 @@
 }
 
 flag {
-    name: "storage_lifetime_api"
+    name: "battery_saver_supported_check_api"
     is_exported: true
-    namespace: "phoenix"
-    description: "Feature flag for adding storage component health APIs."
+    namespace: "backstage_power"
+    description: "Guards a new API in PowerManager to check if battery saver is supported or not."
+    bug: "305067031"
+}
+
+flag {
+    name: "battery_service_support_current_adb_command"
+    namespace: "backstage_power"
+    description: "Whether or not BatteryService supports adb commands for Current values."
     is_fixed_read_only: true
-    bug: "309792384"
+    bug: "315037695"
 }
 
 flag {
-     namespace: "system_performance"
-     name: "telemetry_apis_framework_initialization"
-     is_exported: true
-     description: "Control framework initialization APIs of telemetry APIs feature."
-     is_fixed_read_only: true
-     bug: "324241334"
+    name: "binder_frozen_state_change_callback"
+    is_exported: true
+    namespace: "system_performance"
+    description: "Guards the frozen state change callback API."
+    bug: "361157077"
 }
 
 flag {
-     namespace: "system_performance"
-     name: "perfetto_sdk_tracing"
-     description: "Tracing using Perfetto SDK."
-     bug: "303199244"
+    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."
+    bug: "276752881"
 }
 
 flag {
-    name: "allow_consentless_bugreport_delegated_consent"
-    namespace: "crumpet"
-    description: "Allow privileged apps to call bugreport generation without enforcing user consent and delegate it to the calling app instead"
-    bug: "324046728"
+    name: "enable_angle_allow_list"
+    namespace: "gpu"
+    description: "Whether to read from angle allowlist to determine if app should use ANGLE"
+    is_fixed_read_only: true
+    bug: "370845648"
 }
 
 flag {
@@ -226,9 +171,83 @@
 }
 
 flag {
+    name: "message_queue_tail_tracking"
+    namespace: "system_performance"
+    description: "track tail of message queue."
+    bug: "305311707"
+    is_fixed_read_only: true
+}
+
+flag {
     name: "network_time_uses_shared_memory"
     namespace: "system_performance"
     description: "SystemClock.currentNetworkTimeMillis() reads network time offset from shared memory"
     bug: "361329788"
     is_exported: true
 }
+
+flag {
+    name: "ordered_broadcast_multiple_permissions"
+    is_exported: true
+    namespace: "bluetooth"
+    description: "Guards the Context.sendOrderedBroadcastMultiplePermissions API"
+    bug: "345802719"
+}
+
+flag {
+    name: "remove_app_profiler_pss_collection"
+    is_exported: true
+    namespace: "backstage_power"
+    description: "Replaces background PSS collection in AppProfiler with RSS"
+    bug: "297542292"
+}
+
+flag {
+    name: "security_state_service"
+    is_exported: true
+    namespace: "dynamic_spl"
+    description: "Guards the Security State API."
+    bug: "302189431"
+}
+
+flag {
+    name: "state_of_health_public"
+    is_exported: true
+    namespace: "system_sw_battery"
+    description: "Feature flag for making state_of_health a public api."
+    bug: "288842045"
+}
+
+flag {
+    name: "storage_lifetime_api"
+    is_exported: true
+    namespace: "phoenix"
+    description: "Feature flag for adding storage component health APIs."
+    is_fixed_read_only: true
+    bug: "309792384"
+}
+
+flag {
+    name: "strict_mode_restricted_network"
+    namespace: "backstage_power"
+    description: "Guards StrictMode APIs for detecting restricted network access."
+    bug: "317250784"
+}
+
+flag {
+     namespace: "system_performance"
+     name: "perfetto_sdk_tracing"
+     description: "Tracing using Perfetto SDK."
+     bug: "303199244"
+}
+
+flag {
+     namespace: "system_performance"
+     name: "telemetry_apis_framework_initialization"
+     is_exported: true
+     description: "Control framework initialization APIs of telemetry APIs feature."
+     is_fixed_read_only: true
+     bug: "324241334"
+}
+
+# keep-sorted end
diff --git a/core/java/android/os/vibrator/MultiVibratorInfo.java b/core/java/android/os/vibrator/MultiVibratorInfo.java
index 9c2b978..1ba8d99 100644
--- a/core/java/android/os/vibrator/MultiVibratorInfo.java
+++ b/core/java/android/os/vibrator/MultiVibratorInfo.java
@@ -27,6 +27,9 @@
 import android.util.SparseIntArray;
 
 import java.util.Arrays;
+import java.util.Iterator;
+import java.util.Set;
+import java.util.TreeSet;
 import java.util.function.Function;
 
 /**
@@ -44,13 +47,18 @@
     private static final float EPSILON = 1e-5f;
 
     public MultiVibratorInfo(int id, VibratorInfo[] vibrators) {
-        this(id, vibrators, frequencyProfileIntersection(vibrators));
+        this(id, vibrators, frequencyProfileLegacyIntersection(vibrators),
+                frequencyProfileIntersection(vibrators));
     }
 
     private MultiVibratorInfo(
-            int id, VibratorInfo[] vibrators, VibratorInfo.FrequencyProfile mergedProfile) {
+            int id, VibratorInfo[] vibrators,
+            VibratorInfo.FrequencyProfileLegacy mergedLegacyProfile,
+            FrequencyProfile mergedProfile) {
         super(id,
-                capabilitiesIntersection(vibrators, mergedProfile.isEmpty()),
+                capabilitiesIntersection(vibrators,
+                        Flags.normalizedPwleEffects() ? mergedProfile.isEmpty()
+                                : mergedLegacyProfile.isEmpty()),
                 supportedEffectsIntersection(vibrators),
                 supportedBrakingIntersection(vibrators),
                 supportedPrimitivesAndDurationsIntersection(vibrators),
@@ -59,6 +67,7 @@
                 integerLimitIntersection(vibrators, VibratorInfo::getPwlePrimitiveDurationMax),
                 integerLimitIntersection(vibrators, VibratorInfo::getPwleSizeMax),
                 floatPropertyIntersection(vibrators, VibratorInfo::getQFactor),
+                mergedLegacyProfile,
                 mergedProfile,
                 integerLimitIntersection(vibrators,
                         VibratorInfo::getMaxEnvelopeEffectSize),
@@ -210,14 +219,89 @@
 
     @NonNull
     private static FrequencyProfile frequencyProfileIntersection(VibratorInfo[] infos) {
+        if (infos == null || infos.length == 0) {
+            return new FrequencyProfile(Float.NaN,
+                    /*frequenciesHz=*/ null, /*outputAccelerationsGs=*/ null);
+        }
+
+        float resonantFreq = floatPropertyIntersection(infos, VibratorInfo::getResonantFrequencyHz);
+
+        if (Float.isNaN(resonantFreq)) {
+            return new FrequencyProfile(Float.NaN,
+                    /*frequenciesHz=*/ null, /*outputAccelerationsGs=*/ null);
+        }
+
+        float minFrequency = 0.0f;
+        float maxFrequency = Float.MAX_VALUE;
+        Set<Float> allFrequencies = new TreeSet<>(); // Using TreeSet for automatic sorting
+
+        for (VibratorInfo info : infos) {
+            float newMinFrequency = info.getFrequencyProfile().getMinFrequencyHz();
+            float newMaxFrequency = info.getFrequencyProfile().getMaxFrequencyHz();
+
+            if (Float.isNaN(newMinFrequency) || Float.isNaN(newMaxFrequency)) {
+                // If one vibrator is undefined then the intersection is undefined.
+                return new FrequencyProfile(Float.NaN,
+                        /*frequenciesHz=*/ null, /*outputAccelerationsGs=*/ null);
+            }
+
+            minFrequency = Math.max(minFrequency, newMinFrequency);
+            maxFrequency = Math.min(maxFrequency, newMaxFrequency);
+
+            if (info.getFrequencyProfile().getFrequenciesHz() == null) {
+                return new FrequencyProfile(Float.NaN,
+                        /*frequenciesHz=*/ null, /*outputAccelerationsGs=*/ null);
+            }
+
+            for (float frequency : info.getFrequencyProfile().getFrequenciesHz()) {
+                allFrequencies.add(frequency);
+            }
+        }
+
+        if (minFrequency > maxFrequency) {
+            // If the range and intersection are disjoint then the intersection is undefined
+            return new FrequencyProfile(Float.NaN,
+                    /*frequenciesHz=*/ null, /*outputAccelerationsGs=*/ null);
+        }
+
+        // Trim frequencies to the min/max range
+        Iterator<Float> iterator = allFrequencies.iterator();
+        while (iterator.hasNext()) {
+            float frequency = iterator.next();
+            if (frequency < minFrequency || frequency > maxFrequency) {
+                iterator.remove();
+            }
+        }
+
+        float[] frequencies = new float[allFrequencies.size()];
+        float[] accelerations = new float[allFrequencies.size()];
+        int idx = 0;
+
+        for (Float frequency : allFrequencies) {
+            float outputAcceleration = Float.MAX_VALUE;
+            for (VibratorInfo info : infos) {
+                // This will find the mapped value or interpolate it if needed.
+                outputAcceleration = Math.min(outputAcceleration,
+                        info.getFrequencyProfile().getOutputAccelerationGs(frequency));
+            }
+            frequencies[idx] = frequency;
+            accelerations[idx] = outputAcceleration;
+            idx++;
+        }
+
+        return new FrequencyProfile(resonantFreq, frequencies, accelerations);
+    }
+
+    @NonNull
+    private static FrequencyProfileLegacy frequencyProfileLegacyIntersection(VibratorInfo[] infos) {
         float freqResolution = floatPropertyIntersection(infos,
-                info -> info.getFrequencyProfile().getFrequencyResolutionHz());
+                info -> info.getFrequencyProfileLegacy().getFrequencyResolutionHz());
         float resonantFreq = floatPropertyIntersection(infos,
                 VibratorInfo::getResonantFrequencyHz);
         Range<Float> freqRange = frequencyRangeIntersection(infos, freqResolution);
 
         if ((freqRange == null) || Float.isNaN(freqResolution)) {
-            return new FrequencyProfile(resonantFreq, Float.NaN, freqResolution, null);
+            return new FrequencyProfileLegacy(resonantFreq, Float.NaN, freqResolution, null);
         }
 
         int amplitudeCount =
@@ -230,8 +314,8 @@
         Arrays.fill(maxAmplitudes, Float.MAX_VALUE);
 
         for (VibratorInfo info : infos) {
-            Range<Float> vibratorFreqRange = info.getFrequencyProfile().getFrequencyRangeHz();
-            float[] vibratorMaxAmplitudes = info.getFrequencyProfile().getMaxAmplitudes();
+            Range<Float> vibratorFreqRange = info.getFrequencyProfileLegacy().getFrequencyRangeHz();
+            float[] vibratorMaxAmplitudes = info.getFrequencyProfileLegacy().getMaxAmplitudes();
             int vibratorStartIdx = Math.round(
                     (freqRange.getLower() - vibratorFreqRange.getLower()) / freqResolution);
             int vibratorEndIdx = vibratorStartIdx + maxAmplitudes.length - 1;
@@ -240,7 +324,7 @@
                 Slog.w(TAG, "Error calculating the intersection of vibrator frequency"
                         + " profiles: attempted to fetch from vibrator "
                         + info.getId() + " max amplitude with bad index " + vibratorStartIdx);
-                return new FrequencyProfile(resonantFreq, Float.NaN, Float.NaN, null);
+                return new FrequencyProfileLegacy(resonantFreq, Float.NaN, Float.NaN, null);
             }
 
             for (int i = 0; i < maxAmplitudes.length; i++) {
@@ -249,14 +333,14 @@
             }
         }
 
-        return new FrequencyProfile(resonantFreq, freqRange.getLower(),
+        return new FrequencyProfileLegacy(resonantFreq, freqRange.getLower(),
                 freqResolution, maxAmplitudes);
     }
 
     @Nullable
     private static Range<Float> frequencyRangeIntersection(VibratorInfo[] infos,
             float frequencyResolution) {
-        Range<Float> firstRange = infos[0].getFrequencyProfile().getFrequencyRangeHz();
+        Range<Float> firstRange = infos[0].getFrequencyProfileLegacy().getFrequencyRangeHz();
         if (firstRange == null) {
             // If one vibrator is undefined then the intersection is undefined.
             return null;
@@ -268,7 +352,7 @@
         // min supported frequencies are aligned w.r.t. the frequency resolution.
 
         for (int i = 1; i < infos.length; i++) {
-            Range<Float> vibratorRange = infos[i].getFrequencyProfile().getFrequencyRangeHz();
+            Range<Float> vibratorRange = infos[i].getFrequencyProfileLegacy().getFrequencyRangeHz();
             if (vibratorRange == null) {
                 // If one vibrator is undefined then the intersection is undefined.
                 return null;
diff --git a/core/java/android/os/vibrator/VibratorFrequencyProfile.java b/core/java/android/os/vibrator/VibratorFrequencyProfile.java
index 8392940..2b5f9bf 100644
--- a/core/java/android/os/vibrator/VibratorFrequencyProfile.java
+++ b/core/java/android/os/vibrator/VibratorFrequencyProfile.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2022 The Android Open Source Project
+ * Copyright (C) 2024 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,95 +16,135 @@
 
 package android.os.vibrator;
 
-import android.annotation.FloatRange;
+import android.annotation.FlaggedApi;
 import android.annotation.NonNull;
-import android.annotation.TestApi;
+import android.annotation.Nullable;
 import android.os.VibratorInfo;
+import android.util.Range;
+import android.util.SparseArray;
 
 import com.android.internal.util.Preconditions;
 
+import java.util.Objects;
+
 /**
  * Describes the output of a {@link android.os.Vibrator} for different vibration frequencies.
  *
- * <p>The profile contains the minimum and maximum supported vibration frequencies, if the device
- * supports independent frequency control.
+ * <p>The profile contains the vibrator's frequency range (minimum/maximum) and maximum
+ * acceleration, enabling retrieval of supported acceleration levels for specific frequencies, if
+ * the device supports independent frequency control.
  *
- * <p>It also describes the relative output acceleration of a vibration at different supported
- * frequencies. The acceleration is defined by a relative amplitude value between 0 and 1,
- * inclusive, where 0 represents the vibrator off state and 1 represents the maximum output
- * acceleration that the vibrator can reach across all supported frequencies.
- *
- * <p>The measurements are returned as an array of uniformly distributed amplitude values for
- * frequencies between the minimum and maximum supported ones. The measurement interval is the
- * frequency increment between each pair of amplitude values.
+ * <p>It also describes the max output acceleration (Gs), of a vibration at different supported
+ * frequencies (Hz).
  *
  * <p>Vibrators without independent frequency control do not have a frequency profile.
- * @hide
  */
-@TestApi
+@FlaggedApi(Flags.FLAG_NORMALIZED_PWLE_EFFECTS)
 public final class VibratorFrequencyProfile {
 
     private final VibratorInfo.FrequencyProfile mFrequencyProfile;
+    private final SparseArray<Float> mFrequenciesOutputAcceleration;
 
     /** @hide */
     public VibratorFrequencyProfile(@NonNull VibratorInfo.FrequencyProfile frequencyProfile) {
+        Objects.requireNonNull(frequencyProfile);
         Preconditions.checkArgument(!frequencyProfile.isEmpty(),
-                "Frequency profile must have a non-empty frequency range");
+                "Frequency profile must not be empty");
         mFrequencyProfile = frequencyProfile;
+        mFrequenciesOutputAcceleration = generateFrequencyToAccelerationMap(
+                frequencyProfile.getFrequenciesHz(), frequencyProfile.getOutputAccelerationsGs());
     }
 
     /**
-     * Measurements of the maximum relative amplitude the vibrator can achieve for each supported
-     * frequency.
+     * Returns a {@link SparseArray} representing the vibrator's output acceleration capabilities
+     * across different frequencies. This map defines the maximum acceleration
+     * the vibrator can achieve at each supported frequency.
+     * <p>The map's keys are frequencies in Hz, and the corresponding values
+     * are the maximum achievable output accelerations in Gs.
      *
-     * <p>The frequency of a measurement is determined as:
-     *
-     * {@code getMinFrequency() + measurementIndex * getMaxAmplitudeMeasurementInterval()}
-     *
-     * <p>The returned list will not be empty, and will have entries representing frequencies from
-     * {@link #getMinFrequency()} to {@link #getMaxFrequency()}, inclusive.
-     *
-     * @return Array of maximum relative amplitude measurements.
-     * @hide
+     * @return A map of frequencies (Hz) to maximum accelerations (Gs).
      */
-    @TestApi
+    @FlaggedApi(Flags.FLAG_NORMALIZED_PWLE_EFFECTS)
     @NonNull
-    @FloatRange(from = 0, to = 1)
-    public float[] getMaxAmplitudeMeasurements() {
-        // VibratorInfo getters always return a copy or clone of the data objects.
-        return mFrequencyProfile.getMaxAmplitudes();
+    public SparseArray<Float> getFrequenciesOutputAcceleration() {
+        return mFrequenciesOutputAcceleration;
     }
 
     /**
-     * Gets the frequency interval used to measure the maximum relative amplitudes.
+     * Returns the maximum output acceleration (in Gs) supported by the vibrator.
+     * This value represents the highest acceleration the vibrator can achieve
+     * across its entire frequency range.
      *
-     * @return the frequency interval used for the measurement, in hertz.
-     * @hide
+     * @return The maximum output acceleration in Gs.
      */
-    @TestApi
-    public float getMaxAmplitudeMeasurementInterval() {
-        return mFrequencyProfile.getFrequencyResolutionHz();
+    @FlaggedApi(Flags.FLAG_NORMALIZED_PWLE_EFFECTS)
+    public float getMaxOutputAccelerationGs() {
+        return mFrequencyProfile.getMaxOutputAccelerationGs();
+    }
+
+    /**
+     * Returns the frequency range (in Hz) where the vibrator can sustain at least
+     * the given minimum output acceleration (Gs).
+     *
+     * @param minOutputAccelerationGs The minimum desired output acceleration in Gs.
+     * @return A {@link Range} object representing the frequency range where the
+     *         vibrator can sustain at least the given minimum acceleration, or null if
+     *         the minimum output acceleration cannot be achieved.
+     *
+     */
+    @FlaggedApi(Flags.FLAG_NORMALIZED_PWLE_EFFECTS)
+    @Nullable
+    public Range<Float> getFrequencyRange(float minOutputAccelerationGs) {
+        return mFrequencyProfile.getFrequencyRangeHz(minOutputAccelerationGs);
+    }
+
+    /**
+     * Returns the output acceleration (in Gs) for the given frequency (Hz).
+     * This method provides the actual acceleration the vibrator will produce
+     * when operating at the specified frequency, using linear interpolation over
+     * the {@link #getFrequenciesOutputAcceleration()}.
+     *
+     * @param frequencyHz The frequency in Hz.
+     * @return The output acceleration in Gs for the given frequency.
+     */
+    @FlaggedApi(Flags.FLAG_NORMALIZED_PWLE_EFFECTS)
+    public float getOutputAccelerationGs(float frequencyHz) {
+        return mFrequencyProfile.getOutputAccelerationGs(frequencyHz);
     }
 
     /**
      * Gets the minimum frequency supported by the vibrator.
      *
      * @return the minimum frequency supported by the vibrator, in hertz.
-     * @hide
      */
-    @TestApi
-    public float getMinFrequency() {
-        return mFrequencyProfile.getFrequencyRangeHz().getLower();
+    @FlaggedApi(Flags.FLAG_NORMALIZED_PWLE_EFFECTS)
+    public float getMinFrequencyHz() {
+        return mFrequencyProfile.getMinFrequencyHz();
     }
 
     /**
      * Gets the maximum frequency supported by the vibrator.
      *
      * @return the maximum frequency supported by the vibrator, in hertz.
-     * @hide
      */
-    @TestApi
-    public float getMaxFrequency() {
-        return mFrequencyProfile.getFrequencyRangeHz().getUpper();
+    @FlaggedApi(Flags.FLAG_NORMALIZED_PWLE_EFFECTS)
+    public float getMaxFrequencyHz() {
+        return mFrequencyProfile.getMaxFrequencyHz();
+    }
+
+    private static SparseArray<Float> generateFrequencyToAccelerationMap(
+            float[] frequencies, float[] accelerations) {
+        SparseArray<Float> sparseArray = new SparseArray<>(frequencies.length);
+
+        for (int i = 0; i < frequencies.length; i++) {
+            int frequency = (int) frequencies[i];
+            float acceleration = accelerations[i];
+
+            sparseArray.put(frequency,
+                    Math.min(acceleration, sparseArray.get(frequency, Float.MAX_VALUE)));
+
+        }
+
+        return sparseArray;
     }
 }
diff --git a/core/java/android/os/vibrator/VibratorFrequencyProfileLegacy.java b/core/java/android/os/vibrator/VibratorFrequencyProfileLegacy.java
new file mode 100644
index 0000000..5c3e785
--- /dev/null
+++ b/core/java/android/os/vibrator/VibratorFrequencyProfileLegacy.java
@@ -0,0 +1,117 @@
+/*
+ * 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 android.os.vibrator;
+
+import android.annotation.FloatRange;
+import android.annotation.NonNull;
+import android.annotation.SuppressLint;
+import android.annotation.TestApi;
+import android.os.VibratorInfo;
+
+import com.android.internal.util.Preconditions;
+
+/**
+ * Describes the output of a {@link android.os.Vibrator} for different vibration frequencies.
+ *
+ * <p>The profile contains the minimum and maximum supported vibration frequencies, if the device
+ * supports independent frequency control.
+ *
+ * <p>It also describes the relative output acceleration of a vibration at different supported
+ * frequencies. The acceleration is defined by a relative amplitude value between 0 and 1,
+ * inclusive, where 0 represents the vibrator off state and 1 represents the maximum output
+ * acceleration that the vibrator can reach across all supported frequencies.
+ *
+ * <p>The measurements are returned as an array of uniformly distributed amplitude values for
+ * frequencies between the minimum and maximum supported ones. The measurement interval is the
+ * frequency increment between each pair of amplitude values.
+ *
+ * <p>Vibrators without independent frequency control do not have a frequency profile.
+ * @hide
+ */
+@TestApi
+@SuppressLint("UnflaggedApi")
+public final class VibratorFrequencyProfileLegacy {
+
+    private final VibratorInfo.FrequencyProfileLegacy mFrequencyProfile;
+
+    /** @hide */
+    public VibratorFrequencyProfileLegacy(
+            @NonNull VibratorInfo.FrequencyProfileLegacy frequencyProfile) {
+        Preconditions.checkArgument(!frequencyProfile.isEmpty(),
+                "Frequency profile must have a non-empty frequency range");
+        mFrequencyProfile = frequencyProfile;
+    }
+
+    /**
+     * Measurements of the maximum relative amplitude the vibrator can achieve for each supported
+     * frequency.
+     *
+     * <p>The frequency of a measurement is determined as:
+     *
+     * {@code getMinFrequency() + measurementIndex * getMaxAmplitudeMeasurementInterval()}
+     *
+     * <p>The returned list will not be empty, and will have entries representing frequencies from
+     * {@link #getMinFrequency()} to {@link #getMaxFrequency()}, inclusive.
+     *
+     * @return Array of maximum relative amplitude measurements.
+     * @hide
+     */
+    @TestApi
+    @SuppressLint("UnflaggedApi")
+    @NonNull
+    @FloatRange(from = 0, to = 1)
+    public float[] getMaxAmplitudeMeasurements() {
+        // VibratorInfo getters always return a copy or clone of the data objects.
+        return mFrequencyProfile.getMaxAmplitudes();
+    }
+
+    /**
+     * Gets the frequency interval used to measure the maximum relative amplitudes.
+     *
+     * @return the frequency interval used for the measurement, in hertz.
+     * @hide
+     */
+    @TestApi
+    @SuppressLint("UnflaggedApi")
+    public float getMaxAmplitudeMeasurementInterval() {
+        return mFrequencyProfile.getFrequencyResolutionHz();
+    }
+
+    /**
+     * Gets the minimum frequency supported by the vibrator.
+     *
+     * @return the minimum frequency supported by the vibrator, in hertz.
+     * @hide
+     */
+    @TestApi
+    @SuppressLint("UnflaggedApi")
+    public float getMinFrequency() {
+        return mFrequencyProfile.getFrequencyRangeHz().getLower();
+    }
+
+    /**
+     * Gets the maximum frequency supported by the vibrator.
+     *
+     * @return the maximum frequency supported by the vibrator, in hertz.
+     * @hide
+     */
+    @TestApi
+    @SuppressLint("UnflaggedApi")
+    public float getMaxFrequency() {
+        return mFrequencyProfile.getFrequencyRangeHz().getUpper();
+    }
+}
diff --git a/core/java/android/permission/flags.aconfig b/core/java/android/permission/flags.aconfig
index bca5bcc..e59501f 100644
--- a/core/java/android/permission/flags.aconfig
+++ b/core/java/android/permission/flags.aconfig
@@ -206,17 +206,6 @@
 }
 
 flag {
-    name: "apex_signature_permission_allowlist_enabled"
-    is_fixed_read_only: true
-    namespace: "permissions"
-    description: "Enable reading signature permission allowlist from APEXes"
-    bug: "308573169"
-    metadata {
-        purpose: PURPOSE_BUGFIX
-    }
-}
-
-flag {
     name: "check_op_validate_package"
     namespace: "permissions"
     description: "Validate package/uid match in checkOp similar to noteOp"
@@ -243,6 +232,13 @@
 }
 
 flag {
+  name: "sync_on_op_noted_api"
+  namespace: "permissions"
+  description: "New setOnOpNotedCallback API to allow subscribing to only sync ops."
+  bug: "372910217"
+}
+
+flag {
     name: "wallet_role_icon_property_enabled"
     is_exported: true
     namespace: "wallet_integration"
@@ -266,3 +262,14 @@
     description: "This fixed read-only flag is used to enable replacing permission BODY_SENSORS (and BODY_SENSORS_BACKGROUND) with granular health permission READ_HEART_RATE (and READ_HEALTH_DATA_IN_BACKGROUND)"
     bug: "364638912"
 }
+
+flag {
+    name: "delay_uid_state_changes_from_capability_updates"
+    is_fixed_read_only: true
+    namespace: "permissions"
+    description: "If proc state is decreasing over the restriction threshold and capability is changed, delay if no new capabilities are added"
+    bug: "347891382"
+    metadata {
+        purpose: PURPOSE_BUGFIX
+    }
+}
diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
index d557046..5ecf361 100644
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -3028,6 +3028,13 @@
         @FlaggedApi(Flags.FLAG_NEW_DEFAULT_ACCOUNT_API_ENABLED)
         public static final class DefaultAccount {
             /**
+             * no public constructor since this is a utility class
+             */
+            private DefaultAccount() {
+
+            }
+
+            /**
              * Key in the outgoing Bundle for the default account list.
              *
              * @hide
@@ -3063,11 +3070,6 @@
             public static final String QUERY_DEFAULT_ACCOUNT_FOR_NEW_CONTACTS_METHOD =
                     "queryDefaultAccountForNewContacts";
 
-            private DefaultAccount() {
-
-            }
-
-
             /**
              * Represents the state of the default account, and the actual {@link Account} if it's
              * a cloud account.
@@ -3207,7 +3209,11 @@
                     return new DefaultAccountAndState(DEFAULT_ACCOUNT_STATE_NOT_SET, null);
                 }
 
-                private static boolean isCloudOrSimAccount(@DefaultAccountState int state) {
+                /**
+                 *
+                 * @hide
+                 */
+                public static boolean isCloudOrSimAccount(@DefaultAccountState int state) {
                     return state == DEFAULT_ACCOUNT_STATE_CLOUD
                             || state == DEFAULT_ACCOUNT_STATE_SIM;
                 }
@@ -3285,23 +3291,20 @@
                 Bundle response = nullSafeCall(resolver, ContactsContract.AUTHORITY_URI,
                         QUERY_DEFAULT_ACCOUNT_FOR_NEW_CONTACTS_METHOD, null, null);
 
-                int defaultContactsAccountState = response.getInt(KEY_DEFAULT_ACCOUNT_STATE, -1);
-                if (defaultContactsAccountState
-                        == DefaultAccountAndState.DEFAULT_ACCOUNT_STATE_CLOUD) {
+                int defaultAccountState = response.getInt(KEY_DEFAULT_ACCOUNT_STATE, -1);
+                if (DefaultAccountAndState.isCloudOrSimAccount(defaultAccountState)) {
                     String accountName = response.getString(Settings.ACCOUNT_NAME);
                     String accountType = response.getString(Settings.ACCOUNT_TYPE);
                     if (TextUtils.isEmpty(accountName) || TextUtils.isEmpty(accountType)) {
                         throw new IllegalStateException(
                                 "account name and type cannot be null or empty");
                     }
-                    return new DefaultAccountAndState(
-                            DefaultAccountAndState.DEFAULT_ACCOUNT_STATE_CLOUD,
+                    return new DefaultAccountAndState(defaultAccountState,
                             new Account(accountName, accountType));
-                } else if (defaultContactsAccountState
-                        == DefaultAccountAndState.DEFAULT_ACCOUNT_STATE_LOCAL
-                        || defaultContactsAccountState
+                } else if (defaultAccountState == DefaultAccountAndState.DEFAULT_ACCOUNT_STATE_LOCAL
+                        || defaultAccountState
                         == DefaultAccountAndState.DEFAULT_ACCOUNT_STATE_NOT_SET) {
-                    return new DefaultAccountAndState(defaultContactsAccountState, /*cloudAccount=*/
+                    return new DefaultAccountAndState(defaultAccountState, /*account=*/
                             null);
                 } else {
                     throw new IllegalStateException("Invalid default account state");
@@ -3346,16 +3349,197 @@
                 Bundle extras = new Bundle();
 
                 extras.putInt(KEY_DEFAULT_ACCOUNT_STATE, defaultAccountAndState.getState());
-                if (defaultAccountAndState.getState()
-                        == DefaultAccountAndState.DEFAULT_ACCOUNT_STATE_CLOUD) {
-                    Account cloudAccount = defaultAccountAndState.getAccount();
-                    assert cloudAccount != null;
-                    extras.putString(Settings.ACCOUNT_NAME, cloudAccount.name);
-                    extras.putString(Settings.ACCOUNT_TYPE, cloudAccount.type);
+                if (DefaultAccountAndState.isCloudOrSimAccount(defaultAccountAndState.getState())) {
+                    Account account = defaultAccountAndState.getAccount();
+                    assert account != null;
+                    extras.putString(Settings.ACCOUNT_NAME, account.name);
+                    extras.putString(Settings.ACCOUNT_TYPE, account.type);
                 }
                 nullSafeCall(resolver, ContactsContract.AUTHORITY_URI,
                         SET_DEFAULT_ACCOUNT_FOR_NEW_CONTACTS_METHOD, null, extras);
             }
+
+            /**
+             * Get a list of cloud accounts that is eligible to set as default account with state of
+             * {@link DefaultAccountAndState#DEFAULT_ACCOUNT_STATE_CLOUD}. May be empty but never
+             * null.
+             *
+             * @param resolver content resolver to query.
+             * @return a of cloud accounts that is eligible to set as default account with state of
+             * {@link DefaultAccountAndState#DEFAULT_ACCOUNT_STATE_CLOUD}.
+             * @throws RuntimeException if the query fails.
+             *
+             * @hide
+             */
+            @RequiresPermission(android.Manifest.permission.SET_DEFAULT_ACCOUNT_FOR_CONTACTS)
+            @FlaggedApi(Flags.FLAG_NEW_DEFAULT_ACCOUNT_API_ENABLED)
+            @SystemApi
+            public static @NonNull List<Account> getEligibleCloudAccounts(
+                    @NonNull ContentResolver resolver) {
+                Bundle response = nullSafeCall(resolver, ContactsContract.AUTHORITY_URI,
+                        QUERY_ELIGIBLE_DEFAULT_ACCOUNTS_METHOD, null, null);
+                List<Account> result = response.getParcelableArrayList(
+                        KEY_ELIGIBLE_DEFAULT_ACCOUNTS, Account.class);
+                if (result == null) {
+                    return new ArrayList<>();
+                }
+                return result;
+            }
+
+
+
+            /**
+             * The method to invoke to move local {@link RawContacts} and {@link Groups} from local
+             * account(s) to the Cloud Default Account (if any).
+             *
+             * @hide
+             */
+            public static final String MOVE_LOCAL_CONTACTS_TO_CLOUD_DEFAULT_ACCOUNT_METHOD =
+                    "moveLocalContactsToCloudDefaultAccount";
+
+            /**
+             * Move {@link RawContacts} and {@link Groups} (if any) from the local account to the
+             * Cloud Default Account (if any).
+             * @param resolver the ContentResolver to query.
+             * @throws RuntimeException if it fails to move contacts to the default account.
+             *
+             * @hide
+             */
+            @SystemApi
+            @FlaggedApi(Flags.FLAG_NEW_DEFAULT_ACCOUNT_API_ENABLED)
+            @RequiresPermission(allOf = {android.Manifest.permission.WRITE_CONTACTS,
+                    android.Manifest.permission.SET_DEFAULT_ACCOUNT_FOR_CONTACTS})
+            public static void moveLocalContactsToCloudDefaultAccount(
+                    @NonNull ContentResolver resolver) {
+
+                Bundle extras = new Bundle();
+                Bundle result = nullSafeCall(
+                        resolver,
+                        ContactsContract.AUTHORITY_URI,
+                        MOVE_LOCAL_CONTACTS_TO_CLOUD_DEFAULT_ACCOUNT_METHOD,
+                        null,
+                        extras);
+            }
+
+            /**
+             * The method to invoke to move {@link RawContacts} and {@link Groups} from SIM
+             * account(s) to the Cloud Default Account (if any).
+             *
+             * @hide
+             */
+            public static final String MOVE_SIM_CONTACTS_TO_CLOUD_DEFAULT_ACCOUNT_METHOD =
+                    "moveSimContactsToCloudDefaultAccount";
+
+            /**
+             * Move {@link RawContacts} and {@link Groups} (if any) from the local account to the
+             * Cloud Default Account (if any).
+             * @param resolver the ContentResolver to query.
+             * @throws RuntimeException if it fails to move contacts to the default account.
+             *
+             * @hide
+             */
+            @SystemApi
+            @FlaggedApi(Flags.FLAG_NEW_DEFAULT_ACCOUNT_API_ENABLED)
+            @RequiresPermission(allOf = {android.Manifest.permission.WRITE_CONTACTS,
+                    android.Manifest.permission.SET_DEFAULT_ACCOUNT_FOR_CONTACTS})
+            public static void moveSimContactsToCloudDefaultAccount(
+                    @NonNull ContentResolver resolver) {
+                Bundle result = nullSafeCall(
+                        resolver,
+                        ContactsContract.AUTHORITY_URI,
+                        MOVE_SIM_CONTACTS_TO_CLOUD_DEFAULT_ACCOUNT_METHOD,
+                        /* arg= */ null,
+                        /* extras= */ null);
+            }
+
+            /**
+             * The method to invoke to get the number of {@link RawContacts} that are in local
+             * account(s) and movable to the Cloud Default Account (if any).
+             *
+             * @hide
+             */
+            public static final String GET_NUMBER_OF_MOVABLE_LOCAL_CONTACTS_METHOD =
+                    "getNumberOfMovableLocalContacts";
+
+            /**
+             * The result key for moving local {@link RawContacts} and {@link Groups} from SIM
+             * account(s) to the Cloud Default Account (if any).
+             *
+             * @hide
+             */
+            public static final String KEY_NUMBER_OF_MOVABLE_LOCAL_CONTACTS =
+                    "key_number_of_movable_local_contacts";
+
+            /**
+             * Gets the number of {@link RawContacts} in the local account(s) which may be moved
+             * using {@link DefaultAccount#moveLocalContactsToCloudDefaultAccount} (if any).
+             * @param resolver the ContentResolver to query.
+             * @return the number of {@link RawContacts} in the local account(s), or 0 if there is
+             * no Cloud Default Account.
+             * @throws RuntimeException if it fails get the number of movable local contacts.
+             *
+             * @hide
+             */
+            @SystemApi
+            @FlaggedApi(Flags.FLAG_NEW_DEFAULT_ACCOUNT_API_ENABLED)
+            @RequiresPermission(allOf = {android.Manifest.permission.READ_CONTACTS,
+                    android.Manifest.permission.SET_DEFAULT_ACCOUNT_FOR_CONTACTS})
+            public static int getNumberOfMovableLocalContacts(
+                    @NonNull ContentResolver resolver) {
+                Bundle result = nullSafeCall(
+                        resolver,
+                        ContactsContract.AUTHORITY_URI,
+                        GET_NUMBER_OF_MOVABLE_LOCAL_CONTACTS_METHOD,
+                        /* arg= */ null,
+                        /* extras= */ null);
+                return result.getInt(KEY_NUMBER_OF_MOVABLE_LOCAL_CONTACTS,
+                        /* defaultValue= */ 0);
+            }
+
+            /**
+             * The method to invoke to get the number of {@link RawContacts} that are in SIM
+             * account(s) and movable to the Cloud Default Account (if any).
+             *
+             * @hide
+             */
+            public static final String GET_NUMBER_OF_MOVABLE_SIM_CONTACTS_METHOD =
+                    "getNumberOfMovableSimContacts";
+
+            /**
+             * The result key for moving local {@link RawContacts} and {@link Groups} from SIM
+             * account(s) to the Cloud Default Account (if any).
+             *
+             * @hide
+             */
+            public static final String KEY_NUMBER_OF_MOVABLE_SIM_CONTACTS =
+                    "key_number_of_movable_sim_contacts";
+
+            /**
+             * Gets the number of {@link RawContacts} in the SIM account(s) which may be moved using
+             * {@link DefaultAccount#moveSimContactsToCloudDefaultAccount} (if any).
+             * @param resolver the ContentResolver to query.
+             * @return the number of {@link RawContacts} in the SIM account(s), or 0 if there is
+             * no Cloud Default Account.
+             * @throws RuntimeException if it fails get the number of movable sim contacts.
+             *
+             * @hide
+             */
+            @SystemApi
+            @FlaggedApi(Flags.FLAG_NEW_DEFAULT_ACCOUNT_API_ENABLED)
+            @RequiresPermission(allOf = {android.Manifest.permission.READ_CONTACTS,
+                    android.Manifest.permission.SET_DEFAULT_ACCOUNT_FOR_CONTACTS})
+            public static int getNumberOfMovableSimContacts(
+                    @NonNull ContentResolver resolver) {
+                Bundle result = nullSafeCall(
+                        resolver,
+                        ContactsContract.AUTHORITY_URI,
+                        GET_NUMBER_OF_MOVABLE_SIM_CONTACTS_METHOD,
+                        /* arg= */ null,
+                        /* extras= */ null);
+                return result.getInt(KEY_NUMBER_OF_MOVABLE_SIM_CONTACTS,
+                        /* defaultValue= */ 0);
+            }
+
         }
 
         /**
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 1a15d09..594005c 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -2351,6 +2351,11 @@
 
     /**
      * Activity Action: Show the permission screen for allowing apps to post promoted notifications.
+     * Properly formatted priority notifications are elevated in appearance. For example they may be
+     * able to use colors, have richer progress bars, show as chips in the status bar, and/or
+     * permanently appear on always-on-displays. This functionality is intended to be reserved for
+     * user initiated ongoing activities like navigation, phone calls, and ride sharing.
+     *
      * <p>
      *     Input: {@link #EXTRA_APP_PACKAGE}, the package to display.
      * <p>
@@ -6205,6 +6210,25 @@
         public static final String TOUCHPAD_RIGHT_CLICK_ZONE = "touchpad_right_click_zone";
 
         /**
+         * Whether to enable reversed vertical scrolling for connected mice.
+         *
+         * When enabled, scrolling down on the mouse wheel will move the screen up and vice versa.
+         * @hide
+         */
+        public static final String MOUSE_REVERSE_VERTICAL_SCROLLING =
+                "mouse_reverse_vertical_scrolling";
+
+        /**
+         * Whether to enable swapping the primary button for connected mice.
+         *
+         * When enabled, right clicking will be the primary button and left clicking will be the
+         * secondary button (e.g. show menu).
+         * @hide
+         */
+        public static final String MOUSE_SWAP_PRIMARY_BUTTON =
+                "mouse_swap_primary_button";
+
+        /**
          * Pointer fill style, specified by
          * {@link android.view.PointerIcon.PointerIconVectorStyleFill} constants.
          *
@@ -6442,6 +6466,8 @@
             PRIVATE_SETTINGS.add(SCREEN_FLASH_NOTIFICATION);
             PRIVATE_SETTINGS.add(SCREEN_FLASH_NOTIFICATION_COLOR);
             PRIVATE_SETTINGS.add(DEFAULT_DEVICE_FONT_SCALE);
+            PRIVATE_SETTINGS.add(MOUSE_REVERSE_VERTICAL_SCROLLING);
+            PRIVATE_SETTINGS.add(MOUSE_SWAP_PRIMARY_BUTTON);
         }
 
         /**
diff --git a/core/java/android/service/ondeviceintelligence/OnDeviceSandboxedInferenceService.java b/core/java/android/service/ondeviceintelligence/OnDeviceSandboxedInferenceService.java
index f123a96..3181556 100644
--- a/core/java/android/service/ondeviceintelligence/OnDeviceSandboxedInferenceService.java
+++ b/core/java/android/service/ondeviceintelligence/OnDeviceSandboxedInferenceService.java
@@ -129,6 +129,16 @@
      * @hide
      */
     public static final String MODEL_UNLOADED_BUNDLE_KEY = "model_unloaded";
+    /**
+     * @hide
+     */
+    public static final String MODEL_LOADED_BROADCAST_INTENT =
+        "android.service.ondeviceintelligence.MODEL_LOADED";
+    /**
+     * @hide
+     */
+    public static final String MODEL_UNLOADED_BROADCAST_INTENT =
+        "android.service.ondeviceintelligence.MODEL_UNLOADED";
 
     /**
      * @hide
diff --git a/core/java/android/telephony/PhoneStateListener.java b/core/java/android/telephony/PhoneStateListener.java
index 5ac0c50..e8ef9d6 100644
--- a/core/java/android/telephony/PhoneStateListener.java
+++ b/core/java/android/telephony/PhoneStateListener.java
@@ -1671,14 +1671,22 @@
         }
 
         /** @hide */
-        public final void onCallBackModeStarted(
-                @TelephonyManager.EmergencyCallbackModeType int type) {
+        public final void onCallbackModeStarted(
+                @TelephonyManager.EmergencyCallbackModeType int type, long durationMillis,
+                int subId) {
             // not support. Can't override. Use TelephonyCallback.
         }
 
         /** @hide */
-        public final void onCallBackModeStopped(@EmergencyCallbackModeType int type,
-                @EmergencyCallbackModeStopReason int reason) {
+        public final void onCallbackModeRestarted(
+                @TelephonyManager.EmergencyCallbackModeType int type, long durationMillis,
+                int subId) {
+            // not support. Can't override. Use TelephonyCallback.
+        }
+
+        /** @hide */
+        public final void onCallbackModeStopped(@EmergencyCallbackModeType int type,
+                @EmergencyCallbackModeStopReason int reason, int subId) {
             // not support. Can't override. Use TelephonyCallback.
         }
 
diff --git a/core/java/android/telephony/TelephonyCallback.java b/core/java/android/telephony/TelephonyCallback.java
index c360e64..14d5800 100644
--- a/core/java/android/telephony/TelephonyCallback.java
+++ b/core/java/android/telephony/TelephonyCallback.java
@@ -41,6 +41,7 @@
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.ref.WeakReference;
+import java.time.Duration;
 import java.util.Arrays;
 import java.util.List;
 import java.util.Map;
@@ -619,16 +620,20 @@
 
 
     /**
-     * Event for changes to the Emergency callback mode
+     * Event for changes to the emergency callback mode
      *
      * <p>Requires permission {@link android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE}
      *
-     * @see EmergencyCallbackModeListener#onCallbackModeStarted(int)
-     * @see EmergencyCallbackModeListener#onCallbackModeStopped(int, int)
+     * @see EmergencyCallbackModeListener#onCallbackModeStarted(int, Duration, int)
+     * @see EmergencyCallbackModeListener#onCallbackModeRestarted(int, Duration, int)
+     * @see EmergencyCallbackModeListener#onCallbackModeStopped(int, int, int)
      *
      * @hide
      */
+
+    @FlaggedApi(Flags.FLAG_EMERGENCY_CALLBACK_MODE_NOTIFICATION)
     @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+    @SystemApi
     public static final int EVENT_EMERGENCY_CALLBACK_MODE_CHANGED = 40;
 
     /**
@@ -1671,39 +1676,64 @@
     }
 
     /**
-     * Interface for emergency callback mode listener.
+     * Interface for the emergency callback mode listener.
      *
      * @hide
      */
+    @FlaggedApi(Flags.FLAG_EMERGENCY_CALLBACK_MODE_NOTIFICATION)
+    @SystemApi
     public interface EmergencyCallbackModeListener {
         /**
-         * Indicates that Callback Mode has been started.
+         * Indicates that emergency callback mode has been started.
          * <p>
-         * This method will be called when an emergency sms/emergency call is sent
-         * and the callback mode is supported by the carrier.
-         * If an emergency SMS is transmitted during callback mode for SMS, this API will be called
-         * once again with TelephonyManager#EMERGENCY_CALLBACK_MODE_SMS.
+         * This method will be called when an emergency SMS or emergency call is ended and
+         * the emergency callback mode is supported by the carrier.
+         * If the emergency callback mode was started for an emergency call and an emergency SMS is
+         * transmitted during callback mode for SMS then this API will be called once again with
+         * TelephonyManager#EMERGENCY_CALLBACK_MODE_SMS.
          *
-         * @param type for callback mode entry
+         * @param type for the emergency callback mode entry
          *             See {@link TelephonyManager.EmergencyCallbackModeType}.
          * @see TelephonyManager#EMERGENCY_CALLBACK_MODE_CALL
          * @see TelephonyManager#EMERGENCY_CALLBACK_MODE_SMS
+         *
+         * @param timerDuration is the time remaining in the emergency callback mode.
+         * @param subId The subscription ID used to start the emergency callback mode.
          */
         @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
-        void onCallBackModeStarted(@TelephonyManager.EmergencyCallbackModeType int type);
+        void onCallbackModeStarted(@TelephonyManager.EmergencyCallbackModeType int type,
+                @NonNull Duration timerDuration, int subId);
 
         /**
-         * Indicates that Callback Mode has been stopped.
+         * Indicates that emergency callback mode has been re-started.
          * <p>
-         * This method will be called when the callback mode timer expires or when
-         * a normal call/SMS is sent
+         * This method will be called when an emergency SMS or emergency call is ended
+         * in the emergency callback mode.
+         * This is used to restart the emergency callback mode when it is already in progress.
          *
-         * @param type for callback mode entry
+         * @param type for the emergency callback mode entry
+         *             See {@link TelephonyManager.EmergencyCallbackModeType}.
          * @see TelephonyManager#EMERGENCY_CALLBACK_MODE_CALL
          * @see TelephonyManager#EMERGENCY_CALLBACK_MODE_SMS
          *
-         * @param reason for changing callback mode
+         * @param timerDuration is the time remaining in the emergency callback mode.
+         * @param subId The subscription ID used to restart the emergency callback mode.
+         */
+        @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+        void onCallbackModeRestarted(@TelephonyManager.EmergencyCallbackModeType int type,
+                @NonNull Duration timerDuration, int subId);
+
+        /**
+         * Indicates that emergency callback mode has been stopped.
+         * <p>
+         * This method will be called when the emergency callback mode timer expires or when
+         * a normal call/SMS is sent
          *
+         * @param type for the emergency callback mode entry
+         * @see TelephonyManager#EMERGENCY_CALLBACK_MODE_CALL
+         * @see TelephonyManager#EMERGENCY_CALLBACK_MODE_SMS
+         *
+         * @param reason for changing emergency callback mode
          * @see TelephonyManager#STOP_REASON_UNKNOWN
          * @see TelephonyManager#STOP_REASON_OUTGOING_NORMAL_CALL_INITIATED
          * @see TelephonyManager#STOP_REASON_NORMAL_SMS_SENT
@@ -1711,10 +1741,12 @@
          * @see TelephonyManager#STOP_REASON_EMERGENCY_SMS_SENT
          * @see TelephonyManager#STOP_REASON_TIMER_EXPIRED
          * @see TelephonyManager#STOP_REASON_USER_ACTION
+         *
+         * @param subId is the current subscription used the emergency callback mode.
          */
         @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
-        void onCallBackModeStopped(@TelephonyManager.EmergencyCallbackModeType int type,
-                @TelephonyManager.EmergencyCallbackModeStopReason int reason);
+        void onCallbackModeStopped(@TelephonyManager.EmergencyCallbackModeType int type,
+                @TelephonyManager.EmergencyCallbackModeStopReason int reason, int subId);
     }
 
     /**
@@ -2132,18 +2164,43 @@
                             mediaQualityStatus)));
         }
 
-        public void onCallBackModeStarted(@TelephonyManager.EmergencyCallbackModeType int type) {
+        @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+        public void onCallbackModeStarted(@TelephonyManager.EmergencyCallbackModeType int type,
+                long durationMillis, int subId) {
+            if (!Flags.emergencyCallbackModeNotification()) return;
+
             EmergencyCallbackModeListener listener =
                     (EmergencyCallbackModeListener) mTelephonyCallbackWeakRef.get();
             Log.d(LOG_TAG, "onCallBackModeStarted:type=" + type + ", listener=" + listener);
             if (listener == null) return;
 
+            final Duration timerDuration = Duration.ofMillis(durationMillis);
             Binder.withCleanCallingIdentity(
-                    () -> mExecutor.execute(() -> listener.onCallBackModeStarted(type)));
+                    () -> mExecutor.execute(() -> listener.onCallbackModeStarted(type,
+                            timerDuration, subId)));
         }
 
-        public void onCallBackModeStopped(@TelephonyManager.EmergencyCallbackModeType int type,
-                @TelephonyManager.EmergencyCallbackModeStopReason int reason) {
+        @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+        public void onCallbackModeRestarted(@TelephonyManager.EmergencyCallbackModeType int type,
+                long durationMillis, int subId) {
+            if (!Flags.emergencyCallbackModeNotification()) return;
+
+            EmergencyCallbackModeListener listener =
+                    (EmergencyCallbackModeListener) mTelephonyCallbackWeakRef.get();
+            Log.d(LOG_TAG, "onCallbackModeRestarted:type=" + type + ", listener=" + listener);
+            if (listener == null) return;
+
+            final Duration timerDuration = Duration.ofMillis(durationMillis);
+            Binder.withCleanCallingIdentity(
+                    () -> mExecutor.execute(() -> listener.onCallbackModeRestarted(type,
+                            timerDuration, subId)));
+        }
+
+        @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+        public void onCallbackModeStopped(@TelephonyManager.EmergencyCallbackModeType int type,
+                @TelephonyManager.EmergencyCallbackModeStopReason int reason, int subId) {
+            if (!Flags.emergencyCallbackModeNotification()) return;
+
             EmergencyCallbackModeListener listener =
                     (EmergencyCallbackModeListener) mTelephonyCallbackWeakRef.get();
             Log.d(LOG_TAG, "onCallBackModeStopped:type=" + type
@@ -2151,7 +2208,8 @@
             if (listener == null) return;
 
             Binder.withCleanCallingIdentity(
-                    () -> mExecutor.execute(() -> listener.onCallBackModeStopped(type, reason)));
+                    () -> mExecutor.execute(() -> listener.onCallbackModeStopped(type, reason,
+                            subId)));
         }
 
         public void onCarrierRoamingNtnModeChanged(boolean active) {
diff --git a/core/java/android/telephony/TelephonyRegistryManager.java b/core/java/android/telephony/TelephonyRegistryManager.java
index 10f03c1..3c7e924 100644
--- a/core/java/android/telephony/TelephonyRegistryManager.java
+++ b/core/java/android/telephony/TelephonyRegistryManager.java
@@ -115,7 +115,6 @@
                 ICarrierConfigChangeListener>
             mCarrierConfigChangeListenerMap = new ConcurrentHashMap<>();
 
-
     /** @hide **/
     public TelephonyRegistryManager(@NonNull Context context) {
         mContext = context;
@@ -1721,13 +1720,36 @@
      * @param subId Sender subscription ID.
      * @param type for callback mode entry.
      *             See {@link TelephonyManager.EmergencyCallbackModeType}.
+     * @param durationMillis is the number of milliseconds remaining in the emergency callback
+     *                        mode.
      * @hide
      */
-    public void notifyCallBackModeStarted(int phoneId, int subId,
-            @TelephonyManager.EmergencyCallbackModeType int type) {
+    public void notifyCallbackModeStarted(int phoneId, int subId,
+            @TelephonyManager.EmergencyCallbackModeType int type, long durationMillis) {
         try {
-            Log.d(TAG, "notifyCallBackModeStarted:type=" + type);
-            sRegistry.notifyCallbackModeStarted(phoneId, subId, type);
+            Log.d(TAG, "notifyCallbackModeStarted:type=" + type);
+            sRegistry.notifyCallbackModeStarted(phoneId, subId, type, durationMillis);
+        } catch (RemoteException ex) {
+            // system process is dead
+            throw ex.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Notify Callback Mode has been restarted.
+     * @param phoneId Sender phone ID.
+     * @param subId Sender subscription ID.
+     * @param type for callback mode entry.
+     *             See {@link TelephonyManager.EmergencyCallbackModeType}.
+     * @param durationMillis is the number of milliseconds remaining in the emergency callback
+     *                        mode.
+     * @hide
+     */
+    public void notifyCallbackModeRestarted(int phoneId, int subId,
+            @TelephonyManager.EmergencyCallbackModeType int type, long durationMillis) {
+        try {
+            Log.d(TAG, "notifyCallbackModeRestarted:type=" + type);
+            sRegistry.notifyCallbackModeRestarted(phoneId, subId, type, durationMillis);
         } catch (RemoteException ex) {
             // system process is dead
             throw ex.rethrowFromSystemServer();
diff --git a/core/java/android/text/flags/flags.aconfig b/core/java/android/text/flags/flags.aconfig
index ec5b488..09b2201 100644
--- a/core/java/android/text/flags/flags.aconfig
+++ b/core/java/android/text/flags/flags.aconfig
@@ -188,3 +188,10 @@
     purpose: PURPOSE_BUGFIX
   }
 }
+
+flag {
+  name: "tts_span_duration"
+  namespace: "text"
+  description: "Feature flag for adding a TYPE_DURATION to TtsSpan"
+  bug: "337103893"
+}
diff --git a/core/java/android/text/style/TtsSpan.java b/core/java/android/text/style/TtsSpan.java
index f9a1a0d..b7b8f0b1 100644
--- a/core/java/android/text/style/TtsSpan.java
+++ b/core/java/android/text/style/TtsSpan.java
@@ -16,6 +16,10 @@
 
 package android.text.style;
 
+import static com.android.text.flags.Flags.FLAG_TTS_SPAN_DURATION;
+
+import android.annotation.FlaggedApi;
+import android.annotation.NonNull;
 import android.os.Parcel;
 import android.os.PersistableBundle;
 import android.text.ParcelableSpan;
@@ -112,6 +116,16 @@
     public static final String TYPE_TIME = "android.type.time";
 
     /**
+     * The text associated with this span is a duration, consisting of a number of
+     * hours, minutes, and seconds specified with {@link #ARG_HOURS},
+     * {@link #ARG_MINUTES}, and {@link #ARG_SECONDS}. This is different from {@link #TYPE_TIME}.
+     * This should be used to convey an interval of time, while {@link #TYPE_TIME} should be used to
+     * convey a particular moment in time, such as a clock time.
+     */
+    @FlaggedApi(FLAG_TTS_SPAN_DURATION)
+    public static final String TYPE_DURATION = "android.type.duration";
+
+    /**
      * The text associated with this span is a date. At least one of the
      * arguments {@link #ARG_MONTH} and {@link #ARG_YEAR} has to be provided.
      * The argument {@link #ARG_DAY} is optional if {@link #ARG_MONTH} is set.
@@ -302,13 +316,21 @@
     public static final String ARG_HOURS = "android.arg.hours";
 
     /**
-     * Argument used to specify the minutes of a time. The hours should be
+     * Argument used to specify the minutes of a time. The minutes should be
      * provided as an integer in the range from 0 up to and including 59.
      * Can be used with {@link #TYPE_TIME}.
      */
     public static final String ARG_MINUTES = "android.arg.minutes";
 
     /**
+     * Argument used to specify the seconds of a time or duration. The seconds should be
+     * provided as an integer in the range from 0 up to and including 59.
+     * Can be used with {@link #TYPE_TIME} or {@link #TYPE_DURATION}.
+     */
+    @FlaggedApi(FLAG_TTS_SPAN_DURATION)
+    public static final String ARG_SECONDS = "android.arg.seconds";
+
+    /**
      * Argument used to specify the weekday of a date. The value should be
      * provided as an integer and can be any of {@link #WEEKDAY_SUNDAY},
      * {@link #WEEKDAY_MONDAY}, {@link #WEEKDAY_TUESDAY},
@@ -1132,9 +1154,70 @@
         public TimeBuilder setMinutes(int minutes) {
             return setIntArgument(TtsSpan.ARG_MINUTES, minutes);
         }
+
+        /**
+         * Sets the {@link #ARG_SECONDS} argument.
+         * @param seconds The value to be set for seconds.
+         * @return This instance.
+         */
+        @FlaggedApi(FLAG_TTS_SPAN_DURATION)
+        @NonNull
+        public TimeBuilder setSeconds(int seconds) {
+            return setIntArgument(TtsSpan.ARG_SECONDS, seconds);
+        }
     }
 
     /**
+     * A builder for TtsSpans of type {@link #TYPE_DURATION}.
+     */
+    @FlaggedApi(FLAG_TTS_SPAN_DURATION)
+    public static class DurationBuilder
+            extends SemioticClassBuilder<DurationBuilder> {
+
+        /**
+         * Creates a builder for a TtsSpan of type {@link #TYPE_DURATION}.
+         */
+        @FlaggedApi(FLAG_TTS_SPAN_DURATION)
+        public DurationBuilder() {
+            super(TtsSpan.TYPE_DURATION);
+        }
+
+        /**
+         * Sets the {@link #ARG_HOURS} argument.
+         * @param hours The value to be set for hours.
+         * @return This instance.
+         */
+        @FlaggedApi(FLAG_TTS_SPAN_DURATION)
+        @NonNull
+        public DurationBuilder setHours(int hours) {
+            return setIntArgument(TtsSpan.ARG_HOURS, hours);
+        }
+
+        /**
+         * Sets the {@link #ARG_MINUTES} argument.
+         * @param minutes The value to be set for minutes.
+         * @return This instance.
+         */
+        @FlaggedApi(FLAG_TTS_SPAN_DURATION)
+        @NonNull
+        public DurationBuilder setMinutes(int minutes) {
+            return setIntArgument(TtsSpan.ARG_MINUTES, minutes);
+        }
+
+        /**
+         * Sets the {@link #ARG_SECONDS} argument.
+         * @param seconds The value to be set for seconds.
+         * @return This instance.
+         */
+        @FlaggedApi(FLAG_TTS_SPAN_DURATION)
+        @NonNull
+        public DurationBuilder setSeconds(int seconds) {
+            return setIntArgument(TtsSpan.ARG_SECONDS, seconds);
+        }
+    }
+
+
+    /**
      * A builder for TtsSpans of type {@link #TYPE_DATE}.
      */
     public static class DateBuilder
diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java
index 53935e8..8a8022c 100644
--- a/core/java/android/view/Display.java
+++ b/core/java/android/view/Display.java
@@ -449,6 +449,13 @@
     public static final int TYPE_VIRTUAL = 5;
 
     /**
+     * The maximum display type value.
+     * Helpful to get all possible display values.
+     * @hide
+     */
+    public static final int TYPE_MAX = TYPE_VIRTUAL;
+
+    /**
      * Display state: The display state is unknown.
      *
      * @see #getState
diff --git a/core/java/android/view/ImeInsetsSourceConsumer.java b/core/java/android/view/ImeInsetsSourceConsumer.java
index 229e8ee7..4f74198 100644
--- a/core/java/android/view/ImeInsetsSourceConsumer.java
+++ b/core/java/android/view/ImeInsetsSourceConsumer.java
@@ -221,13 +221,13 @@
 
     @Override
     public boolean setControl(@Nullable InsetsSourceControl control, int[] showTypes,
-            int[] hideTypes) {
+            int[] hideTypes, int[] cancelTypes) {
         if (Flags.refactorInsetsController()) {
-            return super.setControl(control, showTypes, hideTypes);
+            return super.setControl(control, showTypes, hideTypes, cancelTypes);
         } else {
             ImeTracing.getInstance().triggerClientDump("ImeInsetsSourceConsumer#setControl",
                     mController.getHost().getInputMethodManager(), null /* icProto */);
-            if (!super.setControl(control, showTypes, hideTypes)) {
+            if (!super.setControl(control, showTypes, hideTypes, cancelTypes)) {
                 return false;
             }
             if (control == null && !mIsRequestedVisibleAwaitingLeash) {
diff --git a/core/java/android/view/InsetsAnimationControlImpl.java b/core/java/android/view/InsetsAnimationControlImpl.java
index 97facc1..4fead2a 100644
--- a/core/java/android/view/InsetsAnimationControlImpl.java
+++ b/core/java/android/view/InsetsAnimationControlImpl.java
@@ -371,6 +371,7 @@
         mPendingInsets = mLayoutInsetsDuringAnimation == LAYOUT_INSETS_DURING_ANIMATION_SHOWN
                 ? mShownInsets : mHiddenInsets;
         mPendingAlpha = 1f;
+        mPendingFraction = 1f;
         applyChangeInsets(null);
         mCancelled = true;
         mListener.onCancelled(mReadyDispatched ? this : null);
@@ -486,6 +487,17 @@
         if (controls == null) {
             return;
         }
+
+        final boolean visible = mPendingFraction == 0
+                // The first frame of ANIMATION_TYPE_SHOW should be invisible since it is
+                // animated from the hidden state.
+                ? mAnimationType != ANIMATION_TYPE_SHOW
+                : mPendingFraction < 1f || (mFinished
+                        ? mShownOnFinish
+                        // If the animation is cancelled, mFinished and mShownOnFinish are not set.
+                        // Here uses mLayoutInsetsDuringAnimation to decide if it should be visible.
+                        : mLayoutInsetsDuringAnimation == LAYOUT_INSETS_DURING_ANIMATION_SHOWN);
+
         // TODO: Implement behavior when inset spans over multiple types
         for (int i = controls.size() - 1; i >= 0; i--) {
             final InsetsSourceControl control = controls.valueAt(i);
@@ -498,12 +510,6 @@
             }
             addTranslationToMatrix(side, offset, mTmpMatrix, mTmpFrame);
 
-            // The first frame of ANIMATION_TYPE_SHOW should be invisible since it is animated from
-            // the hidden state.
-            final boolean visible = mPendingFraction == 0
-                    ? mAnimationType != ANIMATION_TYPE_SHOW
-                    : !mFinished || mShownOnFinish;
-
             if (outState != null && source != null) {
                 outState.addSource(new InsetsSource(source)
                         .setVisible(visible)
diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java
index 8ac5532..d08873c 100644
--- a/core/java/android/view/InsetsController.java
+++ b/core/java/android/view/InsetsController.java
@@ -957,6 +957,7 @@
         int consumedControlCount = 0;
         final @InsetsType int[] showTypes = new int[1];
         final @InsetsType int[] hideTypes = new int[1];
+        final @InsetsType int[] cancelTypes = new int[1];
         ImeTracker.Token statsToken = null;
 
         // Ensure to update all existing source consumers
@@ -982,7 +983,7 @@
 
             // control may be null, but we still need to update the control to null if it got
             // revoked.
-            consumer.setControl(control, showTypes, hideTypes);
+            consumer.setControl(control, showTypes, hideTypes, cancelTypes);
         }
 
         // Ensure to create source consumers if not available yet.
@@ -990,7 +991,7 @@
             for (int i = mTmpControlArray.size() - 1; i >= 0; i--) {
                 final InsetsSourceControl control = mTmpControlArray.valueAt(i);
                 getSourceConsumer(control.getId(), control.getType())
-                        .setControl(control, showTypes, hideTypes);
+                        .setControl(control, showTypes, hideTypes, cancelTypes);
             }
         }
 
@@ -1002,6 +1003,10 @@
         }
         mTmpControlArray.clear();
 
+        if (cancelTypes[0] != 0) {
+            cancelExistingControllers(cancelTypes[0]);
+        }
+
         // Do not override any animations that the app started in the OnControllableInsetsChanged
         // listeners.
         int animatingTypes = invokeControllableInsetsChangedListeners();
@@ -2154,12 +2159,12 @@
                         new InsetsSourceControl(ID_IME_CAPTION_BAR, captionBar(),
                                 null /* leash */, false /* initialVisible */,
                                 new Point(), Insets.NONE),
-                        new int[1], new int[1]);
+                        new int[1], new int[1], new int[1]);
             } else {
                 mState.removeSource(ID_IME_CAPTION_BAR);
                 InsetsSourceConsumer sourceConsumer = mSourceConsumers.get(ID_IME_CAPTION_BAR);
                 if (sourceConsumer != null) {
-                    sourceConsumer.setControl(null, new int[1], new int[1]);
+                    sourceConsumer.setControl(null, new int[1], new int[1], new int[1]);
                 }
             }
             mHost.notifyInsetsChanged();
diff --git a/core/java/android/view/InsetsSourceConsumer.java b/core/java/android/view/InsetsSourceConsumer.java
index da788a7..17f33c1 100644
--- a/core/java/android/view/InsetsSourceConsumer.java
+++ b/core/java/android/view/InsetsSourceConsumer.java
@@ -122,7 +122,7 @@
 
     /**
      * Updates the control delivered from the server.
-
+     *
      * @param showTypes An integer array with a single entry that determines which types a show
      *                  animation should be run after setting the control.
      * @param hideTypes An integer array with a single entry that determines which types a hide
@@ -130,7 +130,7 @@
      * @return Whether the control has changed from the server
      */
     public boolean setControl(@Nullable InsetsSourceControl control,
-            @InsetsType int[] showTypes, @InsetsType int[] hideTypes) {
+            @InsetsType int[] showTypes, @InsetsType int[] hideTypes, int[] cancelTypes) {
         if (Objects.equals(mSourceControl, control)) {
             if (mSourceControl != null && mSourceControl != control) {
                 mSourceControl.release(SurfaceControl::release);
@@ -165,6 +165,12 @@
             // Reset the applier to the default one which has the most lightweight implementation.
             setSurfaceParamsApplier(InsetsAnimationControlRunner.SurfaceParamsApplier.DEFAULT);
         } else {
+            if (lastControl != null && InsetsSource.getInsetSide(lastControl.getInsetsHint())
+                    != InsetsSource.getInsetSide(control.getInsetsHint())) {
+                // The source has been moved to a different side. The coordinates are stale.
+                // Canceling existing animation if there is any.
+                cancelTypes[0] |= mType;
+            }
             final boolean requestedVisible = isRequestedVisibleAwaitingControl();
             final SurfaceControl oldLeash = lastControl != null ? lastControl.getLeash() : null;
             final SurfaceControl newLeash = control.getLeash();
diff --git a/core/java/android/view/InsetsState.java b/core/java/android/view/InsetsState.java
index 5c41516..67050e0 100644
--- a/core/java/android/view/InsetsState.java
+++ b/core/java/android/view/InsetsState.java
@@ -38,7 +38,7 @@
 import static android.view.WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST;
 import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ERROR;
 import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
-import static android.window.flags.DesktopModeFlags.ENABLE_CAPTION_COMPAT_INSET_FORCE_CONSUMPTION_ALWAYS;
+import static android.window.DesktopModeFlags.ENABLE_CAPTION_COMPAT_INSET_FORCE_CONSUMPTION_ALWAYS;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index 2748e32..19e244a 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -49,6 +49,7 @@
 import android.gui.StalledTransactionInfo;
 import android.gui.TrustedOverlay;
 import android.hardware.DataSpace;
+import android.hardware.DisplayLuts;
 import android.hardware.HardwareBuffer;
 import android.hardware.OverlayProperties;
 import android.hardware.SyncFence;
@@ -307,9 +308,9 @@
     private static native StalledTransactionInfo nativeGetStalledTransactionInfo(int pid);
     private static native void nativeSetDesiredPresentTimeNanos(long transactionObj,
                                                                 long desiredPresentTimeNanos);
-    private static native void nativeSetFrameTimeline(long transactionObj,
-                                                           long vsyncId);
     private static native void nativeNotifyShutdown();
+    private static native void nativeSetLuts(long transactionObj, long nativeObject,
+            float[] buffers, int[] slots, int[] dimensions, int[] sizes, int[] samplingKeys);
 
     /**
      * Transforms that can be applied to buffers as they are displayed to a window.
@@ -4399,6 +4400,17 @@
             return this;
         }
 
+        /** @hide */
+        public @NonNull Transaction setLuts(@NonNull SurfaceControl sc,
+                @NonNull DisplayLuts displayLuts) {
+            checkPreconditions(sc);
+
+            nativeSetLuts(mNativeObject, sc.mNativeObject, displayLuts.getLutBuffers(),
+                    displayLuts.getOffsets(), displayLuts.getLutDimensions(),
+                    displayLuts.getLutSizes(), displayLuts.getLutSamplingKeys());
+            return this;
+        }
+
         /**
          * Sets the caching hint for the layer. By default, the caching hint is
          * {@link CACHING_ENABLED}.
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index f7745d1..83b4971 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -16,6 +16,7 @@
 
 package android.view;
 
+import static android.view.flags.Flags.FLAG_SURFACE_VIEW_SET_COMPOSITION_ORDER;
 import static android.view.WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
 import static android.view.WindowManagerPolicyConstants.APPLICATION_MEDIA_OVERLAY_SUBLAYER;
 import static android.view.WindowManagerPolicyConstants.APPLICATION_MEDIA_SUBLAYER;
@@ -770,6 +771,36 @@
     }
 
     /**
+     * Controls the composition order of the SurfaceView. A non-negative composition order
+     * value indicates that the SurfaceView is composited on top of the parent window, while
+     * a negative composition order indicates that the SurfaceView is behind the parent
+     * window. A SurfaceView with a higher value appears above its peers with lower values.
+     * For SurfaceViews with the same composition order value, their relative order is
+     * undefined.
+     *
+     * @param compositionOrder the composition order of the surface view.
+     */
+    @FlaggedApi(FLAG_SURFACE_VIEW_SET_COMPOSITION_ORDER)
+    public void setCompositionOrder(int compositionOrder) {
+        mRequestedSubLayer = compositionOrder;
+        if (mSubLayer != mRequestedSubLayer) {
+            updateSurface();
+        }
+    }
+
+    /**
+     * Returns the composition order of the SurfaceView.
+     *
+     * @return composition order of the SurfaceView.
+     *
+     * @see #setCompositionOrder(int)
+     */
+    @FlaggedApi(FLAG_SURFACE_VIEW_SET_COMPOSITION_ORDER)
+    public int getCompositionOrder() {
+        return mRequestedSubLayer;
+    }
+
+    /**
      * Control whether the surface view's surface is placed on top of another
      * regular surface view in the window (but still behind the window itself).
      * This is typically used to place overlays on top of an underlying media
@@ -1257,7 +1288,8 @@
                 final Transaction surfaceUpdateTransaction = new Transaction();
                 if (creating) {
                     updateOpaqueFlag();
-                    final String name = "SurfaceView[" + viewRoot.getTitle().toString() + "]";
+                    final String name = Integer.toHexString(System.identityHashCode(this))
+                            + " SurfaceView[" + viewRoot.getTitle().toString() + "]";
                     createBlastSurfaceControls(viewRoot, name, surfaceUpdateTransaction);
                 } else if (mSurfaceControl == null) {
                     return;
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 0ca442d..b921213 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -125,7 +125,7 @@
 import static android.view.flags.Flags.toolkitSetFrameRateReadOnly;
 import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodClientsTraceProto.ClientSideProto.IME_FOCUS_CONTROLLER;
 import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodClientsTraceProto.ClientSideProto.INSETS_CONTROLLER;
-import static android.window.flags.DesktopModeFlags.ENABLE_CAPTION_COMPAT_INSET_FORCE_CONSUMPTION;
+import static android.window.DesktopModeFlags.ENABLE_CAPTION_COMPAT_INSET_FORCE_CONSUMPTION;
 
 import static com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE;
 import static com.android.text.flags.Flags.disableHandwritingInitiatorForIme;
@@ -284,6 +284,7 @@
 import com.android.internal.view.RootViewSurfaceTaker;
 import com.android.internal.view.SurfaceCallbackHelper;
 import com.android.modules.expresslog.Counter;
+import com.android.os.coregraphics.HwuiStatsLog;
 
 import libcore.io.IoUtils;
 
@@ -1228,6 +1229,8 @@
 
     // The latest input event from the gesture that was used to resolve the pointer icon.
     private MotionEvent mPointerIconEvent = null;
+    private @ActivityInfo.ColorMode int mCurrentColorMode = ActivityInfo.COLOR_MODE_DEFAULT;
+    private long mColorModeLastSetMillis = -1;
 
     public ViewRootImpl(Context context, Display display) {
         this(context, display, WindowManagerGlobal.getWindowSession(), new WindowLayout());
@@ -2646,6 +2649,7 @@
                 mFirstFramePresentedTimeNs = -1;
             }
         }
+        logColorMode(mCurrentColorMode, true);
     }
 
 
@@ -6341,6 +6345,7 @@
         if (mAttachInfo.mThreadedRenderer == null) {
             return;
         }
+
         boolean isHdr = colorMode == ActivityInfo.COLOR_MODE_HDR
                 || colorMode == ActivityInfo.COLOR_MODE_HDR10;
         if (isHdr && !mDisplay.isHdrSdrRatioAvailable()) {
@@ -6353,6 +6358,9 @@
                 && !getConfiguration().isScreenWideColorGamut()) {
             colorMode = ActivityInfo.COLOR_MODE_DEFAULT;
         }
+
+        logColorMode(colorMode, false);
+
         float automaticRatio = mAttachInfo.mThreadedRenderer.setColorMode(colorMode);
         if (desiredRatio == 0 || desiredRatio > automaticRatio) {
             desiredRatio = automaticRatio;
@@ -10005,6 +10013,7 @@
 
             mAttachInfo.mThreadedRenderer = null;
             mAttachInfo.mHardwareAccelerated = false;
+            logColorMode(mCurrentColorMode, true);
         }
     }
 
@@ -13346,4 +13355,27 @@
             mInfrequentUpdateCount = 0;
         }
     }
+
+    private void logColorMode(@ActivityInfo.ColorMode int colorMode, boolean windowStopped) {
+        if (mColorModeLastSetMillis == -1 && windowStopped) {
+            Log.d(TAG, "Skipping stats log for color mode");
+            return;
+        }
+
+        long currentTimeMillis = System.currentTimeMillis();
+
+        if (windowStopped) {
+            HwuiStatsLog.write(HwuiStatsLog.HARDWARE_RENDERER_EVENT, Process.myUid(),
+                    currentTimeMillis - mColorModeLastSetMillis, mCurrentColorMode);
+            mColorModeLastSetMillis = -1;
+        } else {
+            if (mColorModeLastSetMillis > 0) {
+                HwuiStatsLog.write(HwuiStatsLog.HARDWARE_RENDERER_EVENT, Process.myUid(),
+                        currentTimeMillis - mColorModeLastSetMillis, mCurrentColorMode);
+            }
+            mColorModeLastSetMillis = currentTimeMillis;
+        }
+
+        mCurrentColorMode = colorMode;
+    }
 }
diff --git a/core/java/android/view/accessibility/AccessibilityEvent.java b/core/java/android/view/accessibility/AccessibilityEvent.java
index a43906f..dfac244 100644
--- a/core/java/android/view/accessibility/AccessibilityEvent.java
+++ b/core/java/android/view/accessibility/AccessibilityEvent.java
@@ -16,6 +16,7 @@
 
 package android.view.accessibility;
 
+import android.annotation.FlaggedApi;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.compat.annotation.UnsupportedAppUsage;
@@ -784,6 +785,19 @@
      */
     public static final int CONTENT_CHANGE_TYPE_ENABLED = 1 << 12;
 
+    /**
+     * Change type for {@link #TYPE_WINDOW_CONTENT_CHANGED} event:
+     * The source node changed its checked state, which is returned by
+     * {@link AccessibilityNodeInfo#getChecked()}.
+     * The view changing its checked state should call
+     * {@link AccessibilityNodeInfo#setChecked(int)} and then send this event.
+     *
+     * @see AccessibilityNodeInfo#getChecked()
+     * @see AccessibilityNodeInfo#setChecked(int)
+     */
+    @FlaggedApi(Flags.FLAG_TRI_STATE_CHECKED)
+    public static final int CONTENT_CHANGE_TYPE_CHECKED = 1 << 13;
+
     // Speech state change types.
 
     /** Change type for {@link #TYPE_SPEECH_STATE_CHANGE} event: another service is speaking. */
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
index fe6aafb..c5ca059 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
@@ -860,6 +860,37 @@
     public static final String EXTRA_DATA_REQUESTED_KEY =
             "android.view.accessibility.AccessibilityNodeInfo.extra_data_requested";
 
+    // Tri-state checked states.
+
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = { "CHECKED_STATE" }, value = {
+            CHECKED_STATE_FALSE,
+            CHECKED_STATE_TRUE,
+            CHECKED_STATE_PARTIAL
+    })
+    public @interface CheckedState {}
+
+    /**
+     * This node is not checked.
+     */
+    @FlaggedApi(Flags.FLAG_TRI_STATE_CHECKED)
+    public static final int CHECKED_STATE_FALSE = 0;
+
+    /**
+     * This node is checked.
+     */
+    @FlaggedApi(Flags.FLAG_TRI_STATE_CHECKED)
+    public static final int CHECKED_STATE_TRUE = 1;
+
+    /**
+     * This node is partially checked. For example,
+     * when a checkbox owns a number of sub-options and they have
+     * different states, then the main checkbox is in a partially-checked state.
+     */
+    @FlaggedApi(Flags.FLAG_TRI_STATE_CHECKED)
+    public static final int CHECKED_STATE_PARTIAL = 2;
+
     // Boolean attributes.
 
     private static final int BOOLEAN_PROPERTY_CHECKABLE = 1 /* << 0 */;
@@ -1038,6 +1069,10 @@
     private IBinder mLeashedParent;
     private long mLeashedParentNodeId = UNDEFINED_NODE_ID;
 
+    // TODO(b/369951517) Initialize mChecked explicitly with
+    // the CHECKED_FALSE state when flagging is removed.
+    private int mChecked;
+
     /**
      * Creates a new {@link AccessibilityNodeInfo}.
      */
@@ -2319,28 +2354,100 @@
     }
 
     /**
-     * Gets whether this node is checked.
+     * Gets whether this node is checked. This is only meaningful
+     * when {@link #isCheckable()} returns {@code true}.
+     *
+     * @deprecated Use {@link #getChecked()} instead.
      *
      * @return True if the node is checked.
      */
+    @FlaggedApi(Flags.FLAG_TRI_STATE_CHECKED)
+    @Deprecated
     public boolean isChecked() {
         return getBooleanProperty(BOOLEAN_PROPERTY_CHECKED);
     }
 
     /**
-     * Sets whether this node is checked.
+     * Sets whether this node is checked. This is only meaningful
+     * when {@link #isCheckable()} returns {@code true}.
      * <p>
      *   <strong>Note:</strong> Cannot be called from an
      *   {@link android.accessibilityservice.AccessibilityService}.
      *   This class is made immutable before being delivered to an AccessibilityService.
      * </p>
      *
+     * @deprecated Use {@link #setChecked(int)} instead.
+     *
      * @param checked True if the node is checked.
      *
      * @throws IllegalStateException If called from an AccessibilityService.
      */
+    @FlaggedApi(Flags.FLAG_TRI_STATE_CHECKED)
+    @Deprecated
     public void setChecked(boolean checked) {
         setBooleanProperty(BOOLEAN_PROPERTY_CHECKED, checked);
+        if (Flags.triStateChecked()) {
+            mChecked = checked ? CHECKED_STATE_TRUE : CHECKED_STATE_FALSE;
+        }
+    }
+
+    /**
+     * Gets the checked state of this node. This is only meaningful
+     * when {@link #isCheckable()} returns {@code true}.
+     *
+     * @see #setCheckable(boolean)
+     * @see #isCheckable()
+     * @see #setChecked(int)
+     *
+     * @return The checked state, one of:
+     *          <ul>
+     *          <li>{@link #CHECKED_STATE_FALSE}
+     *          <li>{@link #CHECKED_STATE_TRUE}
+     *          <li>{@link #CHECKED_STATE_PARTIAL}
+     *          </ul>
+     */
+    @FlaggedApi(Flags.FLAG_TRI_STATE_CHECKED)
+    public @CheckedState int getChecked() {
+        return mChecked;
+    }
+
+    /**
+     * Sets the checked state of this node. This is only meaningful
+     * when {@link #isCheckable()} returns {@code true}.
+     * <p>
+     *   <strong>Note:</strong> Cannot be called from an
+     *   {@link android.accessibilityservice.AccessibilityService}.
+     *   This class is made immutable before being delivered to an AccessibilityService.
+     * </p>
+     *
+     * @see #setCheckable(boolean)
+     * @see #isCheckable()
+     * @see #getChecked()
+     *
+     * @param checked The checked state. One of
+     *          <ul>
+     *          <li>{@link #CHECKED_STATE_FALSE}
+     *          <li>{@link #CHECKED_STATE_TRUE}
+     *          <li>{@link #CHECKED_STATE_PARTIAL}
+     *          </ul>
+     *
+     * @throws IllegalStateException If called from an AccessibilityService.
+     * @throws IllegalArgumentException if checked is not one of {@link #CHECKED_STATE_FALSE},
+     *          {@link #CHECKED_STATE_TRUE}, or {@link #CHECKED_STATE_PARTIAL}.
+     */
+    @FlaggedApi(Flags.FLAG_TRI_STATE_CHECKED)
+    public void setChecked(@CheckedState int checked) {
+        enforceNotSealed();
+        switch (checked) {
+            case CHECKED_STATE_FALSE:
+            case CHECKED_STATE_TRUE:
+            case CHECKED_STATE_PARTIAL:
+                mChecked = checked;
+                break;
+            default:
+                throw new IllegalArgumentException("Unknown checked argument: " + checked);
+        }
+        setBooleanProperty(BOOLEAN_PROPERTY_CHECKED, checked == CHECKED_STATE_TRUE);
     }
 
     /**
@@ -4515,6 +4622,10 @@
         if (mLeashedParentNodeId != DEFAULT.mLeashedParentNodeId) {
             nonDefaultFields |= bitAt(fieldIndex);
         }
+        fieldIndex++;
+        if (mChecked != DEFAULT.mChecked) {
+            nonDefaultFields |= bitAt(fieldIndex);
+        }
         int totalFields = fieldIndex;
         parcel.writeLong(nonDefaultFields);
 
@@ -4683,6 +4794,9 @@
         if (isBitSet(nonDefaultFields, fieldIndex++)) {
             parcel.writeLong(mLeashedParentNodeId);
         }
+        if (isBitSet(nonDefaultFields, fieldIndex++)) {
+            parcel.writeInt(mChecked);
+        }
 
         if (DEBUG) {
             fieldIndex--;
@@ -4771,6 +4885,7 @@
         mLeashedChild = other.mLeashedChild;
         mLeashedParent = other.mLeashedParent;
         mLeashedParentNodeId = other.mLeashedParentNodeId;
+        mChecked = other.mChecked;
     }
 
     private void initCopyInfos(AccessibilityNodeInfo other) {
@@ -4960,6 +5075,9 @@
         if (isBitSet(nonDefaultFields, fieldIndex++)) {
             mLeashedParentNodeId = parcel.readLong();
         }
+        if (isBitSet(nonDefaultFields, fieldIndex++)) {
+            mChecked = parcel.readInt();
+        }
 
         mSealed = sealed;
     }
diff --git a/core/java/android/view/accessibility/flags/accessibility_flags.aconfig b/core/java/android/view/accessibility/flags/accessibility_flags.aconfig
index b9e9750..8ffae84 100644
--- a/core/java/android/view/accessibility/flags/accessibility_flags.aconfig
+++ b/core/java/android/view/accessibility/flags/accessibility_flags.aconfig
@@ -11,6 +11,13 @@
 }
 
 flag {
+    name: "a11y_is_required_api"
+    namespace: "accessibility"
+    description: "Adds an API to indicate whether a form field (or similar element) is required."
+    bug: "362784403"
+}
+
+flag {
     name: "a11y_overlay_callbacks"
     is_exported: true
     namespace: "accessibility"
@@ -210,3 +217,20 @@
     description: "Feature flag for declaring system pinch zoom opt-out apis"
     bug: "315089687"
 }
+
+flag {
+    name: "tri_state_checked"
+    namespace: "accessibility"
+    description: "Feature flag for adding tri-state checked api"
+    bug: "333784774"
+}
+
+flag {
+    name: "warning_use_default_dialog_type"
+    namespace: "accessibility"
+    description: "Uses the default type for the A11yService warning dialog, instead of SYSTEM_ALERT_DIALOG"
+    bug: "336719951"
+    metadata {
+        purpose: PURPOSE_BUGFIX
+    }
+ }
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index 79ecfe1e..1a45939 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -117,6 +117,8 @@
 import java.util.Map;
 import java.util.Objects;
 import java.util.Set;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicBoolean;
 
 import sun.misc.Cleaner;
@@ -4914,7 +4916,22 @@
                     && (root.getWindowFlags() & WindowManager.LayoutParams.FLAG_SECURE) == 0) {
                 ViewNodeBuilder viewStructure = new ViewNodeBuilder();
                 viewStructure.setAutofillId(view.getAutofillId());
-                view.onProvideAutofillStructure(viewStructure, /* flags= */ 0);
+
+                // Post onProvideAutofillStructure to the UI thread
+                final CountDownLatch latch = new CountDownLatch(1);
+                afm.post(
+                    () -> {
+                        view.onProvideAutofillStructure(viewStructure, /* flags= */ 0);
+                        latch.countDown();
+                    }
+                );
+                try {
+                    latch.await(5000, TimeUnit.MILLISECONDS);
+                } catch (InterruptedException e) {
+                    Thread.currentThread().interrupt();
+                    return null;
+                }
+
                 // TODO(b/141703532): We don't call View#onProvideAutofillVirtualStructure for
                 //  efficiency reason. But this also means we will return null for virtual views
                 //  for now. We will add a new API to fetch the view node info of the virtual
diff --git a/core/java/android/view/flags/view_flags.aconfig b/core/java/android/view/flags/view_flags.aconfig
index f570a9a..1cf26ab 100644
--- a/core/java/android/view/flags/view_flags.aconfig
+++ b/core/java/android/view/flags/view_flags.aconfig
@@ -97,4 +97,23 @@
     description: "Disable Draw Wakelock starting U."
     bug: "331698645"
     is_fixed_read_only: true
+}
+
+flag {
+  name: "calculate_bounds_in_parent_from_bounds_in_screen"
+  namespace: "accessibility"
+  description: "Calculate bounds in parent of each node in ViewStructure from its bounds set relative to screen and its parent's"
+  bug: "366131857"
+  is_fixed_read_only: true
+  metadata {
+      purpose: PURPOSE_BUGFIX
+  }
+}
+
+flag {
+    name: "surface_view_set_composition_order"
+    namespace: "window_surfaces"
+    description: "Add a SurfaceView composition order control API."
+    bug: "341021569"
+    is_fixed_read_only: true
 }
\ No newline at end of file
diff --git a/core/java/android/view/inputmethod/InputMethodInfo.java b/core/java/android/view/inputmethod/InputMethodInfo.java
index 806a593..0a83bdc 100644
--- a/core/java/android/view/inputmethod/InputMethodInfo.java
+++ b/core/java/android/view/inputmethod/InputMethodInfo.java
@@ -860,7 +860,7 @@
      * <p>e.g.<pre><code>startActivity(createStylusHandwritingSettingsActivityIntent());</code>
      * </pre></p>
      *
-     * @attr ref R.styleable#InputMethod_stylusHandwritingSettingsActivity
+     * @attr ref android.R.styleable#InputMethod_stylusHandwritingSettingsActivity
      * @see #getSettingsActivity()
      * @see #supportsStylusHandwriting()
      */
@@ -888,8 +888,8 @@
      * the IME language settings activity.</p>
      * <p>e.g.<pre><code>startActivity(createImeLanguageSettingsActivityIntent());</code></pre></p>
      *
-     * @attr ref R.styleable#InputMethod_languageSettingsActivity
-     * @attr ref R.styleable#InputMethod_settingsActivity
+     * @attr ref android.R.styleable#InputMethod_languageSettingsActivity
+     * @attr ref android.R.styleable#InputMethod_settingsActivity
      */
     @FlaggedApi(android.view.inputmethod.Flags.FLAG_IME_SWITCHER_REVAMP_API)
     @Nullable
diff --git a/core/java/android/webkit/WebSettings.java b/core/java/android/webkit/WebSettings.java
index 7366b9a..ab5969b 100644
--- a/core/java/android/webkit/WebSettings.java
+++ b/core/java/android/webkit/WebSettings.java
@@ -16,10 +16,12 @@
 
 package android.webkit;
 
+import android.annotation.FlaggedApi;
 import android.annotation.IntDef;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.compat.annotation.ChangeId;
+import android.compat.annotation.EnabledAfter;
 import android.compat.annotation.EnabledSince;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
@@ -151,6 +153,24 @@
     public static final long ENABLE_SIMPLIFIED_DARK_MODE = 214741472L;
 
     /**
+     * Enable User-Agent Reduction for webview.
+     * The OS, CPU, and Build information in the default User-Agent will be
+     * reduced to the static "Linux; Android 10; K" string.
+     * Minor/build/patch version information in the default User-Agent is
+     * reduced to "0.0.0". The rest of the default User-Agent remains unchanged.
+     *
+     * See https://developers.google.com/privacy-sandbox/protections/user-agent
+     * for details related to User-Agent Reduction.
+     *
+     * @hide
+     */
+    @ChangeId
+    @EnabledAfter(targetSdkVersion = android.os.Build.VERSION_CODES.VANILLA_ICE_CREAM)
+    @FlaggedApi(android.webkit.Flags.FLAG_USER_AGENT_REDUCTION)
+    @SystemApi
+    public static final long ENABLE_USER_AGENT_REDUCTION = 371034303L;
+
+    /**
      * Default cache usage mode. If the navigation type doesn't impose any
      * specific behavior, use cached resources when they are available
      * and not expired, otherwise load resources from the network.
diff --git a/core/java/android/webkit/flags.aconfig b/core/java/android/webkit/flags.aconfig
index b21a490..d1013a9 100644
--- a/core/java/android/webkit/flags.aconfig
+++ b/core/java/android/webkit/flags.aconfig
@@ -18,3 +18,11 @@
     bug: "310653407"
     is_fixed_read_only: true
 }
+
+flag {
+    name: "user_agent_reduction"
+    is_exported: true
+    namespace: "webview"
+    description: "New feature reduce user-agent for webview"
+    bug: "371034303"
+}
diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java
index 510a92d..3f611c7 100644
--- a/core/java/android/widget/ListView.java
+++ b/core/java/android/widget/ListView.java
@@ -3636,7 +3636,7 @@
      * Returns the drawable that will be drawn between each item in the list.
      *
      * @return the current drawable drawn between list elements
-     * @attr ref R.styleable#ListView_divider
+     * @attr ref android.R.styleable#ListView_divider
      */
     @InspectableProperty
     @Nullable
@@ -3651,7 +3651,7 @@
      * height, you should also call {@link #setDividerHeight(int)}.
      *
      * @param divider the drawable to use
-     * @attr ref R.styleable#ListView_divider
+     * @attr ref android.R.styleable#ListView_divider
      */
     public void setDivider(@Nullable Drawable divider) {
         if (divider != null) {
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index 06820cd..d7b5211 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -46,6 +46,7 @@
 import android.app.PendingIntent;
 import android.app.RemoteInput;
 import android.appwidget.AppWidgetHostView;
+import android.appwidget.flags.Flags;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ComponentName;
 import android.content.Context;
@@ -4119,6 +4120,71 @@
         public void visitUris(@NonNull Consumer<Uri> visitor) {
             mNestedViews.visitUris(visitor);
         }
+
+        @Override
+        public boolean canWriteToProto() {
+            return true;
+        }
+
+        @Override
+        public void writeToProto(ProtoOutputStream out, Context context, Resources appResources) {
+            if (!Flags.remoteViewsProto()) return;
+            final long token = out.start(RemoteViewsProto.Action.VIEW_GROUP_ADD_ACTION);
+            out.write(RemoteViewsProto.ViewGroupAddAction.VIEW_ID,
+                    appResources.getResourceName(mViewId));
+            out.write(RemoteViewsProto.ViewGroupAddAction.INDEX, mIndex);
+            out.write(RemoteViewsProto.ViewGroupAddAction.STABLE_ID, mStableId);
+            long rvToken = out.start(RemoteViewsProto.ViewGroupAddAction.NESTED_VIEWS);
+            mNestedViews.writePreviewToProto(context, out);
+            out.end(rvToken);
+            out.end(token);
+        }
+    }
+
+    private PendingResources<Action> createViewGroupActionAddFromProto(ProtoInputStream in)
+            throws Exception {
+        final LongSparseArray<Object> values = new LongSparseArray<>();
+
+        final long token = in.start(RemoteViewsProto.Action.VIEW_GROUP_ADD_ACTION);
+        while (in.nextField() != NO_MORE_FIELDS) {
+            switch (in.getFieldNumber()) {
+                case (int) RemoteViewsProto.ViewGroupAddAction.VIEW_ID:
+                    values.put(RemoteViewsProto.ViewGroupAddAction.VIEW_ID,
+                            in.readString(RemoteViewsProto.ViewGroupAddAction.VIEW_ID));
+                    break;
+                case (int) RemoteViewsProto.ViewGroupAddAction.NESTED_VIEWS:
+                    final long nvToken = in.start(RemoteViewsProto.ViewGroupAddAction.NESTED_VIEWS);
+                    values.put(RemoteViewsProto.ViewGroupAddAction.NESTED_VIEWS,
+                            createFromProto(in));
+                    in.end(nvToken);
+                    break;
+                case (int) RemoteViewsProto.ViewGroupAddAction.INDEX:
+                    values.put(RemoteViewsProto.ViewGroupAddAction.INDEX,
+                            in.readInt(RemoteViewsProto.ViewGroupAddAction.INDEX));
+                    break;
+                case (int) RemoteViewsProto.ViewGroupAddAction.STABLE_ID:
+                    values.put(RemoteViewsProto.ViewGroupAddAction.STABLE_ID,
+                            in.readInt(RemoteViewsProto.ViewGroupAddAction.STABLE_ID));
+                    break;
+                default:
+                    Log.w(LOG_TAG, "Unhandled field while reading RemoteViews proto!\n"
+                            + ProtoUtils.currentFieldToString(in));
+            }
+        }
+        in.end(token);
+
+        checkContainsKeys(values, new long[]{RemoteViewsProto.ViewGroupAddAction.VIEW_ID,
+                RemoteViewsProto.ViewGroupAddAction.NESTED_VIEWS});
+
+        return (context, resources, rootData, depth) -> {
+            int viewId = getAsIdentifier(resources, values,
+                    RemoteViewsProto.ViewGroupAddAction.VIEW_ID);
+            return new ViewGroupActionAdd(viewId, ((PendingResources<RemoteViews>) values.get(
+                    RemoteViewsProto.ViewGroupAddAction.NESTED_VIEWS)).create(context, resources,
+                    rootData, depth),
+                    (int) values.get(RemoteViewsProto.ViewGroupAddAction.INDEX, 0),
+                    (int) values.get(RemoteViewsProto.ViewGroupAddAction.STABLE_ID, 0));
+        };
     }
 
     /**
@@ -4241,6 +4307,60 @@
         public int mergeBehavior() {
             return MERGE_APPEND;
         }
+
+        @Override
+        public boolean canWriteToProto() {
+            return true;
+        }
+
+        @Override
+        public void writeToProto(ProtoOutputStream out, Context context, Resources appResources) {
+            final long token = out.start(RemoteViewsProto.Action.VIEW_GROUP_REMOVE_ACTION);
+            out.write(RemoteViewsProto.ViewGroupRemoveAction.VIEW_ID,
+                    appResources.getResourceName(mViewId));
+            if (mViewIdToKeep != REMOVE_ALL_VIEWS_ID) {
+                out.write(RemoteViewsProto.ViewGroupRemoveAction.VIEW_ID_TO_KEEP,
+                        appResources.getResourceName(mViewIdToKeep));
+            }
+            out.end(token);
+        }
+
+        public static PendingResources<Action> createFromProto(ProtoInputStream in)
+                throws Exception {
+            final LongSparseArray<Object> values = new LongSparseArray<>();
+
+            final long token = in.start(RemoteViewsProto.Action.VIEW_GROUP_REMOVE_ACTION);
+            while (in.nextField() != NO_MORE_FIELDS) {
+                switch (in.getFieldNumber()) {
+                    case (int) RemoteViewsProto.ViewGroupRemoveAction.VIEW_ID:
+                        values.put(RemoteViewsProto.ViewGroupRemoveAction.VIEW_ID,
+                                in.readString(RemoteViewsProto.ViewGroupRemoveAction.VIEW_ID));
+                        break;
+                    case (int) RemoteViewsProto.ViewGroupRemoveAction.VIEW_ID_TO_KEEP:
+                        values.put(RemoteViewsProto.ViewGroupRemoveAction.VIEW_ID_TO_KEEP,
+                                in.readString(
+                                        RemoteViewsProto.ViewGroupRemoveAction.VIEW_ID_TO_KEEP));
+                        break;
+                    default:
+                        Log.w(LOG_TAG, "Unhandled field while reading RemoteViews proto!\n"
+                                + ProtoUtils.currentFieldToString(in));
+                }
+            }
+            in.end(token);
+
+            checkContainsKeys(values, new long[]{RemoteViewsProto.ViewGroupRemoveAction.VIEW_ID});
+
+            return (context, resources, rootData, depth) -> {
+                int viewId = getAsIdentifier(resources, values,
+                        RemoteViewsProto.ViewGroupRemoveAction.VIEW_ID);
+                int viewIdToKeep = (values.indexOfKey(
+                        RemoteViewsProto.ViewGroupRemoveAction.VIEW_ID_TO_KEEP) >= 0)
+                        ? getAsIdentifier(resources, values,
+                        RemoteViewsProto.ViewGroupRemoveAction.VIEW_ID_TO_KEEP)
+                        : REMOVE_ALL_VIEWS_ID;
+                return new ViewGroupActionRemove(viewId, viewIdToKeep);
+            };
+        }
     }
 
     /**
@@ -4497,6 +4617,200 @@
                 visitIconUri(mI4, visitor);
             }
         }
+
+        @Override
+        public boolean canWriteToProto() {
+            return true;
+        }
+
+        @Override
+        public void writeToProto(ProtoOutputStream out, Context context,
+                Resources appResources) { // rebase
+            final long token = out.start(RemoteViewsProto.Action.TEXT_VIEW_DRAWABLE_ACTION);
+            out.write(RemoteViewsProto.TextViewDrawableAction.VIEW_ID,
+                    appResources.getResourceName(mViewId));
+            out.write(RemoteViewsProto.TextViewDrawableAction.IS_RELATIVE, mIsRelative);
+            if (mUseIcons) {
+                long iconsToken = out.start(RemoteViewsProto.TextViewDrawableAction.ICONS);
+                if (mI1 != null) {
+                    writeIconToProto(out, appResources, mI1,
+                            RemoteViewsProto.TextViewDrawableAction.Icons.ONE);
+                }
+                if (mI2 != null) {
+                    writeIconToProto(out, appResources, mI2,
+                            RemoteViewsProto.TextViewDrawableAction.Icons.TWO);
+                }
+                if (mI3 != null) {
+                    writeIconToProto(out, appResources, mI3,
+                            RemoteViewsProto.TextViewDrawableAction.Icons.THREE);
+                }
+                if (mI4 != null) {
+                    writeIconToProto(out, appResources, mI4,
+                            RemoteViewsProto.TextViewDrawableAction.Icons.FOUR);
+                }
+                out.end(iconsToken);
+            } else {
+                long resourcesToken = out.start(RemoteViewsProto.TextViewDrawableAction.RESOURCES);
+                if (mD1 != 0) {
+                    out.write(RemoteViewsProto.TextViewDrawableAction.Resources.ONE,
+                            appResources.getResourceName(mD1));
+                }
+                if (mD2 != 0) {
+                    out.write(RemoteViewsProto.TextViewDrawableAction.Resources.TWO,
+                            appResources.getResourceName(mD2));
+                }
+                if (mD3 != 0) {
+                    out.write(RemoteViewsProto.TextViewDrawableAction.Resources.THREE,
+                            appResources.getResourceName(mD3));
+                }
+                if (mD4 != 0) {
+                    out.write(RemoteViewsProto.TextViewDrawableAction.Resources.FOUR,
+                            appResources.getResourceName(mD4));
+                }
+                out.end(resourcesToken);
+            }
+            out.end(token);
+        }
+
+        public static PendingResources<Action> createFromProto(ProtoInputStream in)
+                throws Exception {
+            final LongSparseArray<Object> values = new LongSparseArray<>();
+
+            values.put(RemoteViewsProto.TextViewDrawableAction.ICONS,
+                    new SparseArray<PendingResources<Icon>>());
+            values.put(RemoteViewsProto.TextViewDrawableAction.RESOURCES,
+                    new SparseArray<String>());
+            final long token = in.start(RemoteViewsProto.Action.TEXT_VIEW_DRAWABLE_ACTION);
+            while (in.nextField() != NO_MORE_FIELDS) {
+                switch (in.getFieldNumber()) {
+                    case (int) RemoteViewsProto.TextViewDrawableAction.VIEW_ID:
+                        values.put(RemoteViewsProto.TextViewDrawableAction.VIEW_ID,
+                                in.readString(RemoteViewsProto.TextViewDrawableAction.VIEW_ID));
+                        break;
+                    case (int) RemoteViewsProto.TextViewDrawableAction.IS_RELATIVE:
+                        values.put(RemoteViewsProto.TextViewDrawableAction.IS_RELATIVE,
+                                in.readBoolean(
+                                        RemoteViewsProto.TextViewDrawableAction.IS_RELATIVE));
+                        break;
+                    case (int) RemoteViewsProto.TextViewDrawableAction.RESOURCES:
+                        final long resourcesToken = in.start(
+                                RemoteViewsProto.TextViewDrawableAction.RESOURCES);
+                        while (in.nextField() != NO_MORE_FIELDS) {
+                            switch (in.getFieldNumber()) {
+                                case (int) RemoteViewsProto.TextViewDrawableAction.Resources.ONE:
+                                    ((SparseArray<String>) values.get(
+                                            RemoteViewsProto.TextViewDrawableAction.RESOURCES)).put(
+                                            1, in.readString(
+                                                    RemoteViewsProto
+                                                            .TextViewDrawableAction.Resources.ONE));
+                                    break;
+                                case (int) RemoteViewsProto.TextViewDrawableAction.Resources.TWO:
+                                    ((SparseArray<String>) values.get(
+                                            RemoteViewsProto.TextViewDrawableAction.RESOURCES)).put(
+                                            2, in.readString(
+                                                    RemoteViewsProto
+                                                            .TextViewDrawableAction.Resources.TWO));
+                                    break;
+                                case (int) RemoteViewsProto.TextViewDrawableAction.Resources.THREE:
+                                    ((SparseArray<String>) values.get(
+                                            RemoteViewsProto.TextViewDrawableAction.RESOURCES)).put(
+                                            3, in.readString(
+                                                    RemoteViewsProto
+                                                            .TextViewDrawableAction
+                                                            .Resources.THREE));
+                                    break;
+                                case (int) RemoteViewsProto.TextViewDrawableAction.Resources.FOUR:
+                                    ((SparseArray<String>) values.get(
+                                            RemoteViewsProto.TextViewDrawableAction.RESOURCES)).put(
+                                            4, in.readString(
+                                                    RemoteViewsProto
+                                                            .TextViewDrawableAction
+                                                            .Resources.FOUR));
+                                    break;
+                                default:
+                                    Log.w(LOG_TAG,
+                                            "Unhandled field while reading RemoteViews proto!\n"
+                                                    + ProtoUtils.currentFieldToString(in));
+                            }
+                        }
+                        in.end(resourcesToken);
+                        break;
+                    case (int) RemoteViewsProto.TextViewDrawableAction.ICONS:
+                        final long iconsToken = in.start(
+                                RemoteViewsProto.TextViewDrawableAction.ICONS);
+                        while (in.nextField() != NO_MORE_FIELDS) {
+                            switch (in.getFieldNumber()) {
+                                case (int) RemoteViewsProto.TextViewDrawableAction.Icons.ONE:
+                                    ((SparseArray<PendingResources<Icon>>) values.get(
+                                            RemoteViewsProto.TextViewDrawableAction.ICONS)).put(1,
+                                            createIconFromProto(in,
+                                                    RemoteViewsProto
+                                                            .TextViewDrawableAction.Icons.ONE));
+                                    break;
+                                case (int) RemoteViewsProto.TextViewDrawableAction.Icons.TWO:
+                                    ((SparseArray<PendingResources<Icon>>) values.get(
+                                            RemoteViewsProto.TextViewDrawableAction.ICONS)).put(2,
+                                            createIconFromProto(in,
+                                                    RemoteViewsProto
+                                                            .TextViewDrawableAction.Icons.TWO));
+                                    break;
+                                case (int) RemoteViewsProto.TextViewDrawableAction.Icons.THREE:
+                                    ((SparseArray<PendingResources<Icon>>) values.get(
+                                            RemoteViewsProto.TextViewDrawableAction.ICONS)).put(3,
+                                            createIconFromProto(in,
+                                                    RemoteViewsProto
+                                                            .TextViewDrawableAction.Icons.THREE));
+                                    break;
+                                case (int) RemoteViewsProto.TextViewDrawableAction.Icons.FOUR:
+                                    ((SparseArray<PendingResources<Icon>>) values.get(
+                                            RemoteViewsProto.TextViewDrawableAction.ICONS)).put(4,
+                                            createIconFromProto(in,
+                                                    RemoteViewsProto
+                                                            .TextViewDrawableAction.Icons.FOUR));
+                                    break;
+                                default:
+                                    Log.w(LOG_TAG,
+                                            "Unhandled field while reading RemoteViews proto!\n"
+                                                    + ProtoUtils.currentFieldToString(in));
+                            }
+                        }
+                        in.end(iconsToken);
+                        break;
+                    default:
+                        Log.w(LOG_TAG, "Unhandled field while reading RemoteViews proto!\n"
+                                + ProtoUtils.currentFieldToString(in));
+                }
+            }
+            in.end(token);
+
+            checkContainsKeys(values, new long[]{RemoteViewsProto.TextViewDrawableAction.VIEW_ID});
+
+            return (context, resources, rootData, depth) -> {
+                int viewId = getAsIdentifier(resources, values,
+                        RemoteViewsProto.TextViewDrawableAction.VIEW_ID);
+                SparseArray<PendingResources<Icon>> icons =
+                        (SparseArray<PendingResources<Icon>>) values.get(
+                                RemoteViewsProto.TextViewDrawableAction.ICONS);
+                SparseArray<String> resArray = (SparseArray<String>) values.get(
+                        RemoteViewsProto.TextViewDrawableAction.RESOURCES);
+                boolean isRelative = (boolean) values.get(
+                        RemoteViewsProto.TextViewDrawableAction.IS_RELATIVE, false);
+                if (icons.size() > 0) {
+                    return new TextViewDrawableAction(viewId, isRelative,
+                            icons.get(1).create(context, resources, rootData, depth),
+                            icons.get(2).create(context, resources, rootData, depth),
+                            icons.get(3).create(context, resources, rootData, depth),
+                            icons.get(4).create(context, resources, rootData, depth));
+                } else {
+                    int first = resArray.contains(1) ? getAsIdentifier(resources, resArray, 1) : 0;
+                    int second = resArray.contains(2) ? getAsIdentifier(resources, resArray, 2) : 0;
+                    int third = resArray.contains(3) ? getAsIdentifier(resources, resArray, 3) : 0;
+                    int fourth = resArray.contains(4) ? getAsIdentifier(resources, resArray, 4) : 0;
+                    return new TextViewDrawableAction(viewId, isRelative, first, second, third,
+                            fourth);
+                }
+            };
+        }
     }
 
     /**
@@ -4535,6 +4849,58 @@
         public int getActionTag() {
             return TEXT_VIEW_SIZE_ACTION_TAG;
         }
+
+        @Override
+        public boolean canWriteToProto() {
+            return true;
+        }
+
+        @Override
+        public void writeToProto(ProtoOutputStream out, Context context, Resources appResources) {
+            final long token = out.start(RemoteViewsProto.Action.TEXT_VIEW_SIZE_ACTION);
+            out.write(RemoteViewsProto.TextViewSizeAction.VIEW_ID,
+                    appResources.getResourceName(mViewId));
+            out.write(RemoteViewsProto.TextViewSizeAction.UNITS, mUnits);
+            out.write(RemoteViewsProto.TextViewSizeAction.SIZE, mSize);
+            out.end(token);
+        }
+
+        public static PendingResources<Action> createFromProto(ProtoInputStream in)
+                throws Exception {
+            final LongSparseArray<Object> values = new LongSparseArray<>();
+
+            final long token = in.start(RemoteViewsProto.Action.TEXT_VIEW_SIZE_ACTION);
+            while (in.nextField() != NO_MORE_FIELDS) {
+                switch (in.getFieldNumber()) {
+                    case (int) RemoteViewsProto.TextViewSizeAction.VIEW_ID:
+                        values.put(RemoteViewsProto.TextViewSizeAction.VIEW_ID,
+                                in.readString(RemoteViewsProto.TextViewSizeAction.VIEW_ID));
+                        break;
+                    case (int) RemoteViewsProto.TextViewSizeAction.UNITS:
+                        values.put(RemoteViewsProto.TextViewSizeAction.UNITS,
+                                in.readInt(RemoteViewsProto.TextViewSizeAction.UNITS));
+                        break;
+                    case (int) RemoteViewsProto.TextViewSizeAction.SIZE:
+                        values.put(RemoteViewsProto.TextViewSizeAction.SIZE,
+                                in.readFloat(RemoteViewsProto.TextViewSizeAction.SIZE));
+                        break;
+                    default:
+                        Log.w(LOG_TAG, "Unhandled field while reading RemoteViews proto!\n"
+                                + ProtoUtils.currentFieldToString(in));
+                }
+            }
+            in.end(token);
+
+            checkContainsKeys(values, new long[]{RemoteViewsProto.TextViewSizeAction.VIEW_ID});
+
+            return (context, resources, rootData, depth) -> {
+                int viewId = getAsIdentifier(resources, values,
+                        RemoteViewsProto.TextViewSizeAction.VIEW_ID);
+                return new TextViewSizeAction(viewId,
+                        (int) values.get(RemoteViewsProto.TextViewSizeAction.UNITS, 0),
+                        (float) values.get(RemoteViewsProto.TextViewSizeAction.SIZE, 0));
+            };
+        }
     }
 
     /**
@@ -4579,6 +4945,70 @@
         public int getActionTag() {
             return VIEW_PADDING_ACTION_TAG;
         }
+
+        @Override
+        public boolean canWriteToProto() {
+            return true;
+        }
+
+        @Override
+        public void writeToProto(ProtoOutputStream out, Context context, Resources appResources) {
+            final long token = out.start(RemoteViewsProto.Action.VIEW_PADDING_ACTION);
+            out.write(RemoteViewsProto.ViewPaddingAction.VIEW_ID,
+                    appResources.getResourceName(mViewId));
+            out.write(RemoteViewsProto.ViewPaddingAction.LEFT, mLeft);
+            out.write(RemoteViewsProto.ViewPaddingAction.RIGHT, mRight);
+            out.write(RemoteViewsProto.ViewPaddingAction.TOP, mTop);
+            out.write(RemoteViewsProto.ViewPaddingAction.BOTTOM, mBottom);
+            out.end(token);
+        }
+
+        public static PendingResources<Action> createFromProto(ProtoInputStream in)
+                throws Exception {
+            final LongSparseArray<Object> values = new LongSparseArray<>();
+
+            final long token = in.start(RemoteViewsProto.Action.VIEW_PADDING_ACTION);
+            while (in.nextField() != NO_MORE_FIELDS) {
+                switch (in.getFieldNumber()) {
+                    case (int) RemoteViewsProto.ViewPaddingAction.VIEW_ID:
+                        values.put(RemoteViewsProto.ViewPaddingAction.VIEW_ID,
+                                in.readString(RemoteViewsProto.ViewPaddingAction.VIEW_ID));
+                        break;
+                    case (int) RemoteViewsProto.ViewPaddingAction.LEFT:
+                        values.put(RemoteViewsProto.ViewPaddingAction.LEFT,
+                                in.readInt(RemoteViewsProto.ViewPaddingAction.LEFT));
+                        break;
+                    case (int) RemoteViewsProto.ViewPaddingAction.RIGHT:
+                        values.put(RemoteViewsProto.ViewPaddingAction.RIGHT,
+                                in.readInt(RemoteViewsProto.ViewPaddingAction.RIGHT));
+                        break;
+                    case (int) RemoteViewsProto.ViewPaddingAction.TOP:
+                        values.put(RemoteViewsProto.ViewPaddingAction.TOP,
+                                in.readInt(RemoteViewsProto.ViewPaddingAction.TOP));
+                        break;
+                    case (int) RemoteViewsProto.ViewPaddingAction.BOTTOM:
+                        values.put(RemoteViewsProto.ViewPaddingAction.BOTTOM,
+                                in.readInt(RemoteViewsProto.ViewPaddingAction.BOTTOM));
+                        break;
+                    default:
+                        Log.w(LOG_TAG, "Unhandled field while reading RemoteViews proto!\n"
+                                + ProtoUtils.currentFieldToString(in));
+                }
+            }
+            in.end(token);
+
+            checkContainsKeys(values, new long[]{RemoteViewsProto.ViewPaddingAction.VIEW_ID});
+
+            return (context, resources, rootData, depth) -> {
+                int viewId = getAsIdentifier(resources, values,
+                        RemoteViewsProto.ViewPaddingAction.VIEW_ID);
+                return new ViewPaddingAction(viewId,
+                        (int) values.get(RemoteViewsProto.ViewPaddingAction.LEFT, 0),
+                        (int) values.get(RemoteViewsProto.ViewPaddingAction.TOP, 0),
+                        (int) values.get(RemoteViewsProto.ViewPaddingAction.RIGHT, 0),
+                        (int) values.get(RemoteViewsProto.ViewPaddingAction.BOTTOM, 0));
+            };
+        }
     }
 
     /**
@@ -5241,6 +5671,69 @@
         public int getActionTag() {
             return SET_VIEW_OUTLINE_RADIUS_TAG;
         }
+
+        @Override
+        public boolean canWriteToProto() {
+            return true;
+        }
+
+        @Override
+        public void writeToProto(ProtoOutputStream out, Context context, Resources appResources) {
+            final long token = out.start(
+                    RemoteViewsProto.Action.SET_VIEW_OUTLINE_PREFERRED_RADIUS_ACTION);
+            out.write(RemoteViewsProto.SetViewOutlinePreferredRadiusAction.VIEW_ID,
+                    appResources.getResourceName(mViewId));
+            out.write(RemoteViewsProto.SetViewOutlinePreferredRadiusAction.VALUE_TYPE, mValueType);
+            out.write(RemoteViewsProto.SetViewOutlinePreferredRadiusAction.VALUE, mValue);
+            out.end(token);
+        }
+
+        public static PendingResources<Action> createFromProto(ProtoInputStream in)
+                throws Exception {
+            final LongSparseArray<Object> values = new LongSparseArray<>();
+
+            final long token = in.start(
+                    RemoteViewsProto.Action.SET_VIEW_OUTLINE_PREFERRED_RADIUS_ACTION);
+            while (in.nextField() != NO_MORE_FIELDS) {
+                switch (in.getFieldNumber()) {
+                    case (int) RemoteViewsProto.SetViewOutlinePreferredRadiusAction.VIEW_ID:
+                        values.put(RemoteViewsProto.SetViewOutlinePreferredRadiusAction.VIEW_ID,
+                                in.readString(
+                                        RemoteViewsProto
+                                                .SetViewOutlinePreferredRadiusAction.VIEW_ID));
+                        break;
+                    case (int) RemoteViewsProto.SetViewOutlinePreferredRadiusAction.VALUE_TYPE:
+                        values.put(RemoteViewsProto.SetViewOutlinePreferredRadiusAction.VALUE_TYPE,
+                                in.readInt(
+                                        RemoteViewsProto
+                                                .SetViewOutlinePreferredRadiusAction.VALUE_TYPE));
+                        break;
+                    case (int) RemoteViewsProto.SetViewOutlinePreferredRadiusAction.VALUE:
+                        values.put(RemoteViewsProto.SetViewOutlinePreferredRadiusAction.VALUE,
+                                in.readInt(
+                                        RemoteViewsProto
+                                                .SetViewOutlinePreferredRadiusAction.VALUE));
+                        break;
+                    default:
+                        Log.w(LOG_TAG, "Unhandled field while reading RemoteViews proto!\n"
+                                + ProtoUtils.currentFieldToString(in));
+                }
+            }
+            in.end(token);
+
+            checkContainsKeys(values,
+                    new long[]{RemoteViewsProto.SetViewOutlinePreferredRadiusAction.VIEW_ID,
+                            RemoteViewsProto.SetViewOutlinePreferredRadiusAction.VALUE_TYPE});
+
+            return (context, resources, rootData, depth) -> {
+                int viewId = getAsIdentifier(resources, values,
+                        RemoteViewsProto.SetViewOutlinePreferredRadiusAction.VIEW_ID);
+                return new SetViewOutlinePreferredRadiusAction(viewId,
+                        (int) values.get(RemoteViewsProto.SetViewOutlinePreferredRadiusAction.VALUE,
+                                0), (int) values.get(
+                        RemoteViewsProto.SetViewOutlinePreferredRadiusAction.VALUE_TYPE));
+            };
+        }
     }
 
     /**
@@ -5324,6 +5817,46 @@
         public int getActionTag() {
             return SET_DRAW_INSTRUCTION_TAG;
         }
+
+        @Override
+        public boolean canWriteToProto() {
+            return drawDataParcel();
+        }
+
+        @Override
+        public void writeToProto(ProtoOutputStream out, Context context, Resources appResources) {
+            if (!drawDataParcel()) return;
+            final long token = out.start(RemoteViewsProto.Action.SET_DRAW_INSTRUCTION_ACTION);
+            if (mInstructions != null) {
+                for (byte[] bytes : mInstructions.mInstructions) {
+                    out.write(RemoteViewsProto.SetDrawInstructionAction.INSTRUCTIONS, bytes);
+                }
+            }
+            out.end(token);
+        }
+    }
+
+    @FlaggedApi(FLAG_DRAW_DATA_PARCEL)
+    private PendingResources<Action> createSetDrawInstructionActionFromProto(ProtoInputStream in)
+            throws Exception {
+        List<byte[]> instructions = new ArrayList<byte[]>();
+
+        final long token = in.start(RemoteViewsProto.Action.SET_DRAW_INSTRUCTION_ACTION);
+        while (in.nextField() != NO_MORE_FIELDS) {
+            switch (in.getFieldNumber()) {
+                case (int) RemoteViewsProto.SetDrawInstructionAction.INSTRUCTIONS:
+                    instructions.add(
+                            in.readBytes(RemoteViewsProto.SetDrawInstructionAction.INSTRUCTIONS));
+                    break;
+                default:
+                    Log.w(LOG_TAG, "Unhandled field while reading RemoteViews proto!\n"
+                            + ProtoUtils.currentFieldToString(in));
+            }
+        }
+        in.end(token);
+
+        return (context, resources, rootData, depth) -> new SetDrawInstructionAction(
+                new DrawInstructions.Builder(instructions).build());
     }
 
     /**
@@ -9604,12 +10137,20 @@
             }
             if (ref.mMode == MODE_NORMAL) {
                 rv.setIdealSize(ref.mIdealSize);
+                boolean hasDrawInstructionAction = false;
                 for (PendingResources<Action> pendingAction : ref.mActions) {
                     Action action = pendingAction.create(appContext, appResources, rootData, depth);
                     if (action != null) {
+                        if (action instanceof SetDrawInstructionAction) {
+                            hasDrawInstructionAction = true;
+                        }
                         rv.addAction(action);
                     }
                 }
+                if (rv.mHasDrawInstructions && !hasDrawInstructionAction) {
+                    throw new InvalidProtoException(
+                            "RemoteViews proto is missing DrawInstructions");
+                }
                 return rv;
             } else if (ref.mMode == MODE_HAS_SIZED_REMOTEVIEWS) {
                 List<RemoteViews> sizedViews = new ArrayList<>();
@@ -9685,6 +10226,23 @@
                 return rv.createSetRemoteCollectionItemListAdapterActionFromProto(in);
             case (int) RemoteViewsProto.Action.SET_RIPPLE_DRAWABLE_COLOR_ACTION:
                 return SetRippleDrawableColor.createFromProto(in);
+            case (int) RemoteViewsProto.Action.SET_VIEW_OUTLINE_PREFERRED_RADIUS_ACTION:
+                return SetViewOutlinePreferredRadiusAction.createFromProto(in);
+            case (int) RemoteViewsProto.Action.TEXT_VIEW_DRAWABLE_ACTION:
+                return TextViewDrawableAction.createFromProto(in);
+            case (int) RemoteViewsProto.Action.TEXT_VIEW_SIZE_ACTION:
+                return TextViewSizeAction.createFromProto(in);
+            case (int) RemoteViewsProto.Action.VIEW_GROUP_ADD_ACTION:
+                return rv.createViewGroupActionAddFromProto(in);
+            case (int) RemoteViewsProto.Action.VIEW_GROUP_REMOVE_ACTION:
+                return ViewGroupActionRemove.createFromProto(in);
+            case (int) RemoteViewsProto.Action.VIEW_PADDING_ACTION:
+                return ViewPaddingAction.createFromProto(in);
+            case (int) RemoteViewsProto.Action.SET_DRAW_INSTRUCTION_ACTION:
+                if (!drawDataParcel()) {
+                    return null;
+                }
+                return rv.createSetDrawInstructionActionFromProto(in);
             default:
                 throw new RuntimeException("Unhandled field while reading Action proto!\n"
                         + ProtoUtils.currentFieldToString(in));
diff --git a/core/java/android/window/BackMotionEvent.java b/core/java/android/window/BackMotionEvent.java
index 7cda3a3..8ac68ab 100644
--- a/core/java/android/window/BackMotionEvent.java
+++ b/core/java/android/window/BackMotionEvent.java
@@ -34,8 +34,6 @@
     private final float mTouchX;
     private final float mTouchY;
     private final float mProgress;
-    private final float mVelocityX;
-    private final float mVelocityY;
     private final boolean mTriggerBack;
 
     @BackEvent.SwipeEdge
@@ -51,10 +49,6 @@
      * @param touchX Absolute X location of the touch point of this event.
      * @param touchY Absolute Y location of the touch point of this event.
      * @param progress Value between 0 and 1 on how far along the back gesture is.
-     * @param velocityX X velocity computed from the touch point of this event.
-     *                  Value in pixels/second. {@link Float#NaN} if was not computed.
-     * @param velocityY Y velocity computed from the touch point of this event.
-     *                  Value in pixels/second. {@link Float#NaN} if was not computed.
      * @param triggerBack Indicates whether the back arrow is in the triggered state or not
      * @param swipeEdge Indicates which edge the swipe starts from.
      * @param departingAnimationTarget The remote animation target of the departing
@@ -64,16 +58,12 @@
             float touchX,
             float touchY,
             float progress,
-            float velocityX,
-            float velocityY,
             boolean triggerBack,
             @BackEvent.SwipeEdge int swipeEdge,
             @Nullable RemoteAnimationTarget departingAnimationTarget) {
         mTouchX = touchX;
         mTouchY = touchY;
         mProgress = progress;
-        mVelocityX = velocityX;
-        mVelocityY = velocityY;
         mTriggerBack = triggerBack;
         mSwipeEdge = swipeEdge;
         mDepartingAnimationTarget = departingAnimationTarget;
@@ -83,8 +73,6 @@
         mTouchX = in.readFloat();
         mTouchY = in.readFloat();
         mProgress = in.readFloat();
-        mVelocityX = in.readFloat();
-        mVelocityY = in.readFloat();
         mTriggerBack = in.readBoolean();
         mSwipeEdge = in.readInt();
         mDepartingAnimationTarget = in.readTypedObject(RemoteAnimationTarget.CREATOR);
@@ -113,8 +101,6 @@
         dest.writeFloat(mTouchX);
         dest.writeFloat(mTouchY);
         dest.writeFloat(mProgress);
-        dest.writeFloat(mVelocityX);
-        dest.writeFloat(mVelocityY);
         dest.writeBoolean(mTriggerBack);
         dest.writeInt(mSwipeEdge);
         dest.writeTypedObject(mDepartingAnimationTarget, flags);
@@ -145,24 +131,6 @@
     }
 
     /**
-     * Returns the X velocity computed from the touch point.
-     *
-     * @return value in pixels/second or {@link Float#NaN} if was not computed.
-     */
-    public float getVelocityX() {
-        return mVelocityX;
-    }
-
-    /**
-     * Returns the Y velocity computed from the touch point.
-     *
-     * @return value in pixels/second or {@link Float#NaN} if was not computed.
-     */
-    public float getVelocityY() {
-        return mVelocityY;
-    }
-
-    /**
      * Returns whether the back arrow is in the triggered state or not
      *
      * @return boolean indicating whether the back arrow is in the triggered state or not
@@ -195,8 +163,6 @@
                 + "mTouchX=" + mTouchX
                 + ", mTouchY=" + mTouchY
                 + ", mProgress=" + mProgress
-                + ", mVelocityX=" + mVelocityX
-                + ", mVelocityY=" + mVelocityY
                 + ", mTriggerBack=" + mTriggerBack
                 + ", mSwipeEdge" + mSwipeEdge
                 + ", mDepartingAnimationTarget" + mDepartingAnimationTarget
diff --git a/core/java/android/window/BackTouchTracker.java b/core/java/android/window/BackTouchTracker.java
index eb23af2..290c494 100644
--- a/core/java/android/window/BackTouchTracker.java
+++ b/core/java/android/window/BackTouchTracker.java
@@ -48,8 +48,6 @@
      */
     private float mInitTouchX;
     private float mInitTouchY;
-    private float mLatestVelocityX;
-    private float mLatestVelocityY;
     private float mStartThresholdX;
     private int mSwipeEdge;
     private boolean mShouldUpdateStartLocation = false;
@@ -58,7 +56,7 @@
     /**
      * Updates the tracker with a new motion event.
      */
-    public void update(float touchX, float touchY, float velocityX, float velocityY) {
+    public void update(float touchX, float touchY) {
         /**
          * If back was previously cancelled but the user has started swiping in the forward
          * direction again, restart back.
@@ -73,8 +71,6 @@
         }
         mLatestTouchX = touchX;
         mLatestTouchY = touchY;
-        mLatestVelocityX = velocityX;
-        mLatestVelocityY = velocityY;
     }
 
     /** Sets whether the back gesture is past the trigger threshold. */
@@ -156,8 +152,6 @@
                 /* touchX = */ mInitTouchX,
                 /* touchY = */ mInitTouchY,
                 /* progress = */ 0,
-                /* velocityX = */ 0,
-                /* velocityY = */ 0,
                 /* triggerBack = */ mTriggerBack,
                 /* swipeEdge = */ mSwipeEdge,
                 /* departingAnimationTarget = */ target);
@@ -242,8 +236,6 @@
                 /* touchX = */ mLatestTouchX,
                 /* touchY = */ mLatestTouchY,
                 /* progress = */ progress,
-                /* velocityX = */ mLatestVelocityX,
-                /* velocityY = */ mLatestVelocityY,
                 /* triggerBack = */ mTriggerBack,
                 /* swipeEdge = */ mSwipeEdge,
                 /* departingAnimationTarget = */ null);
diff --git a/core/java/android/window/flags/DesktopModeFlags.java b/core/java/android/window/DesktopModeFlags.java
similarity index 97%
rename from core/java/android/window/flags/DesktopModeFlags.java
rename to core/java/android/window/DesktopModeFlags.java
index 47af50da..8e35843e 100644
--- a/core/java/android/window/flags/DesktopModeFlags.java
+++ b/core/java/android/window/DesktopModeFlags.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.window.flags;
+package android.window;
 
 import android.annotation.Nullable;
 import android.app.ActivityThread;
@@ -65,7 +65,9 @@
     ENABLE_DESKTOP_WINDOWING_TASKBAR_RUNNING_APPS(
             Flags::enableDesktopWindowingTaskbarRunningApps, true),
     ENABLE_DESKTOP_WINDOWING_TRANSITIONS(Flags::enableDesktopWindowingTransitions, false),
-    ENABLE_DESKTOP_WINDOWING_EXIT_TRANSITIONS(Flags::enableDesktopWindowingExitTransitions, false);
+    ENABLE_DESKTOP_WINDOWING_EXIT_TRANSITIONS(Flags::enableDesktopWindowingExitTransitions, false),
+    ENABLE_WINDOWING_TRANSITION_HANDLERS_OBSERVERS(
+            Flags::enableWindowingTransitionHandlersObservers, false);
 
     private static final String TAG = "DesktopModeFlagsUtil";
     // Function called to obtain aconfig flag value.
diff --git a/core/java/android/window/ImeOnBackInvokedDispatcher.java b/core/java/android/window/ImeOnBackInvokedDispatcher.java
index 771dc7a..66c35e2 100644
--- a/core/java/android/window/ImeOnBackInvokedDispatcher.java
+++ b/core/java/android/window/ImeOnBackInvokedDispatcher.java
@@ -237,7 +237,7 @@
             try {
                 mIOnBackInvokedCallback.onBackStarted(
                         new BackMotionEvent(backEvent.getTouchX(), backEvent.getTouchY(),
-                                backEvent.getProgress(), 0f, 0f, false, backEvent.getSwipeEdge(),
+                                backEvent.getProgress(), false, backEvent.getSwipeEdge(),
                                 null));
             } catch (RemoteException e) {
                 Log.e(TAG, "Exception when invoking forwarded callback. e: ", e);
@@ -249,7 +249,7 @@
             try {
                 mIOnBackInvokedCallback.onBackProgressed(
                         new BackMotionEvent(backEvent.getTouchX(), backEvent.getTouchY(),
-                                backEvent.getProgress(), 0f, 0f, false, backEvent.getSwipeEdge(),
+                                backEvent.getProgress(), false, backEvent.getSwipeEdge(),
                                 null));
             } catch (RemoteException e) {
                 Log.e(TAG, "Exception when invoking forwarded callback. e: ", e);
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/data/repository/FixedColumnsRepositoryKosmos.kt b/core/java/android/window/KeyguardState.aidl
similarity index 76%
copy from packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/data/repository/FixedColumnsRepositoryKosmos.kt
copy to core/java/android/window/KeyguardState.aidl
index 2f5daaa..9612d95 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/data/repository/FixedColumnsRepositoryKosmos.kt
+++ b/core/java/android/window/KeyguardState.aidl
@@ -14,8 +14,9 @@
  * limitations under the License.
  */
 
-package com.android.systemui.qs.panels.data.repository
+package android.window;
 
-import com.android.systemui.kosmos.Kosmos
-
-val Kosmos.fixedColumnsRepository by Kosmos.Fixture { FixedColumnsRepository() }
+/**
+ * @hide
+ */
+parcelable KeyguardState;
diff --git a/core/java/android/window/KeyguardState.java b/core/java/android/window/KeyguardState.java
new file mode 100644
index 0000000..6584d30
--- /dev/null
+++ b/core/java/android/window/KeyguardState.java
@@ -0,0 +1,160 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.window;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Objects;
+
+/**
+ * Data object of params for Keyguard related {@link WindowContainerTransaction} operation.
+ *
+ * @hide
+ */
+public final class KeyguardState implements Parcelable {
+
+    private final int mDisplayId;
+
+    private final boolean mKeyguardShowing;
+
+    private final boolean mAodShowing;
+
+
+    private KeyguardState(int displayId, boolean keyguardShowing, boolean aodShowing) {
+        mDisplayId = displayId;
+        mKeyguardShowing = keyguardShowing;
+        mAodShowing = aodShowing;
+    }
+
+    private KeyguardState(Parcel in) {
+        mDisplayId = in.readInt();
+        mKeyguardShowing = in.readBoolean();
+        mAodShowing = in.readBoolean();
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeInt(mDisplayId);
+        dest.writeBoolean(mKeyguardShowing);
+        dest.writeBoolean(mAodShowing);
+    }
+
+    @NonNull
+    public static final Creator<KeyguardState> CREATOR =
+            new Creator<KeyguardState>() {
+                @Override
+                public KeyguardState createFromParcel(Parcel in) {
+                    return new KeyguardState(in);
+                }
+
+                @Override
+                public KeyguardState[] newArray(int size) {
+                    return new KeyguardState[size];
+                }
+            };
+
+    /**
+     * Gets the display id of this {@link KeyguardState}.
+     */
+    public int getDisplayId() {
+        return mDisplayId;
+    }
+
+    /** Returns the keyguard showing value. */
+    public boolean getKeyguardShowing() {
+        return mKeyguardShowing;
+    }
+
+    /** Returns the aod showing value. */
+    public boolean getAodShowing() {
+        return mAodShowing;
+    }
+
+    @Override
+    public String toString() {
+        return "KeyguardState{ displayId=" + mDisplayId
+                + ", keyguardShowing=" + mKeyguardShowing
+                + ", aodShowing=" + mAodShowing
+                + '}';
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mDisplayId, mKeyguardShowing, mAodShowing);
+    }
+
+    @Override
+    public boolean equals(@Nullable Object obj) {
+        if (!(obj instanceof KeyguardState other)) {
+            return false;
+        }
+        return mDisplayId == other.mDisplayId
+                && mKeyguardShowing == other.mKeyguardShowing
+                && mAodShowing == other.mAodShowing;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    /** Builder to construct the {@link KeyguardState}. */
+    public static final class Builder {
+
+        private final int mDisplayId;
+
+        private boolean mKeyguardShowing;
+
+        private boolean mAodShowing;
+
+        /**
+         * @param displayId the display of this {@link KeyguardState}.
+         */
+        public Builder(int displayId) {
+            mDisplayId = displayId;
+        }
+
+        /**
+         * Sets the boolean value for this operation.
+         */
+        @NonNull
+        public Builder setKeyguardShowing(boolean keyguardShowing) {
+            mKeyguardShowing = keyguardShowing;
+            return this;
+        }
+
+        /**
+         * Sets the boolean value for this operation.
+         */
+        @NonNull
+        public Builder setAodShowing(boolean aodShowing) {
+            mAodShowing = aodShowing;
+            return this;
+        }
+
+        /**
+         * Constructs the {@link KeyguardState}.
+         */
+        @NonNull
+        public KeyguardState build() {
+            return new KeyguardState(mDisplayId, mKeyguardShowing, mAodShowing);
+        }
+    }
+}
diff --git a/core/java/android/window/OWNERS b/core/java/android/window/OWNERS
index 2c61df9..77c99b9 100644
--- a/core/java/android/window/OWNERS
+++ b/core/java/android/window/OWNERS
@@ -1,3 +1,5 @@
 set noparent
 
 include /services/core/java/com/android/server/wm/OWNERS
+
+per-file DesktopModeFlags.java = file:/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/OWNERS
diff --git a/core/java/android/window/WindowContainerTransaction.java b/core/java/android/window/WindowContainerTransaction.java
index 0dc9263..8e495ec 100644
--- a/core/java/android/window/WindowContainerTransaction.java
+++ b/core/java/android/window/WindowContainerTransaction.java
@@ -869,6 +869,24 @@
     }
 
     /**
+     * Adds a {@link KeyguardState} to apply to the given displays.
+     *
+     * @hide
+     */
+    @NonNull
+    public WindowContainerTransaction addKeyguardState(
+            @NonNull KeyguardState keyguardState) {
+        Objects.requireNonNull(keyguardState);
+        final HierarchyOp hierarchyOp =
+                new HierarchyOp.Builder(
+                        HierarchyOp.HIERARCHY_OP_TYPE_SET_KEYGUARD_STATE)
+                        .setKeyguardState(keyguardState)
+                        .build();
+        mHierarchyOps.add(hierarchyOp);
+        return this;
+    }
+
+    /**
      * Sets/removes the always on top flag for this {@code windowContainer}. See
      * {@link com.android.server.wm.ConfigurationContainer#setAlwaysOnTop(boolean)}.
      * Please note that this method is only intended to be used for a
@@ -1469,6 +1487,7 @@
         public static final int HIERARCHY_OP_TYPE_SET_IS_TRIMMABLE = 19;
         public static final int HIERARCHY_OP_TYPE_RESTORE_BACK_NAVIGATION = 20;
         public static final int HIERARCHY_OP_TYPE_SET_EXCLUDE_INSETS_TYPES = 21;
+        public static final int HIERARCHY_OP_TYPE_SET_KEYGUARD_STATE = 22;
 
         // The following key(s) are for use with mLaunchOptions:
         // When launching a task (eg. from recents), this is the taskId to be launched.
@@ -1516,6 +1535,9 @@
         private TaskFragmentOperation mTaskFragmentOperation;
 
         @Nullable
+        private KeyguardState mKeyguardState;
+
+        @Nullable
         private PendingIntent mPendingIntent;
 
         @Nullable
@@ -1666,6 +1688,7 @@
             mLaunchOptions = copy.mLaunchOptions;
             mActivityIntent = copy.mActivityIntent;
             mTaskFragmentOperation = copy.mTaskFragmentOperation;
+            mKeyguardState = copy.mKeyguardState;
             mPendingIntent = copy.mPendingIntent;
             mShortcutInfo = copy.mShortcutInfo;
             mAlwaysOnTop = copy.mAlwaysOnTop;
@@ -1689,6 +1712,7 @@
             mLaunchOptions = in.readBundle();
             mActivityIntent = in.readTypedObject(Intent.CREATOR);
             mTaskFragmentOperation = in.readTypedObject(TaskFragmentOperation.CREATOR);
+            mKeyguardState = in.readTypedObject(KeyguardState.CREATOR);
             mPendingIntent = in.readTypedObject(PendingIntent.CREATOR);
             mShortcutInfo = in.readTypedObject(ShortcutInfo.CREATOR);
             mAlwaysOnTop = in.readBoolean();
@@ -1770,6 +1794,11 @@
         }
 
         @Nullable
+        public KeyguardState getKeyguardState() {
+            return mKeyguardState;
+        }
+
+        @Nullable
         public PendingIntent getPendingIntent() {
             return mPendingIntent;
         }
@@ -1902,6 +1931,9 @@
                             .append(" mExcludeInsetsTypes= ")
                             .append(WindowInsets.Type.toString(mExcludeInsetsTypes));
                     break;
+                case HIERARCHY_OP_TYPE_SET_KEYGUARD_STATE:
+                    sb.append("KeyguardState= ").append(mKeyguardState);
+                    break;
                 case HIERARCHY_OP_TYPE_SET_IS_TRIMMABLE:
                     sb.append("container= ").append(mContainer)
                             .append(" isTrimmable= ")
@@ -1932,6 +1964,7 @@
             dest.writeBundle(mLaunchOptions);
             dest.writeTypedObject(mActivityIntent, flags);
             dest.writeTypedObject(mTaskFragmentOperation, flags);
+            dest.writeTypedObject(mKeyguardState, flags);
             dest.writeTypedObject(mPendingIntent, flags);
             dest.writeTypedObject(mShortcutInfo, flags);
             dest.writeBoolean(mAlwaysOnTop);
@@ -1993,6 +2026,9 @@
             private TaskFragmentOperation mTaskFragmentOperation;
 
             @Nullable
+            private KeyguardState mKeyguardState;
+
+            @Nullable
             private PendingIntent mPendingIntent;
 
             @Nullable
@@ -2081,6 +2117,12 @@
                 return this;
             }
 
+            Builder setKeyguardState(
+                    @Nullable KeyguardState keyguardState) {
+                mKeyguardState = keyguardState;
+                return this;
+            }
+
             Builder setReparentLeafTaskIfRelaunch(boolean reparentLeafTaskIfRelaunch) {
                 mReparentLeafTaskIfRelaunch = reparentLeafTaskIfRelaunch;
                 return this;
@@ -2130,6 +2172,7 @@
                 hierarchyOp.mPendingIntent = mPendingIntent;
                 hierarchyOp.mAlwaysOnTop = mAlwaysOnTop;
                 hierarchyOp.mTaskFragmentOperation = mTaskFragmentOperation;
+                hierarchyOp.mKeyguardState = mKeyguardState;
                 hierarchyOp.mShortcutInfo = mShortcutInfo;
                 hierarchyOp.mBounds = mBounds;
                 hierarchyOp.mIncludingParents = mIncludingParents;
diff --git a/core/java/android/window/WindowOnBackInvokedDispatcher.java b/core/java/android/window/WindowOnBackInvokedDispatcher.java
index 51bc7d5..44a374f 100644
--- a/core/java/android/window/WindowOnBackInvokedDispatcher.java
+++ b/core/java/android/window/WindowOnBackInvokedDispatcher.java
@@ -124,7 +124,7 @@
         if (!isBackGestureInProgress() || ev == null || ev.getAction() != MotionEvent.ACTION_MOVE) {
             return;
         }
-        mTouchTracker.update(ev.getX(), ev.getY(), Float.NaN, Float.NaN);
+        mTouchTracker.update(ev.getX(), ev.getY());
         if (mTouchTracker.shouldUpdateStartLocation()) {
             // Reset the start location on the first event after starting back, so that
             // the beginning of the animation feels smooth.
diff --git a/core/java/android/window/flags/lse_desktop_experience.aconfig b/core/java/android/window/flags/lse_desktop_experience.aconfig
index b22aa22..155494f 100644
--- a/core/java/android/window/flags/lse_desktop_experience.aconfig
+++ b/core/java/android/window/flags/lse_desktop_experience.aconfig
@@ -228,7 +228,7 @@
     name: "enable_desktop_windowing_app_handle_education"
     namespace: "lse_desktop_experience"
     description: "Enables desktop windowing app handle education"
-    bug: "348208342"
+    bug: "316006079"
 }
 
 flag {
@@ -319,4 +319,11 @@
     namespace: "lse_desktop_experience"
     description: "Enables custom transitions for alt-tab app launches in Desktop Mode."
     bug: "370735595"
-}
\ No newline at end of file
+}
+
+flag {
+    name: "enable_move_to_next_display_shortcut"
+    namespace: "lse_desktop_experience"
+    description: "Add new keyboard shortcut of moving a task into next display"
+    bug: "364154795"
+}
diff --git a/core/java/android/window/flags/windowing_frontend.aconfig b/core/java/android/window/flags/windowing_frontend.aconfig
index c9b93c9..622f8c8 100644
--- a/core/java/android/window/flags/windowing_frontend.aconfig
+++ b/core/java/android/window/flags/windowing_frontend.aconfig
@@ -173,6 +173,16 @@
 }
 
 flag {
+  name: "filter_irrelevant_input_device_change"
+  namespace: "windowing_frontend"
+  description: "Recompute display configuration only for necessary input device changes"
+  bug: "368461853"
+  metadata {
+    purpose: PURPOSE_BUGFIX
+  }
+}
+
+flag {
   name: "respect_non_top_visible_fixed_orientation"
   namespace: "windowing_frontend"
   description: "If top activity is not opaque, respect the fixed orientation of activity behind it"
diff --git a/core/java/com/android/internal/accessibility/dialog/AccessibilityServiceWarning.java b/core/java/com/android/internal/accessibility/dialog/AccessibilityServiceWarning.java
index 0f8ced2..3557633 100644
--- a/core/java/com/android/internal/accessibility/dialog/AccessibilityServiceWarning.java
+++ b/core/java/com/android/internal/accessibility/dialog/AccessibilityServiceWarning.java
@@ -29,6 +29,7 @@
 import android.view.View;
 import android.view.Window;
 import android.view.WindowManager;
+import android.view.accessibility.Flags;
 import android.widget.Button;
 import android.widget.ImageView;
 import android.widget.TextView;
@@ -58,13 +59,15 @@
             @NonNull View.OnClickListener uninstallListener) {
         final AlertDialog ad = new AlertDialog.Builder(context)
                 .setView(createAccessibilityServiceWarningDialogContentView(
-                                context, info, allowListener, denyListener, uninstallListener))
+                        context, info, allowListener, denyListener, uninstallListener))
                 .setCancelable(true)
                 .create();
         Window window = ad.getWindow();
         WindowManager.LayoutParams params = window.getAttributes();
         params.privateFlags |= SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
-        params.type = WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG;
+        if (!Flags.warningUseDefaultDialogType()) {
+            params.type = WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG;
+        }
         window.setAttributes(params);
         return ad;
     }
diff --git a/core/java/com/android/internal/pm/pkg/component/AconfigFlags.java b/core/java/com/android/internal/pm/pkg/component/AconfigFlags.java
index 39aadfb..8faaf95 100644
--- a/core/java/com/android/internal/pm/pkg/component/AconfigFlags.java
+++ b/core/java/com/android/internal/pm/pkg/component/AconfigFlags.java
@@ -53,19 +53,18 @@
  * @hide
  */
 public class AconfigFlags {
+    private static final boolean DEBUG = false;
     private static final String LOG_TAG = "AconfigFlags";
-
-    public enum Permission {
-        READ_WRITE,
-        READ_ONLY
-    }
+    private static final String OVERRIDE_PREFIX = "device_config_overrides/";
+    private static final String STAGED_PREFIX = "staged/";
 
     private final ArrayMap<String, Boolean> mFlagValues = new ArrayMap<>();
-    private final ArrayMap<String, Permission> mFlagPermissions = new ArrayMap<>();
 
     public AconfigFlags() {
         if (!Flags.manifestFlagging()) {
-            Slog.v(LOG_TAG, "Feature disabled, skipped all loading");
+            if (DEBUG) {
+                Slog.v(LOG_TAG, "Feature disabled, skipped all loading");
+            }
             return;
         }
         final var defaultFlagProtoFiles =
@@ -130,19 +129,17 @@
                     if (!"false".equalsIgnoreCase(value) && !"true".equalsIgnoreCase(value)) {
                         continue;
                     }
-                    final var overridePrefix = "device_config_overrides/";
-                    final var stagedPrefix = "staged/";
                     String separator = "/";
                     String prefix = "default";
                     int priority = 0;
-                    if (name.startsWith(overridePrefix)) {
-                        prefix = overridePrefix;
-                        name = name.substring(overridePrefix.length());
+                    if (name.startsWith(OVERRIDE_PREFIX)) {
+                        prefix = OVERRIDE_PREFIX;
+                        name = name.substring(OVERRIDE_PREFIX.length());
                         separator = ":";
                         priority = 20;
-                    } else if (name.startsWith(stagedPrefix)) {
-                        prefix = stagedPrefix;
-                        name = name.substring(stagedPrefix.length());
+                    } else if (name.startsWith(STAGED_PREFIX)) {
+                        prefix = STAGED_PREFIX;
+                        name = name.substring(STAGED_PREFIX.length());
                         separator = "*";
                         priority = 10;
                     }
@@ -155,12 +152,19 @@
                     if (!mFlagValues.containsKey(flagPackageAndName)) {
                         continue;
                     }
-                    Slog.d(LOG_TAG, "Found " + prefix
-                            + " Aconfig flag value for " + flagPackageAndName + " = " + value);
+                    if (DEBUG) {
+                        Slog.d(LOG_TAG, "Found " + prefix
+                                + " Aconfig flag value in settings for " + flagPackageAndName
+                                + " = " + value);
+                    }
                     final Integer currentPriority = flagPriority.get(flagPackageAndName);
                     if (currentPriority != null && currentPriority >= priority) {
-                        Slog.i(LOG_TAG, "Skipping " + prefix + " flag " + flagPackageAndName
-                                + " because of the existing one with priority " + currentPriority);
+                        if (DEBUG) {
+                            Slog.d(LOG_TAG, "Skipping " + prefix + " flag "
+                                    + flagPackageAndName
+                                    + " in settings because of existing one with priority "
+                                    + currentPriority);
+                        }
                         continue;
                     }
                     flagPriority.put(flagPackageAndName, priority);
@@ -185,15 +189,7 @@
         for (parsed_flag flag : parsedFlags.parsedFlag) {
             String flagPackageAndName = flag.package_ + "." + flag.name;
             boolean flagValue = (flag.state == Aconfig.ENABLED);
-            Slog.v(LOG_TAG, "Read Aconfig default flag value "
-                    + flagPackageAndName + " = " + flagValue);
             mFlagValues.put(flagPackageAndName, flagValue);
-
-            Permission permission = flag.permission == Aconfig.READ_ONLY
-                    ? Permission.READ_ONLY
-                    : Permission.READ_WRITE;
-
-            mFlagPermissions.put(flagPackageAndName, permission);
         }
     }
 
@@ -203,24 +199,15 @@
      * @return the current value of the given Aconfig flag, or null if there is no such flag
      */
     @Nullable
-    public Boolean getFlagValue(@NonNull String flagPackageAndName) {
+    private Boolean getFlagValue(@NonNull String flagPackageAndName) {
         Boolean value = mFlagValues.get(flagPackageAndName);
-        Slog.d(LOG_TAG, "Aconfig flag value for " + flagPackageAndName + " = " + value);
+        if (DEBUG) {
+            Slog.v(LOG_TAG, "Aconfig flag value for " + flagPackageAndName + " = " + value);
+        }
         return value;
     }
 
     /**
-     * Get the flag permission, or null if the flag doesn't exist.
-     * @param flagPackageAndName Full flag name formatted as 'package.flag'
-     * @return the current permission of the given Aconfig flag, or null if there is no such flag
-     */
-    @Nullable
-    public Permission getFlagPermission(@NonNull String flagPackageAndName) {
-        Permission permission = mFlagPermissions.get(flagPackageAndName);
-        return permission;
-    }
-
-    /**
      * Check if the element in {@code parser} should be skipped because of the feature flag.
      * @param parser XML parser object currently parsing an element
      * @return true if the element is disabled because of its feature flag
@@ -247,7 +234,7 @@
         }
         // Skip if flag==false && attr=="flag" OR flag==true && attr=="!flag" (negated)
         if (flagValue == negated) {
-            Slog.v(LOG_TAG, "Skipping element " + parser.getName()
+            Slog.i(LOG_TAG, "Skipping element " + parser.getName()
                     + " behind feature flag " + featureFlag + " = " + flagValue);
             return true;
         }
diff --git a/core/java/com/android/internal/policy/DecorView.java b/core/java/com/android/internal/policy/DecorView.java
index 6faea17..bd746d5 100644
--- a/core/java/com/android/internal/policy/DecorView.java
+++ b/core/java/com/android/internal/policy/DecorView.java
@@ -38,8 +38,8 @@
 import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;
 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
 import static android.view.flags.Flags.customizableWindowHeaders;
-import static android.window.flags.DesktopModeFlags.ENABLE_CAPTION_COMPAT_INSET_FORCE_CONSUMPTION;
-import static android.window.flags.DesktopModeFlags.ENABLE_CAPTION_COMPAT_INSET_FORCE_CONSUMPTION_ALWAYS;
+import static android.window.DesktopModeFlags.ENABLE_CAPTION_COMPAT_INSET_FORCE_CONSUMPTION;
+import static android.window.DesktopModeFlags.ENABLE_CAPTION_COMPAT_INSET_FORCE_CONSUMPTION_ALWAYS;
 
 import static com.android.internal.policy.PhoneWindow.FEATURE_OPTIONS_PANEL;
 
diff --git a/core/java/com/android/internal/telephony/IPhoneStateListener.aidl b/core/java/com/android/internal/telephony/IPhoneStateListener.aidl
index f177e14..81b885a 100644
--- a/core/java/com/android/internal/telephony/IPhoneStateListener.aidl
+++ b/core/java/com/android/internal/telephony/IPhoneStateListener.aidl
@@ -78,8 +78,9 @@
     void onAllowedNetworkTypesChanged(in int reason, in long allowedNetworkType);
     void onLinkCapacityEstimateChanged(in List<LinkCapacityEstimate> linkCapacityEstimateList);
     void onMediaQualityStatusChanged(in MediaQualityStatus mediaQualityStatus);
-    void onCallBackModeStarted(int type);
-    void onCallBackModeStopped(int type, int reason);
+    void onCallbackModeStarted(int type, long durationMillis, int subId);
+    void onCallbackModeRestarted(int type, long durationMillis, int subId);
+    void onCallbackModeStopped(int type, int reason, int subId);
     void onSimultaneousCallingStateChanged(in int[] subIds);
     void onCarrierRoamingNtnModeChanged(in boolean active);
     void onCarrierRoamingNtnEligibleStateChanged(in boolean eligible);
diff --git a/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl b/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl
index e500a37a..f836cf2 100644
--- a/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl
+++ b/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl
@@ -118,7 +118,8 @@
     void removeCarrierConfigChangeListener(ICarrierConfigChangeListener listener, String pkg);
     void notifyCarrierConfigChanged(int phoneId, int subId, int carrierId, int specificCarrierId);
 
-    void notifyCallbackModeStarted(int phoneId, int subId, int type);
+    void notifyCallbackModeStarted(int phoneId, int subId, int type, long durationMillis);
+    void notifyCallbackModeRestarted(int phoneId, int subId, int type, long durationMillis);
     void notifyCallbackModeStopped(int phoneId, int subId, int type, int reason);
     void notifyCarrierRoamingNtnModeChanged(int subId, in boolean active);
     void notifyCarrierRoamingNtnEligibleStateChanged(int subId, in boolean eligible);
diff --git a/core/java/com/android/internal/util/MemInfoReader.java b/core/java/com/android/internal/util/MemInfoReader.java
index 0c5c853..d34bca6 100644
--- a/core/java/com/android/internal/util/MemInfoReader.java
+++ b/core/java/com/android/internal/util/MemInfoReader.java
@@ -88,6 +88,13 @@
     }
 
     /**
+     * Amount of RAM that used by shared memory (shmem) and tmpfs
+     */
+    public long getShmemSizeKb() {
+        return mInfos[Debug.MEMINFO_SHMEM];
+    }
+
+    /**
      * Amount of RAM that the kernel is being used for caches, not counting caches
      * that are mapped in to processes.
      */
diff --git a/core/java/com/android/internal/widget/NotificationProgressBar.java b/core/java/com/android/internal/widget/NotificationProgressBar.java
new file mode 100644
index 0000000..3e597d7
--- /dev/null
+++ b/core/java/com/android/internal/widget/NotificationProgressBar.java
@@ -0,0 +1,280 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.widget;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.Notification.ProgressStyle;
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.Icon;
+import android.os.Bundle;
+import android.util.AttributeSet;
+import android.view.RemotableViewMethod;
+import android.widget.ProgressBar;
+import android.widget.RemoteViews;
+
+import androidx.annotation.ColorInt;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.Preconditions;
+import com.android.internal.widget.NotificationProgressDrawable.Part;
+import com.android.internal.widget.NotificationProgressDrawable.Point;
+import com.android.internal.widget.NotificationProgressDrawable.Segment;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.SortedSet;
+import java.util.TreeSet;
+
+/**
+ * NotificationProgressBar extends the capabilities of ProgressBar by adding functionalities to
+ * represent Notification ProgressStyle progress, such as for ridesharing and navigation.
+ */
+@RemoteViews.RemoteView
+public class NotificationProgressBar extends ProgressBar {
+    private NotificationProgressModel mProgressModel;
+    @Nullable
+    private Drawable mProgressTrackerDrawable = null;
+
+    public NotificationProgressBar(Context context) {
+        this(context, null);
+    }
+
+    public NotificationProgressBar(Context context, AttributeSet attrs) {
+        this(context, attrs, com.android.internal.R.attr.progressBarStyle);
+    }
+
+    public NotificationProgressBar(Context context, AttributeSet attrs, int defStyleAttr) {
+        this(context, attrs, defStyleAttr, 0);
+    }
+
+    public NotificationProgressBar(Context context, AttributeSet attrs, int defStyleAttr,
+            int defStyleRes) {
+        super(context, attrs, defStyleAttr, defStyleRes);
+    }
+
+    /**
+     * Setter for the notification progress model.
+     *
+     * @see NotificationProgressModel#fromBundle
+     * @see #setProgressModelAsync
+     */
+    @RemotableViewMethod(asyncImpl = "setProgressModelAsync")
+    public void setProgressModel(@Nullable Bundle bundle) {
+        Preconditions.checkArgument(bundle != null,
+                "Bundle shouldn't be null");
+
+        mProgressModel = NotificationProgressModel.fromBundle(bundle);
+    }
+
+    private void setProgressModel(@NonNull NotificationProgressModel model) {
+        mProgressModel = model;
+    }
+
+    /**
+     * Setter for the progress tracker icon.
+     *
+     * @see #setProgressTrackerIconAsync
+     */
+    @RemotableViewMethod(asyncImpl = "setProgressTrackerIconAsync")
+    public void setProgressTrackerIcon(@Nullable Icon icon) {
+    }
+
+
+    /**
+     * Async version of {@link #setProgressTrackerIcon}
+     */
+    public Runnable setProgressTrackerIconAsync(@Nullable Icon icon) {
+        final Drawable progressTrackerDrawable;
+        if (icon != null) {
+            progressTrackerDrawable = icon.loadDrawable(getContext());
+        } else {
+            progressTrackerDrawable = null;
+        }
+        return () -> {
+            setProgressTrackerDrawable(progressTrackerDrawable);
+        };
+    }
+
+    private void setProgressTrackerDrawable(@Nullable  Drawable drawable) {
+        mProgressTrackerDrawable = drawable;
+    }
+
+    /**
+     * Processes the ProgressStyle data and convert to list of {@code
+     * NotificationProgressDrawable.Part}.
+     */
+    @VisibleForTesting
+    public static List<Part> processAndConvertToDrawableParts(
+            List<ProgressStyle.Segment> segments,
+            List<ProgressStyle.Point> points,
+            int progress,
+            boolean isStyledByProgress
+    ) {
+        if (segments.isEmpty()) {
+            throw new IllegalArgumentException("List of segments shouldn't be empty");
+        }
+
+        for (ProgressStyle.Segment segment : segments) {
+            final int length = segment.getLength();
+            if (length <= 0) {
+                throw new IllegalArgumentException("Invalid segment length : " + length);
+            }
+        }
+
+        final int progressMax = segments.stream().mapToInt(ProgressStyle.Segment::getLength).sum();
+
+        if (progress < 0 || progress > progressMax) {
+            throw new IllegalArgumentException("Invalid progress : " + progress);
+        }
+        for (ProgressStyle.Point point : points) {
+            final int pos = point.getPosition();
+            if (pos <= 0 || pos >= progressMax) {
+                throw new IllegalArgumentException("Invalid Point position : " + pos);
+            }
+        }
+
+        final Map<Integer, ProgressStyle.Segment> startToSegmentMap = generateStartToSegmentMap(
+                segments);
+        final Map<Integer, ProgressStyle.Point> positionToPointMap = generatePositionToPointMap(
+                points);
+        final SortedSet<Integer> sortedPos = generateSortedPositionSet(startToSegmentMap,
+                positionToPointMap, progress, isStyledByProgress);
+
+        final Map<Integer, ProgressStyle.Segment> startToSplitSegmentMap =
+                splitSegmentsByPointsAndProgress(
+                        startToSegmentMap, sortedPos, progressMax);
+
+        return convertToDrawableParts(startToSplitSegmentMap, positionToPointMap, sortedPos,
+                progress, progressMax,
+                isStyledByProgress);
+    }
+
+
+    // Any segment with a point on it gets split by the point.
+    // If isStyledByProgress is true, also split the segment with the progress value in its range.
+    private static Map<Integer, ProgressStyle.Segment> splitSegmentsByPointsAndProgress(
+            Map<Integer, ProgressStyle.Segment> startToSegmentMap,
+            SortedSet<Integer> sortedPos,
+            int progressMax) {
+        int prevSegStart = 0;
+        for (Integer pos : sortedPos) {
+            if (pos == 0 || pos == progressMax) continue;
+            if (startToSegmentMap.containsKey(pos)) {
+                prevSegStart = pos;
+                continue;
+            }
+
+            final ProgressStyle.Segment prevSeg = startToSegmentMap.get(prevSegStart);
+            final ProgressStyle.Segment leftSeg = new ProgressStyle.Segment(
+                    pos - prevSegStart).setColor(
+                    prevSeg.getColor());
+            final ProgressStyle.Segment rightSeg = new ProgressStyle.Segment(
+                    prevSegStart + prevSeg.getLength() - pos).setColor(prevSeg.getColor());
+
+            startToSegmentMap.put(prevSegStart, leftSeg);
+            startToSegmentMap.put(pos, rightSeg);
+
+            prevSegStart = pos;
+        }
+
+        return startToSegmentMap;
+    }
+
+    private static List<Part> convertToDrawableParts(
+            Map<Integer, ProgressStyle.Segment> startToSegmentMap,
+            Map<Integer, ProgressStyle.Point> positionToPointMap,
+            SortedSet<Integer> sortedPos,
+            int progress,
+            int progressMax,
+            boolean isStyledByProgress
+    ) {
+        List<Part> parts = new ArrayList<>();
+        boolean styleRemainingParts = false;
+        for (Integer pos : sortedPos) {
+            if (positionToPointMap.containsKey(pos)) {
+                final ProgressStyle.Point point = positionToPointMap.get(pos);
+                final int color = maybeGetFadedColor(point.getColor(), styleRemainingParts);
+                parts.add(new Point(null, color, styleRemainingParts));
+            }
+            // We want the Point at the current progress to be filled (not faded), but a Segment
+            // starting at this progress to be faded.
+            if (isStyledByProgress && !styleRemainingParts && pos == progress) {
+                styleRemainingParts = true;
+            }
+            if (startToSegmentMap.containsKey(pos)) {
+                final ProgressStyle.Segment seg = startToSegmentMap.get(pos);
+                final int color = maybeGetFadedColor(seg.getColor(), styleRemainingParts);
+                parts.add(new Segment(
+                        (float) seg.getLength() / progressMax, color, styleRemainingParts));
+            }
+        }
+
+        return parts;
+    }
+
+    @ColorInt
+    private static int maybeGetFadedColor(@ColorInt int color, boolean fade) {
+        if (!fade) return color;
+
+        return NotificationProgressDrawable.getFadedColor(color);
+    }
+
+    private static Map<Integer, ProgressStyle.Segment> generateStartToSegmentMap(
+            List<ProgressStyle.Segment> segments) {
+        final Map<Integer, ProgressStyle.Segment> startToSegmentMap = new HashMap<>();
+
+        int currentStart = 0;  // Initial start position is 0
+
+        for (ProgressStyle.Segment segment : segments) {
+            // Use the current start position as the key, and the segment as the value
+            startToSegmentMap.put(currentStart, segment);
+
+            // Update the start position for the next segment
+            currentStart += segment.getLength();
+        }
+
+        return startToSegmentMap;
+    }
+
+    private static Map<Integer, ProgressStyle.Point> generatePositionToPointMap(
+            List<ProgressStyle.Point> points) {
+        final Map<Integer, ProgressStyle.Point> positionToPointMap = new HashMap<>();
+
+        for (ProgressStyle.Point point : points) {
+            positionToPointMap.put(point.getPosition(), point);
+        }
+
+        return positionToPointMap;
+    }
+
+    private static SortedSet<Integer> generateSortedPositionSet(
+            Map<Integer, ProgressStyle.Segment> startToSegmentMap,
+            Map<Integer, ProgressStyle.Point> positionToPointMap, int progress,
+            boolean isStyledByProgress) {
+        final SortedSet<Integer> sortedPos = new TreeSet<>(startToSegmentMap.keySet());
+        sortedPos.addAll(positionToPointMap.keySet());
+        if (isStyledByProgress) {
+            sortedPos.add(progress);
+        }
+
+        return sortedPos;
+    }
+}
diff --git a/core/java/com/android/internal/widget/NotificationProgressDrawable.java b/core/java/com/android/internal/widget/NotificationProgressDrawable.java
new file mode 100644
index 0000000..89ef875
--- /dev/null
+++ b/core/java/com/android/internal/widget/NotificationProgressDrawable.java
@@ -0,0 +1,801 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.widget;
+
+import android.content.pm.ActivityInfo.Config;
+import android.content.res.Resources;
+import android.content.res.Resources.Theme;
+import android.content.res.TypedArray;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.ColorFilter;
+import android.graphics.DashPathEffect;
+import android.graphics.Paint;
+import android.graphics.PixelFormat;
+import android.graphics.Rect;
+import android.graphics.RectF;
+import android.graphics.drawable.Drawable;
+import android.util.AttributeSet;
+import android.util.DisplayMetrics;
+import android.util.Log;
+
+import androidx.annotation.ColorInt;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import com.android.internal.R;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Objects;
+
+/**
+ * This is used by NotificationProgressBar for displaying a custom background. It composes of
+ * segments, which have non-zero length, and points, which have zero length.
+ *
+ * @see Segment
+ * @see Point
+ */
+public final class NotificationProgressDrawable extends Drawable {
+    private static final String TAG = "NotifProgressDrawable";
+
+    private State mState;
+    private boolean mMutated;
+
+    private final ArrayList<Part> mParts = new ArrayList<>();
+
+    private final Rect mPointRect = new Rect();
+    private final RectF mPointRectF = new RectF();
+
+    private final Paint mStrokePaint = new Paint();
+    private final Paint mDashedStrokePaint = new Paint();
+    private final Paint mFillPaint = new Paint();
+
+    {
+        mStrokePaint.setStyle(Paint.Style.STROKE);
+        mStrokePaint.setStrokeCap(Paint.Cap.ROUND);
+
+        mDashedStrokePaint.setStyle(Paint.Style.STROKE);
+
+        mFillPaint.setStyle(Paint.Style.FILL);
+    }
+
+    private int mAlpha;
+
+    public NotificationProgressDrawable() {
+        this(new State(), null);
+    }
+
+    /**
+     * <p>Set the stroke width and default color for the drawable.</p>
+     * <p>Note: changing this property will affect all instances of a drawable loaded from a
+     * resource. It is recommended to invoke
+     * {@link #mutate()} before changing this property.</p>
+     *
+     * @param width The width in pixels of the stroke
+     * @param color The color of the stroke
+     * @see #mutate()
+     * @see #setStroke(int, int, float, float)
+     */
+    public void setStroke(int width, @ColorInt int color) {
+        setStroke(width, color, 0, 0);
+    }
+
+    /**
+     * <p>Set the stroke width and default color for the drawable. This method can also be used
+     * to dash the stroke for the dashed segments.</p>
+     * <p>Note: changing this property will affect all instances of a drawable loaded from a
+     * resource. It is recommended to invoke {@link #mutate()} before changing this property.</p>
+     *
+     * @param width     The width in pixels of the stroke
+     * @param color     The color of the stroke
+     * @param dashWidth The length in pixels of the dashes, set to 0 to disable dashes
+     * @param dashGap   The gap in pixels between dashes
+     * @see #mutate()
+     * @see #setStroke(int, int)
+     */
+    public void setStroke(int width, @ColorInt int color, float dashWidth, float dashGap) {
+        mState.setStroke(width, color, dashWidth, dashGap);
+        setStrokeInternal(width, dashWidth, dashGap);
+    }
+
+    /**
+     * <p>Set the stroke default color for the drawable.</p>
+     * <p>Note: changing this property will affect all instances of a drawable loaded from a
+     * resource. It is recommended to invoke {@link #mutate()} before changing this property.</p>
+     *
+     * @param color The color of the stroke
+     * @see #mutate()
+     * @see #setStroke(int, int, float, float)
+     */
+    public void setStrokeDefaultColor(@ColorInt int color) {
+        mState.setStrokeColor(color);
+    }
+
+    /**
+     * <p>Set the point rect default color for the drawable.</p>
+     * <p>Note: changing this property will affect all instances of a drawable loaded from a
+     * resource. It is recommended to invoke {@link #mutate()} before changing this property.</p>
+     *
+     * @param color The color of the point rect
+     * @see #mutate()
+     */
+    public void setPointRectDefaultColor(@ColorInt int color) {
+        mState.setPointRectColor(color);
+    }
+
+    private void setStrokeInternal(int width, float dashWidth, float dashGap) {
+        mStrokePaint.setStrokeWidth(width);
+
+        mDashedStrokePaint.setStrokeWidth(width);
+        DashPathEffect e = null;
+        if (dashWidth > 0) {
+            e = new DashPathEffect(new float[] { dashWidth, dashGap }, 0);
+        }
+        mDashedStrokePaint.setPathEffect(e);
+
+        invalidateSelf();
+    }
+
+    /**
+     *
+     */
+    public void setParts(@NonNull Part... parts) {
+        mParts.clear();
+        mParts.addAll(Arrays.asList(parts));
+    }
+
+    @Override
+    public void draw(@NonNull Canvas canvas) {
+        final float pointRadius =
+                mState.mPointRadius; // how big the point icon will be, halved
+
+        // generally, we will start drawing at (x, y) and end at (x+w, y)
+        float x = (float) getBounds().left;
+        final float centerY = (float) getBounds().centerY();
+        final float totalWidth = (float) getBounds().width();
+
+        final int numParts = mParts.size();
+        for (int iPart = 0; iPart < numParts; iPart++) {
+            final Part part = mParts.get(iPart);
+            final Part prevPart = iPart == 0 ? null : mParts.get(iPart - 1);
+            final Part nextPart = iPart + 1 == numParts ? null : mParts.get(iPart + 1);
+            if (part instanceof Segment segment) {
+                final float segWidth = segment.mFraction * totalWidth;
+                // Advance the start position to account for a point immediately prior.
+                final float startOffset = getSegStartOffset(prevPart, pointRadius,
+                        mState.mSegPointGap);
+                final float start = x + startOffset;
+                // Retract the end position to account for the padding and a point immediately
+                // after.
+                final float endOffset = getSegEndOffset(nextPart, pointRadius, mState.mSegPointGap,
+                        mState.mSegSegGap);
+                final float end = x + segWidth - endOffset;
+
+                // Transparent is not allowed (and also is the default in the data), so use that
+                // as a sentinel to be replaced by default
+                mStrokePaint.setColor(segment.mColor != Color.TRANSPARENT ? segment.mColor
+                        : mState.mStrokeColor);
+                mDashedStrokePaint.setColor(segment.mColor != Color.TRANSPARENT ? segment.mColor
+                        : mState.mFadedStrokeColor);
+
+                // Leave space for the rounded line cap which extends beyond start/end.
+                final float capWidth = mStrokePaint.getStrokeWidth() / 2F;
+
+                canvas.drawLine(start + capWidth, centerY, end - capWidth, centerY,
+                        segment.mDashed ? mDashedStrokePaint : mStrokePaint);
+
+                // Advance the current position to account for the segment's fraction of the total
+                // width (ignoring offset and padding)
+                x += segWidth;
+            } else if (part instanceof Point point) {
+                mPointRect.set((int) (x - pointRadius), (int) (centerY - pointRadius),
+                        (int) (x + pointRadius), (int) (centerY + pointRadius));
+                if (point.mIcon != null) {
+                    point.mIcon.setBounds(mPointRect);
+                    point.mIcon.draw(canvas);
+                } else {
+                    // TODO: b/367804171 - actually use a vector asset for the default point
+                    //  rather than drawing it as a box?
+                    mPointRectF.set(mPointRect);
+                    final float inset = mState.mPointRectInset;
+                    final float cornerRadius = mState.mPointRectCornerRadius;
+                    mPointRectF.inset(inset, inset);
+
+                    mFillPaint.setColor(point.mColor != Color.TRANSPARENT ? point.mColor
+                            : (point.mFaded ? mState.mFadedPointRectColor
+                                    : mState.mPointRectColor));
+
+                    canvas.drawRoundRect(mPointRectF, cornerRadius, cornerRadius, mFillPaint);
+                }
+            }
+        }
+    }
+
+    private static float getSegStartOffset(Part prevPart, float pointRadius, float segPointGap) {
+        return (prevPart instanceof Point) ? pointRadius + segPointGap : 0F;
+    }
+
+    private static float getSegEndOffset(Part nextPart, float pointRadius, float segPointGap,
+            float segSegGap) {
+        if (nextPart == null) return 0F;
+        return (nextPart instanceof Point) ? segPointGap + pointRadius : segSegGap;
+    }
+
+    @Override
+    public @Config int getChangingConfigurations() {
+        return super.getChangingConfigurations() | mState.getChangingConfigurations();
+    }
+
+    @Override
+    public void setAlpha(int alpha) {
+        if (mAlpha != alpha) {
+            mAlpha = alpha;
+            invalidateSelf();
+        }
+    }
+
+    @Override
+    public int getAlpha() {
+        return mAlpha;
+    }
+
+    @Override
+    public void setColorFilter(@Nullable ColorFilter colorFilter) {
+        // NO-OP
+    }
+
+    @Override
+    public int getOpacity() {
+        // This method is deprecated. Hence we return UNKNOWN.
+        return PixelFormat.UNKNOWN;
+    }
+
+    @Override
+    public void inflate(@NonNull Resources r, @NonNull XmlPullParser parser,
+            @NonNull AttributeSet attrs, @Nullable Resources.Theme theme)
+            throws XmlPullParserException, IOException {
+        super.inflate(r, parser, attrs, theme);
+
+        mState.setDensity(resolveDensity(r, 0));
+
+        final TypedArray a = obtainAttributes(r, theme, attrs,
+                R.styleable.NotificationProgressDrawable);
+        updateStateFromTypedArray(a);
+        a.recycle();
+
+        inflateChildElements(r, parser, attrs, theme);
+
+        updateLocalState();
+    }
+
+    @Override
+    public void applyTheme(@NonNull Theme t) {
+        super.applyTheme(t);
+
+        final State state = mState;
+        if (state == null) {
+            return;
+        }
+
+        state.setDensity(resolveDensity(t.getResources(), 0));
+
+        if (state.mThemeAttrs != null) {
+            final TypedArray a = t.resolveAttributes(
+                    state.mThemeAttrs, R.styleable.NotificationProgressDrawable);
+            updateStateFromTypedArray(a);
+            a.recycle();
+        }
+
+        applyThemeChildElements(t);
+
+        updateLocalState();
+    }
+
+    @Override
+    public boolean canApplyTheme() {
+        return (mState.canApplyTheme()) || super.canApplyTheme();
+    }
+
+    private void updateStateFromTypedArray(TypedArray a) {
+        final State state = mState;
+
+        // Account for any configuration changes.
+        state.mChangingConfigurations |= a.getChangingConfigurations();
+
+        // Extract the theme attributes, if any.
+        state.mThemeAttrs = a.extractThemeAttrs();
+
+        state.mSegSegGap = a.getDimension(R.styleable.NotificationProgressDrawable_segSegGap,
+                state.mSegSegGap);
+        state.mSegPointGap = a.getDimension(R.styleable.NotificationProgressDrawable_segPointGap,
+                state.mSegPointGap);
+    }
+
+    private void inflateChildElements(Resources r, XmlPullParser parser, AttributeSet attrs,
+            Theme theme) throws XmlPullParserException, IOException {
+        TypedArray a;
+        int type;
+
+        final int innerDepth = parser.getDepth() + 1;
+        int depth;
+        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+                && ((depth = parser.getDepth()) >= innerDepth
+                || type != XmlPullParser.END_TAG)) {
+            if (type != XmlPullParser.START_TAG) {
+                continue;
+            }
+
+            if (depth > innerDepth) {
+                continue;
+            }
+
+            String name = parser.getName();
+
+            if (name.equals("segments")) {
+                a = obtainAttributes(r, theme, attrs,
+                        R.styleable.NotificationProgressDrawableSegments);
+                updateSegmentsFromTypedArray(a);
+                a.recycle();
+            } else if (name.equals("points")) {
+                a = obtainAttributes(r, theme, attrs,
+                        R.styleable.NotificationProgressDrawablePoints);
+                updatePointsFromTypedArray(a);
+                a.recycle();
+            } else {
+                Log.w(TAG, "Bad element under NotificationProgressDrawable: " + name);
+            }
+        }
+    }
+
+    private void applyThemeChildElements(Theme t) {
+        final State state = mState;
+
+        if (state.mThemeAttrsSegments != null) {
+            final TypedArray a = t.resolveAttributes(
+                    state.mThemeAttrsSegments, R.styleable.NotificationProgressDrawableSegments);
+            updateSegmentsFromTypedArray(a);
+            a.recycle();
+        }
+
+        if (state.mThemeAttrsPoints != null) {
+            final TypedArray a = t.resolveAttributes(
+                    state.mThemeAttrsPoints, R.styleable.NotificationProgressDrawablePoints);
+            updateSegmentsFromTypedArray(a);
+            a.recycle();
+        }
+    }
+
+    private void updateSegmentsFromTypedArray(TypedArray a) {
+        final State state = mState;
+
+        // Account for any configuration changes.
+        state.mChangingConfigurations |= a.getChangingConfigurations();
+
+        // Extract the theme attributes, if any.
+        state.mThemeAttrsSegments = a.extractThemeAttrs();
+
+        final int width = a.getDimensionPixelSize(
+                R.styleable.NotificationProgressDrawableSegments_width, state.mStrokeWidth);
+        final float dashWidth = a.getDimension(
+                R.styleable.NotificationProgressDrawableSegments_dashWidth, state.mStrokeDashWidth);
+
+        final int color = a.getColor(R.styleable.NotificationProgressDrawableSegments_color,
+                state.mStrokeColor);
+
+        if (dashWidth != 0.0f) {
+            final float dashGap = a.getDimension(
+                    R.styleable.NotificationProgressDrawableSegments_dashGap, state.mStrokeDashGap);
+            setStroke(width, color, dashWidth, dashGap);
+        } else {
+            setStroke(width, color);
+        }
+    }
+
+    private void updatePointsFromTypedArray(TypedArray a) {
+        final State state = mState;
+
+        // Account for any configuration changes.
+        state.mChangingConfigurations |= a.getChangingConfigurations();
+
+        // Extract the theme attributes, if any.
+        state.mThemeAttrsPoints = a.extractThemeAttrs();
+
+        state.mPointRadius = a.getDimension(R.styleable.NotificationProgressDrawablePoints_radius,
+                state.mPointRadius);
+        state.mPointRectInset = a.getDimension(R.styleable.NotificationProgressDrawablePoints_inset,
+                state.mPointRectInset);
+        state.mPointRectCornerRadius = a.getDimension(
+                R.styleable.NotificationProgressDrawablePoints_cornerRadius,
+                state.mPointRectCornerRadius);
+        final int color = a.getColor(R.styleable.NotificationProgressDrawablePoints_color,
+                state.mPointRectColor);
+        setPointRectDefaultColor(color);
+    }
+
+    static int resolveDensity(@Nullable Resources r, int parentDensity) {
+        final int densityDpi = r == null ? parentDensity : r.getDisplayMetrics().densityDpi;
+        return densityDpi == 0 ? DisplayMetrics.DENSITY_DEFAULT : densityDpi;
+    }
+
+    /**
+     * Scales a floating-point pixel value from the source density to the
+     * target density.
+     */
+    private static float scaleFromDensity(float pixels, int sourceDensity, int targetDensity) {
+        return pixels * targetDensity / sourceDensity;
+    }
+
+    /**
+     * Scales a pixel value from the source density to the target density.
+     * <p>
+     * Optionally, when {@code isSize} is true, handles the resulting pixel value as a size,
+     * which is rounded to the closest positive integer.
+     * <p>
+     * Note: Iteratively applying density changes could result in drift of the pixel values due
+     * to rounding, especially for paddings which are truncated. Therefore it should be avoided.
+     * This isn't an issue for the notifications because the inflation pipeline reinflates
+     * notification views on density change.
+     */
+    private static int scaleFromDensity(
+            int pixels, int sourceDensity, int targetDensity, boolean isSize) {
+        if (pixels == 0 || sourceDensity == targetDensity) {
+            return pixels;
+        }
+
+        final float result = pixels * targetDensity / (float) sourceDensity;
+        if (!isSize) {
+            return (int) result;
+        }
+
+        final int rounded = Math.round(result);
+        if (rounded != 0) {
+            return rounded;
+        } else if (pixels > 0) {
+            return 1;
+        } else {
+            return -1;
+        }
+    }
+
+    /**
+     * A part of the progress bar, which is either a S{@link Segment} with non-zero length, or a
+     * {@link Point} with zero length.
+     */
+    public interface Part {
+    }
+
+    /**
+     * A segment is a part of the progress bar with non-zero length. For example, it can
+     * represent a portion in a navigation journey with certain traffic condition.
+     */
+    public static final class Segment implements Part {
+        private final float mFraction;
+        @ColorInt private final int mColor;
+        private final boolean mDashed;
+
+        public Segment(float fraction) {
+            this(fraction, Color.TRANSPARENT);
+        }
+
+        public Segment(float fraction, @ColorInt int color) {
+            this(fraction, color, false);
+        }
+
+        public Segment(float fraction, @ColorInt int color, boolean dashed) {
+            mFraction = fraction;
+            mColor = color;
+            mDashed = dashed;
+        }
+
+        public float getFraction() {
+            return this.mFraction;
+        }
+
+        public int getColor() {
+            return this.mColor;
+        }
+
+        public boolean getDashed() {
+            return this.mDashed;
+        }
+
+        @Override
+        public String toString() {
+            return "Segment(fraction=" + this.mFraction + ", color=" + this.mColor + ", dashed="
+                    + this.mDashed + ')';
+        }
+
+        // Needed for unit tests
+        @Override
+        public boolean equals(@Nullable Object other) {
+            if (this == other) return true;
+
+            if (other == null || getClass() != other.getClass()) return false;
+
+            Segment that = (Segment) other;
+            if (Float.compare(this.mFraction, that.mFraction) != 0) return false;
+            if (this.mColor != that.mColor) return false;
+            return this.mDashed == that.mDashed;
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(mFraction, mColor, mDashed);
+        }
+    }
+
+    /**
+     * A point is a part of the progress bar with zero length. Points are designated points within a
+     * progressbar to visualize distinct stages or milestones. For example, a stop in a multi-stop
+     * ride-share journey.
+     */
+    public static final class Point implements Part {
+        @Nullable
+        private final Drawable mIcon;
+        @ColorInt private final int mColor;
+        private final boolean mFaded;
+
+        public Point(@Nullable Drawable icon) {
+            this(icon, Color.TRANSPARENT, false);
+        }
+
+        public Point(@Nullable Drawable icon, @ColorInt int color) {
+            this(icon, color, false);
+
+        }
+
+        public Point(@Nullable Drawable icon, @ColorInt int color, boolean faded) {
+            mIcon = icon;
+            mColor = color;
+            mFaded = faded;
+        }
+
+        @Nullable
+        public Drawable getIcon() {
+            return this.mIcon;
+        }
+
+        public int getColor() {
+            return this.mColor;
+        }
+
+        public boolean getFaded() {
+            return this.mFaded;
+        }
+
+        @Override
+        public String toString() {
+            return "Point(icon=" + this.mIcon + ", color=" + this.mColor + ", faded=" + this.mFaded
+                    + ")";
+        }
+
+        // Needed for unit tests.
+        @Override
+        public boolean equals(@Nullable Object other) {
+            if (this == other) return true;
+
+            if (other == null || getClass() != other.getClass()) return false;
+
+            Point that = (Point) other;
+
+            if (!Objects.equals(this.mIcon, that.mIcon)) return false;
+            if (this.mColor != that.mColor) return false;
+            return this.mFaded == that.mFaded;
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(mIcon, mColor, mFaded);
+        }
+    }
+
+    @Override
+    public Drawable mutate() {
+        if (!mMutated && super.mutate() == this) {
+            mState = new State(mState, null);
+            updateLocalState();
+            mMutated = true;
+        }
+        return this;
+    }
+
+    @Override
+    public void clearMutated() {
+        super.clearMutated();
+        mMutated = false;
+    }
+
+    static final class State extends ConstantState {
+        @Config
+        int mChangingConfigurations;
+        float mSegSegGap = 0.0f;
+        float mSegPointGap = 0.0f;
+        int mStrokeWidth = 0;
+        int mStrokeColor;
+        int mFadedStrokeColor;
+        float mStrokeDashWidth = 0.0f;
+        float mStrokeDashGap = 0.0f;
+        float mPointRadius;
+        float mPointRectInset;
+        float mPointRectCornerRadius;
+        int mPointRectColor;
+        int mFadedPointRectColor;
+
+        int[] mThemeAttrs;
+        int[] mThemeAttrsSegments;
+        int[] mThemeAttrsPoints;
+
+        int mDensity = DisplayMetrics.DENSITY_DEFAULT;
+
+        State() {
+        }
+
+        State(@NonNull State orig, @Nullable Resources res) {
+            mChangingConfigurations = orig.mChangingConfigurations;
+            mStrokeColor = orig.mStrokeColor;
+            mFadedStrokeColor = orig.mFadedStrokeColor;
+            mStrokeWidth = orig.mStrokeWidth;
+            mStrokeDashWidth = orig.mStrokeDashWidth;
+            mStrokeDashGap = orig.mStrokeDashGap;
+            mPointRadius = orig.mPointRadius;
+            mPointRectInset = orig.mPointRectInset;
+            mPointRectCornerRadius = orig.mPointRectCornerRadius;
+            mPointRectColor = orig.mPointRectColor;
+            mFadedPointRectColor = orig.mFadedPointRectColor;
+
+            mThemeAttrs = orig.mThemeAttrs;
+            mThemeAttrsSegments = orig.mThemeAttrsSegments;
+            mThemeAttrsPoints = orig.mThemeAttrsPoints;
+
+            mDensity = resolveDensity(res, orig.mDensity);
+            if (orig.mDensity != mDensity) {
+                applyDensityScaling(orig.mDensity, mDensity);
+            }
+        }
+
+        private void applyDensityScaling(int sourceDensity, int targetDensity) {
+            if (mStrokeWidth > 0) {
+                mStrokeWidth = scaleFromDensity(
+                        mStrokeWidth, sourceDensity, targetDensity, true);
+            }
+            if (mStrokeDashWidth > 0) {
+                mStrokeDashWidth = scaleFromDensity(
+                        mStrokeDashWidth, sourceDensity, targetDensity);
+            }
+            if (mStrokeDashGap > 0) {
+                mStrokeDashGap = scaleFromDensity(
+                        mStrokeDashGap, sourceDensity, targetDensity);
+            }
+            if (mPointRadius > 0) {
+                mPointRadius = scaleFromDensity(
+                        mPointRadius, sourceDensity, targetDensity);
+            }
+            if (mPointRectInset > 0) {
+                mPointRectInset = scaleFromDensity(
+                        mPointRectInset, sourceDensity, targetDensity);
+            }
+            if (mPointRectCornerRadius > 0) {
+                mPointRectCornerRadius = scaleFromDensity(
+                        mPointRectCornerRadius, sourceDensity, targetDensity);
+            }
+        }
+
+        @NonNull
+        @Override
+        public Drawable newDrawable() {
+            return new NotificationProgressDrawable(this, null);
+        }
+
+        @Override
+        public Drawable newDrawable(@Nullable Resources res) {
+            // If this drawable is being created for a different density,
+            // just create a new constant state and call it a day.
+            final State state;
+            final int density = resolveDensity(res, mDensity);
+            if (density != mDensity) {
+                state = new State(this, res);
+            } else {
+                state = this;
+            }
+
+            return new NotificationProgressDrawable(state, res);
+        }
+
+        @Override
+        public int getChangingConfigurations() {
+            return mChangingConfigurations;
+        }
+
+        @Override
+        public boolean canApplyTheme() {
+            return mThemeAttrs != null || mThemeAttrsSegments != null || mThemeAttrsPoints != null
+                    || super.canApplyTheme();
+        }
+
+        public void setDensity(int targetDensity) {
+            if (mDensity != targetDensity) {
+                final int sourceDensity = mDensity;
+                mDensity = targetDensity;
+
+                applyDensityScaling(sourceDensity, targetDensity);
+            }
+        }
+
+        public void setStroke(int width, int color, float dashWidth, float dashGap) {
+            mStrokeWidth = width;
+            mStrokeDashWidth = dashWidth;
+            mStrokeDashGap = dashGap;
+
+            setStrokeColor(color);
+        }
+
+        public void setStrokeColor(int color) {
+            mStrokeColor = color;
+            mFadedStrokeColor = getFadedColor(color);
+        }
+
+        public void setPointRectColor(int color) {
+            mPointRectColor = color;
+            mFadedPointRectColor = getFadedColor(color);
+        }
+    }
+
+    /**
+     * Get a color with an opacity that's 50% of the input color.
+     */
+    @ColorInt
+    static int getFadedColor(@ColorInt int color) {
+        return Color.argb(Color.alpha(color) / 2, Color.red(color), Color.green(color),
+                Color.blue(color));
+    }
+
+    @Override
+    public ConstantState getConstantState() {
+        mState.mChangingConfigurations = getChangingConfigurations();
+        return mState;
+    }
+
+    /**
+     * Creates a new themed NotificationProgressDrawable based on the specified constant state.
+     * <p>
+     * The resulting drawable is guaranteed to have a new constant state.
+     *
+     * @param state Constant state from which the drawable inherits
+     */
+    private NotificationProgressDrawable(@NonNull State state, @Nullable Resources res) {
+        mState = state;
+
+        updateLocalState();
+    }
+
+    private void updateLocalState() {
+        final State state = mState;
+
+        mStrokePaint.setStrokeWidth(state.mStrokeWidth);
+
+        if (state.mStrokeDashWidth != 0.0f) {
+            final DashPathEffect e = new DashPathEffect(
+                    new float[] { state.mStrokeDashWidth, state.mStrokeDashGap }, 0);
+            mDashedStrokePaint.setPathEffect(e);
+        }
+    }
+}
diff --git a/core/java/com/android/internal/widget/NotificationProgressModel.java b/core/java/com/android/internal/widget/NotificationProgressModel.java
new file mode 100644
index 0000000..e51ea99
--- /dev/null
+++ b/core/java/com/android/internal/widget/NotificationProgressModel.java
@@ -0,0 +1,183 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.widget;
+
+
+import android.annotation.ColorInt;
+import android.annotation.FlaggedApi;
+import android.annotation.NonNull;
+import android.app.Flags;
+import android.app.Notification;
+import android.app.Notification.ProgressStyle.Point;
+import android.app.Notification.ProgressStyle.Segment;
+import android.graphics.Color;
+import android.os.Bundle;
+
+import com.android.internal.util.Preconditions;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * Data model for {@link NotificationProgressBar}.
+ *
+ * This class holds the necessary data to render the notification progressbar.
+ * It is used to bind the progress style progress data to {@link NotificationProgressBar}.
+ *
+ * @hide
+ * @see NotificationProgressModel#toBundle
+ * @see NotificationProgressModel#fromBundle
+ */
+@FlaggedApi(Flags.FLAG_API_RICH_ONGOING)
+public final class NotificationProgressModel {
+    private static final int INVALID_INDETERMINATE_COLOR = Color.TRANSPARENT;
+    private static final String KEY_SEGMENTS = "segments";
+    private static final String KEY_POINTS = "points";
+    private static final String KEY_PROGRESS = "progress";
+    private static final String KEY_IS_STYLED_BY_PROGRESS = "isStyledByProgress";
+    private static final String KEY_INDETERMINATE_COLOR = "indeterminateColor";
+    private final List<Segment> mSegments;
+    private final List<Point> mPoints;
+    private final int mProgress;
+    private final boolean mIsStyledByProgress;
+    @ColorInt
+    private final int mIndeterminateColor;
+
+    public NotificationProgressModel(
+            @NonNull List<Segment> segments,
+            @NonNull List<Point> points,
+            int progress,
+            boolean isStyledByProgress
+    ) {
+        Preconditions.checkArgument(progress >= 0);
+        Preconditions.checkArgument(!segments.isEmpty());
+        mSegments = segments;
+        mPoints = points;
+        mProgress = progress;
+        mIsStyledByProgress = isStyledByProgress;
+        mIndeterminateColor = INVALID_INDETERMINATE_COLOR;
+    }
+
+    public NotificationProgressModel(
+            @ColorInt int indeterminateColor
+    ) {
+        Preconditions.checkArgument(indeterminateColor != INVALID_INDETERMINATE_COLOR);
+        mSegments = Collections.emptyList();
+        mPoints = Collections.emptyList();
+        mProgress = 0;
+        mIsStyledByProgress = false;
+        mIndeterminateColor = indeterminateColor;
+    }
+
+    public List<Segment> getSegments() {
+        return mSegments;
+    }
+
+    public List<Point> getPoints() {
+        return mPoints;
+    }
+
+    public int getProgress() {
+        return mProgress;
+    }
+
+    public boolean isStyledByProgress() {
+        return mIsStyledByProgress;
+    }
+
+    @ColorInt
+    public int getIndeterminateColor() {
+        return mIndeterminateColor;
+    }
+
+    public boolean isIndeterminate() {
+        return mIndeterminateColor != INVALID_INDETERMINATE_COLOR;
+    }
+
+    /**
+     * Returns a {@link Bundle} representation of this {@link NotificationProgressModel}.
+     */
+    @NonNull
+    public Bundle toBundle() {
+        final Bundle bundle = new Bundle();
+        if (mIndeterminateColor != INVALID_INDETERMINATE_COLOR) {
+            bundle.putInt(KEY_INDETERMINATE_COLOR, mIndeterminateColor);
+        } else {
+            bundle.putParcelableList(KEY_SEGMENTS,
+                    Notification.ProgressStyle.getProgressSegmentsAsBundleList(mSegments));
+            bundle.putParcelableList(KEY_POINTS,
+                    Notification.ProgressStyle.getProgressPointsAsBundleList(mPoints));
+            bundle.putInt(KEY_PROGRESS, mProgress);
+            bundle.putBoolean(KEY_IS_STYLED_BY_PROGRESS, mIsStyledByProgress);
+        }
+        return bundle;
+    }
+
+    /**
+     * Creates a {@link NotificationProgressModel} from a {@link Bundle}.
+     */
+    @NonNull
+    public static NotificationProgressModel fromBundle(@NonNull Bundle bundle) {
+        final int indeterminateColor = bundle.getInt(KEY_INDETERMINATE_COLOR,
+                INVALID_INDETERMINATE_COLOR);
+        if (indeterminateColor != INVALID_INDETERMINATE_COLOR) {
+            return new NotificationProgressModel(indeterminateColor);
+        } else {
+            final List<Segment> segments =
+                    Notification.ProgressStyle.getProgressSegmentsFromBundleList(
+                            bundle.getParcelableArrayList(KEY_SEGMENTS, Bundle.class));
+            final List<Point> points =
+                    Notification.ProgressStyle.getProgressPointsFromBundleList(
+                            bundle.getParcelableArrayList(KEY_POINTS, Bundle.class));
+            final int progress = bundle.getInt(KEY_PROGRESS);
+            final boolean isStyledByProgress = bundle.getBoolean(KEY_IS_STYLED_BY_PROGRESS);
+            return new NotificationProgressModel(segments, points, progress, isStyledByProgress);
+        }
+    }
+
+    @Override
+    public String toString() {
+        return "NotificationProgressModel{"
+                + "mSegments=" + mSegments
+                + ", mPoints=" + mPoints
+                + ", mProgress=" + mProgress
+                + ", mIsStyledByProgress=" + mIsStyledByProgress
+                + ", mIndeterminateColor=" + mIndeterminateColor + "}";
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+        final NotificationProgressModel that = (NotificationProgressModel) o;
+        return mProgress == that.mProgress
+                && mIsStyledByProgress == that.mIsStyledByProgress
+                && mIndeterminateColor == that.mIndeterminateColor
+                && Objects.equals(mSegments, that.mSegments)
+                && Objects.equals(mPoints, that.mPoints);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mSegments,
+                mPoints,
+                mProgress,
+                mIsStyledByProgress,
+                mIndeterminateColor);
+    }
+}
diff --git a/core/java/com/android/internal/widget/PointerLocationView.java b/core/java/com/android/internal/widget/PointerLocationView.java
index c0a7383..46855c6 100644
--- a/core/java/com/android/internal/widget/PointerLocationView.java
+++ b/core/java/com/android/internal/widget/PointerLocationView.java
@@ -45,6 +45,7 @@
 import android.view.MotionEvent;
 import android.view.MotionEvent.PointerCoords;
 import android.view.RoundedCorner;
+import android.view.Surface;
 import android.view.VelocityTracker;
 import android.view.View;
 import android.view.ViewConfiguration;
@@ -84,7 +85,7 @@
         private boolean mCurDown;
 
         // Most recent coordinates.
-        private PointerCoords mCoords = new PointerCoords();
+        private final PointerCoords mCoords = new PointerCoords();
         private int mToolType;
 
         // Most recent velocity.
@@ -104,7 +105,7 @@
         public PointerState() {
         }
 
-        public void addTrace(float x, float y, boolean isHistorical) {
+        void addTrace(float x, float y, boolean isHistorical) {
             if (Float.isNaN(mFirstX)) {
                 mFirstX = x;
             }
@@ -148,8 +149,9 @@
 
     // Draw the trace of all pointers in the current gesture in a separate layer
     // that is not cleared on every frame so that we don't have to re-draw the
-    // entire trace on each frame.
-    private final Bitmap mTraceBitmap;
+    // entire trace on each frame. The trace bitmap is in the coordinate space of the unrotated
+    // display.
+    private Bitmap mTraceBitmap;
     private final Canvas mTraceCanvas;
 
     private final Region mSystemGestureExclusion = new Region();
@@ -200,9 +202,8 @@
         mPathPaint.setARGB(255, 0, 96, 255);
         mPathPaint.setStyle(Paint.Style.STROKE);
 
-        mTraceBitmap = Bitmap.createBitmap(getResources().getDisplayMetrics().widthPixels,
-                getResources().getDisplayMetrics().heightPixels, Bitmap.Config.ARGB_8888);
-        mTraceCanvas = new Canvas(mTraceBitmap);
+        mTraceCanvas = new Canvas();
+        configureTraceBitmap();
 
         configureDensityDependentFactors();
 
@@ -275,7 +276,7 @@
 
     // Draw an oval.  When angle is 0 radians, orients the major axis vertically,
     // angles less than or greater than 0 radians rotate the major axis left or right.
-    private RectF mReusableOvalRect = new RectF();
+    private final RectF mReusableOvalRect = new RectF();
 
     private void drawOval(Canvas canvas, float x, float y, float major, float minor,
             float angle, Paint paint) {
@@ -293,7 +294,11 @@
     protected void onDraw(Canvas canvas) {
         final int NP = mPointers.size();
 
+        // Pointer trace.
+        canvas.save();
+        rotateCanvasToUnrotatedDisplay(canvas);
         canvas.drawBitmap(mTraceBitmap, 0, 0, null);
+        canvas.restore();
 
         if (!mSystemGestureExclusion.isEmpty()) {
             mSystemGestureExclusionPath.reset();
@@ -310,7 +315,9 @@
         // Labels
         drawLabels(canvas);
 
-        // Pointer trace.
+        // Current pointer states.
+        canvas.save();
+        rotateCanvasToUnrotatedDisplay(canvas);
         for (int p = 0; p < NP; p++) {
             final PointerState ps = mPointers.valueAt(p);
             float lastX = ps.mCurrentX, lastY = ps.mCurrentY;
@@ -393,6 +400,7 @@
                 }
             }
         }
+        canvas.restore();
     }
 
     private void drawLabels(Canvas canvas) {
@@ -572,6 +580,11 @@
 
     @Override
     public void onPointerEvent(MotionEvent event) {
+        // PointerLocationView stores and draws events in the unrotated display space, so undo the
+        // event's rotation to bring it back to the unrotated display space.
+        event.transform(MotionEvent.createRotateMatrix(inverseRotation(event.getSurfaceRotation()),
+                mTraceBitmap.getWidth(), mTraceBitmap.getHeight()));
+
         final int action = event.getAction();
 
         if (action == MotionEvent.ACTION_DOWN
@@ -633,7 +646,7 @@
                     logCoords("Pointer", action, i, coords, id, event);
                 }
                 if (ps != null) {
-                    ps.addTrace(coords.x, coords.y, true);
+                    ps.addTrace(coords.x, coords.y, /*isHistorical*/ true);
                     updateDrawTrace(ps);
                 }
             }
@@ -647,7 +660,7 @@
                 logCoords("Pointer", action, i, coords, id, event);
             }
             if (ps != null) {
-                ps.addTrace(coords.x, coords.y, false);
+                ps.addTrace(coords.x, coords.y, /*isHistorical*/ false);
                 updateDrawTrace(ps);
                 ps.mXVelocity = mVelocity.getXVelocity(id);
                 ps.mYVelocity = mVelocity.getYVelocity(id);
@@ -704,11 +717,12 @@
         float y = ps.mCurrentY;
         float lastX = ps.mPreviousX;
         float lastY = ps.mPreviousY;
-        if (!Float.isNaN(x) && !Float.isNaN(y) && !Float.isNaN(lastX) && !Float.isNaN(lastY)) {
-            mTraceCanvas.drawLine(lastX, lastY, x, y, mPathPaint);
-            Paint paint = ps.mPreviousPointIsHistorical ? mPaint : mCurrentPointPaint;
-            mTraceCanvas.drawPoint(lastX, lastY, paint);
+        if (Float.isNaN(x) || Float.isNaN(y) || Float.isNaN(lastX) || Float.isNaN(lastY)) {
+            return;
         }
+        mTraceCanvas.drawLine(lastX, lastY, x, y, mPathPaint);
+        Paint paint = ps.mPreviousPointIsHistorical ? mPaint : mCurrentPointPaint;
+        mTraceCanvas.drawPoint(lastX, lastY, paint);
     }
 
     @Override
@@ -973,7 +987,7 @@
         }
     }
 
-    private ISystemGestureExclusionListener mSystemGestureExclusionListener =
+    private final ISystemGestureExclusionListener mSystemGestureExclusionListener =
             new ISystemGestureExclusionListener.Stub() {
                 @Override
                 public void onSystemGestureExclusionChanged(int displayId,
@@ -1000,6 +1014,7 @@
     @Override
     protected void onConfigurationChanged(Configuration newConfig) {
         super.onConfigurationChanged(newConfig);
+        configureTraceBitmap();
         configureDensityDependentFactors();
     }
 
@@ -1011,4 +1026,58 @@
         mCurrentPointPaint.setStrokeWidth(1 * mDensity);
         mPathPaint.setStrokeWidth(1 * mDensity);
     }
+
+    private void configureTraceBitmap() {
+        final var display = mContext.getDisplay();
+        final boolean rotated = display.getRotation() == Surface.ROTATION_90
+                || display.getRotation() == Surface.ROTATION_270;
+        int unrotatedWidth = rotated ? display.getHeight() : display.getWidth();
+        int unrotatedHeight = rotated ? display.getWidth() : display.getHeight();
+
+        if (mTraceBitmap != null && mTraceBitmap.getWidth() == unrotatedWidth
+                && mTraceBitmap.getHeight() == unrotatedHeight) {
+            return;
+        }
+        if (unrotatedWidth <= 0 || unrotatedHeight <= 0) {
+            Slog.w(TAG, "Ignoring configuration: invalid display size: " + unrotatedWidth + "x"
+                    + unrotatedHeight);
+            // Initialize the bitmap to an arbitrary size. It should be reconfigured with a valid
+            // size in the future.
+            unrotatedWidth = 100;
+            unrotatedHeight = 100;
+        }
+        mTraceBitmap = Bitmap.createBitmap(unrotatedWidth, unrotatedHeight,
+                Bitmap.Config.ARGB_8888);
+        mTraceCanvas.setBitmap(mTraceBitmap);
+    }
+
+    private static int inverseRotation(@Surface.Rotation int rotation) {
+        return switch(rotation) {
+            case Surface.ROTATION_0 -> Surface.ROTATION_0;
+            case Surface.ROTATION_90 -> Surface.ROTATION_270;
+            case Surface.ROTATION_180 -> Surface.ROTATION_180;
+            case Surface.ROTATION_270 -> Surface.ROTATION_90;
+            default -> {
+                Slog.e(TAG, "Received unexpected surface rotation: " + rotation);
+                yield Surface.ROTATION_0;
+            }
+        };
+    }
+
+    private void rotateCanvasToUnrotatedDisplay(Canvas c) {
+        switch (inverseRotation(mContext.getDisplay().getRotation())) {
+            case Surface.ROTATION_90 -> {
+                c.rotate(90);
+                c.translate(0, -mTraceBitmap.getHeight());
+            }
+            case Surface.ROTATION_180 -> {
+                c.rotate(180);
+                c.translate(-mTraceBitmap.getWidth(), -mTraceBitmap.getHeight());
+            }
+            case Surface.ROTATION_270 -> {
+                c.rotate(270);
+                c.translate(-mTraceBitmap.getWidth(), 0);
+            }
+        }
+    }
 }
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index 4d2195d..2bc3265 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -308,6 +308,7 @@
                 "spatializer-aidl-cpp",
                 "av-types-aidl-cpp",
                 "android.hardware.camera.device@3.2",
+                "camera_platform_flags_c_lib",
                 "libandroid_net",
                 "libbattery",
                 "libnetdutils",
diff --git a/core/jni/OWNERS b/core/jni/OWNERS
index af10623..af393fd 100644
--- a/core/jni/OWNERS
+++ b/core/jni/OWNERS
@@ -119,3 +119,4 @@
 
 # ApplicationSharedMemory
 per-file *ApplicationSharedMemory* = file:/PERFORMANCE_OWNERS
+per-file *PropertyInvalidatedCache* = file:/PERFORMANCE_OWNERS
diff --git a/core/jni/android_hardware_Camera.cpp b/core/jni/android_hardware_Camera.cpp
index 3f74fac..10e49ef 100644
--- a/core/jni/android_hardware_Camera.cpp
+++ b/core/jni/android_hardware_Camera.cpp
@@ -25,6 +25,7 @@
 #include <binder/Parcel.h>
 #include <camera/Camera.h>
 #include <camera/StringUtils.h>
+#include <com_android_internal_camera_flags.h>
 #include <cutils/properties.h>
 #include <gui/GLConsumer.h>
 #include <gui/Surface.h>
@@ -37,6 +38,7 @@
 #include "jni.h"
 
 using namespace android;
+namespace flags = com::android::internal::camera::flags;
 
 enum {
     // Keep up to date with Camera.java
@@ -527,14 +529,19 @@
 }
 
 static bool attributionSourceStateForJavaParcel(JNIEnv *env, jobject jClientAttributionParcel,
+                                                bool useContextAttributionSource,
                                                 AttributionSourceState &clientAttribution) {
     const Parcel *clientAttributionParcel = parcelForJavaObject(env, jClientAttributionParcel);
     if (clientAttribution.readFromParcel(clientAttributionParcel) != ::android::OK) {
         jniThrowRuntimeException(env, "Fail to unparcel AttributionSourceState");
         return false;
     }
-    clientAttribution.uid = Camera::USE_CALLING_UID;
-    clientAttribution.pid = Camera::USE_CALLING_PID;
+
+    if (!(useContextAttributionSource && flags::use_context_attribution_source())) {
+        clientAttribution.uid = Camera::USE_CALLING_UID;
+        clientAttribution.pid = Camera::USE_CALLING_PID;
+    }
+
     return true;
 }
 
@@ -542,7 +549,9 @@
                                                        jobject jClientAttributionParcel,
                                                        jint devicePolicy) {
     AttributionSourceState clientAttribution;
-    if (!attributionSourceStateForJavaParcel(env, jClientAttributionParcel, clientAttribution)) {
+    if (!attributionSourceStateForJavaParcel(env, jClientAttributionParcel,
+                                             /* useContextAttributionSource= */ false,
+                                             clientAttribution)) {
         return 0;
     }
     return Camera::getNumberOfCameras(clientAttribution, devicePolicy);
@@ -553,7 +562,9 @@
                                                   jobject jClientAttributionParcel,
                                                   jint devicePolicy, jobject info_obj) {
     AttributionSourceState clientAttribution;
-    if (!attributionSourceStateForJavaParcel(env, jClientAttributionParcel, clientAttribution)) {
+    if (!attributionSourceStateForJavaParcel(env, jClientAttributionParcel,
+                                             /* useContextAttributionSource= */ false,
+                                             clientAttribution)) {
         return;
     }
 
@@ -587,7 +598,9 @@
                                                  jobject jClientAttributionParcel,
                                                  jint devicePolicy) {
     AttributionSourceState clientAttribution;
-    if (!attributionSourceStateForJavaParcel(env, jClientAttributionParcel, clientAttribution)) {
+    if (!attributionSourceStateForJavaParcel(env, jClientAttributionParcel,
+                                             /* useContextAttributionSource= */ true,
+                                             clientAttribution)) {
         return -EACCES;
     }
 
diff --git a/core/jni/android_hardware_OverlayProperties.cpp b/core/jni/android_hardware_OverlayProperties.cpp
index 96494b1..63de195 100644
--- a/core/jni/android_hardware_OverlayProperties.cpp
+++ b/core/jni/android_hardware_OverlayProperties.cpp
@@ -17,6 +17,7 @@
 #define LOG_TAG "OverlayProperties"
 // #define LOG_NDEBUG 0
 
+#include <android/gui/LutProperties.h>
 #include <android/gui/OverlayProperties.h>
 #include <binder/Parcel.h>
 #include <gui/SurfaceComposerClient.h>
@@ -35,6 +36,12 @@
     jclass clazz;
     jmethodID ctor;
 } gOverlayPropertiesClassInfo;
+
+static struct {
+    jclass clazz;
+    jmethodID ctor;
+} gLutPropertiesClassInfo;
+
 // ----------------------------------------------------------------------------
 // OverlayProperties lifecycle
 // ----------------------------------------------------------------------------
@@ -95,6 +102,36 @@
     return reinterpret_cast<jlong>(overlayProperties);
 }
 
+static jobjectArray android_hardware_OverlayProperties_getLutProperties(JNIEnv* env, jobject thiz,
+                                                                        jlong nativeObject) {
+    gui::OverlayProperties* overlayProperties =
+            reinterpret_cast<gui::OverlayProperties*>(nativeObject);
+    if (overlayProperties->lutProperties.has_value()) {
+        return NULL;
+    }
+    auto& lutProperties = overlayProperties->lutProperties.value();
+    if (lutProperties.empty()) {
+        return NULL;
+    }
+    int32_t size = static_cast<int32_t>(lutProperties.size());
+    jobjectArray nativeLutProperties =
+            env->NewObjectArray(size, gLutPropertiesClassInfo.clazz, NULL);
+    if (nativeLutProperties == NULL) {
+        return NULL;
+    }
+    for (int32_t i = 0; i < size; i++) {
+        if (lutProperties[i].has_value()) {
+            auto& item = lutProperties[i].value();
+            jobject properties =
+                    env->NewObject(gLutPropertiesClassInfo.clazz, gLutPropertiesClassInfo.ctor,
+                                   static_cast<int32_t>(item.dimension), item.size,
+                                   item.samplingKeys.data());
+            env->SetObjectArrayElement(nativeLutProperties, i, properties);
+        }
+    }
+    return nativeLutProperties;
+}
+
 // ----------------------------------------------------------------------------
 // Serialization
 // ----------------------------------------------------------------------------
@@ -161,6 +198,8 @@
     { "nReadOverlayPropertiesFromParcel", "(Landroid/os/Parcel;)J",
             (void*) android_hardware_OverlayProperties_read },
     {"nCreateDefault", "()J", (void*) android_hardware_OverlayProperties_createDefault },
+    {"nGetLutProperties", "(J)[Landroid/hardware/LutProperties;",
+            (void*) android_hardware_OverlayProperties_getLutProperties },
 };
 // clang-format on
 
@@ -171,5 +210,9 @@
     gOverlayPropertiesClassInfo.clazz = MakeGlobalRefOrDie(env, clazz);
     gOverlayPropertiesClassInfo.ctor =
             GetMethodIDOrDie(env, gOverlayPropertiesClassInfo.clazz, "<init>", "(J)V");
+    clazz = FindClassOrDie(env, "android/hardware/LutProperties");
+    gLutPropertiesClassInfo.clazz = MakeGlobalRefOrDie(env, clazz);
+    gLutPropertiesClassInfo.ctor =
+            GetMethodIDOrDie(env, gLutPropertiesClassInfo.clazz, "<init>", "(IJ[I)V");
     return err;
 }
diff --git a/core/jni/android_media_AudioFormat.h b/core/jni/android_media_AudioFormat.h
index a9b1906..704aef3 100644
--- a/core/jni/android_media_AudioFormat.h
+++ b/core/jni/android_media_AudioFormat.h
@@ -50,6 +50,7 @@
 #define ENCODING_DTS_HD_MA 29
 #define ENCODING_DTS_UHD_P2 30
 #define ENCODING_DSD 31
+#define ENCODING_AC4_L4 32
 
 #define ENCODING_INVALID    0
 #define ENCODING_DEFAULT    1
@@ -95,6 +96,8 @@
         return AUDIO_FORMAT_AAC_XHE;
     case ENCODING_AC4:
         return AUDIO_FORMAT_AC4;
+    case ENCODING_AC4_L4:
+        return AUDIO_FORMAT_AC4_L4;
     case ENCODING_E_AC3_JOC:
         return AUDIO_FORMAT_E_AC3_JOC;
     case ENCODING_DEFAULT:
@@ -177,6 +180,8 @@
         return ENCODING_AAC_XHE;
     case AUDIO_FORMAT_AC4:
         return ENCODING_AC4;
+    case AUDIO_FORMAT_AC4_L4:
+        return ENCODING_AC4_L4;
     case AUDIO_FORMAT_E_AC3_JOC:
         return ENCODING_E_AC3_JOC;
     case AUDIO_FORMAT_MAT:
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index 71ba214..a939d92 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -33,11 +33,13 @@
 #include <android_runtime/android_view_Surface.h>
 #include <android_runtime/android_view_SurfaceControl.h>
 #include <android_runtime/android_view_SurfaceSession.h>
+#include <cutils/ashmem.h>
 #include <gui/ISurfaceComposer.h>
 #include <gui/Surface.h>
 #include <gui/SurfaceComposerClient.h>
 #include <jni.h>
 #include <nativehelper/JNIHelp.h>
+#include <nativehelper/ScopedPrimitiveArray.h>
 #include <nativehelper/ScopedUtfChars.h>
 #include <private/gui/ComposerService.h>
 #include <stdio.h>
@@ -736,6 +738,65 @@
     transaction->setDesiredHdrHeadroom(ctrl, desiredRatio);
 }
 
+static void nativeSetLuts(JNIEnv* env, jclass clazz, jlong transactionObj, jlong nativeObject,
+                          jfloatArray jbufferArray, jintArray joffsetArray,
+                          jintArray jdimensionArray, jintArray jsizeArray,
+                          jintArray jsamplingKeyArray) {
+    auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
+    SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl*>(nativeObject);
+
+    ScopedIntArrayRW joffsets(env, joffsetArray);
+    if (joffsets.get() == nullptr) {
+        jniThrowRuntimeException(env, "Failed to get ScopedIntArrayRW from joffsetArray");
+        return;
+    }
+    ScopedIntArrayRW jdimensions(env, jdimensionArray);
+    if (jdimensions.get() == nullptr) {
+        jniThrowRuntimeException(env, "Failed to get ScopedIntArrayRW from jdimensionArray");
+        return;
+    }
+    ScopedIntArrayRW jsizes(env, jsizeArray);
+    if (jsizes.get() == nullptr) {
+        jniThrowRuntimeException(env, "Failed to get ScopedIntArrayRW from jsizeArray");
+        return;
+    }
+    ScopedIntArrayRW jsamplingKeys(env, jsamplingKeyArray);
+    if (jsamplingKeys.get() == nullptr) {
+        jniThrowRuntimeException(env, "Failed to get ScopedIntArrayRW from jsamplingKeyArray");
+        return;
+    }
+
+    jsize numLuts = env->GetArrayLength(jdimensionArray);
+    std::vector<int32_t> offsets(joffsets.get(), joffsets.get() + numLuts);
+    std::vector<int32_t> dimensions(jdimensions.get(), jdimensions.get() + numLuts);
+    std::vector<int32_t> sizes(jsizes.get(), jsizes.get() + numLuts);
+    std::vector<int32_t> samplingKeys(jsamplingKeys.get(), jsamplingKeys.get() + numLuts);
+
+    ScopedFloatArrayRW jbuffers(env, jbufferArray);
+    if (jbuffers.get() == nullptr) {
+        jniThrowRuntimeException(env, "Failed to get ScopedFloatArrayRW from jbufferArray");
+        return;
+    }
+
+    // create the shared memory and copy jbuffers
+    size_t bufferSize = jbuffers.size() * sizeof(float);
+    int32_t fd = ashmem_create_region("lut_shread_mem", bufferSize);
+    if (fd < 0) {
+        jniThrowRuntimeException(env, "ashmem_create_region() failed");
+        return;
+    }
+    void* ptr = mmap(nullptr, bufferSize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+    if (ptr == MAP_FAILED) {
+        jniThrowRuntimeException(env, "Failed to map the shared memory");
+        return;
+    }
+    memcpy(ptr, jbuffers.get(), bufferSize);
+    // unmap
+    munmap(ptr, bufferSize);
+
+    transaction->setLuts(ctrl, base::unique_fd(fd), offsets, dimensions, sizes, samplingKeys);
+}
+
 static void nativeSetCachingHint(JNIEnv* env, jclass clazz, jlong transactionObj,
                                  jlong nativeObject, jint cachingHint) {
     auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
@@ -2541,6 +2602,7 @@
             (void*) nativeSetDesiredPresentTimeNanos },
     {"nativeNotifyShutdown", "()V",
             (void*)nativeNotifyShutdown },
+    {"nativeSetLuts", "(JJ[F[I[I[I[I)V", (void*)nativeSetLuts },
         // clang-format on
 };
 
diff --git a/core/jni/android_view_WindowManagerGlobal.cpp b/core/jni/android_view_WindowManagerGlobal.cpp
index abc621d..4202de3 100644
--- a/core/jni/android_view_WindowManagerGlobal.cpp
+++ b/core/jni/android_view_WindowManagerGlobal.cpp
@@ -69,8 +69,8 @@
     JNIEnv* env = AndroidRuntime::getJNIEnv();
 
     ScopedLocalRef<jobject> clientTokenObj(env, javaObjectForIBinder(env, clientToken));
-    env->CallStaticObjectMethod(gWindowManagerGlobal.clazz, gWindowManagerGlobal.removeInputChannel,
-                                clientTokenObj.get());
+    env->CallStaticVoidMethod(gWindowManagerGlobal.clazz, gWindowManagerGlobal.removeInputChannel,
+                              clientTokenObj.get());
 }
 
 int register_android_view_WindowManagerGlobal(JNIEnv* env) {
@@ -88,4 +88,4 @@
     return NO_ERROR;
 }
 
-} // namespace android
\ No newline at end of file
+} // namespace android
diff --git a/core/jni/platform/host/HostRuntime.cpp b/core/jni/platform/host/HostRuntime.cpp
index 88b3e1c..06621c9 100644
--- a/core/jni/platform/host/HostRuntime.cpp
+++ b/core/jni/platform/host/HostRuntime.cpp
@@ -20,7 +20,9 @@
 #include <android_runtime/AndroidRuntime.h>
 #include <jni_wrappers.h>
 #include <nativehelper/JNIHelp.h>
+#include <nativehelper/ScopedUtfChars.h>
 #include <nativehelper/jni_macros.h>
+#include <unicode/locid.h>
 #include <unicode/putil.h>
 #include <unicode/udata.h>
 
@@ -64,8 +66,8 @@
 };
 
 int register_libcore_util_NativeAllocationRegistry(JNIEnv* env) {
-    return jniRegisterNativeMethods(env, "libcore/util/NativeAllocationRegistry", gMethods,
-                                    NELEM(gMethods));
+    return android::RegisterMethodsOrDie(env, "libcore/util/NativeAllocationRegistry", gMethods,
+                                         NELEM(gMethods));
 }
 
 namespace android {
@@ -115,9 +117,9 @@
 #ifdef __linux__
         {"android.content.res.ApkAssets", REG_JNI(register_android_content_res_ApkAssets)},
         {"android.content.res.AssetManager", REG_JNI(register_android_content_AssetManager)},
+#endif
         {"android.content.res.StringBlock", REG_JNI(register_android_content_StringBlock)},
         {"android.content.res.XmlBlock", REG_JNI(register_android_content_XmlBlock)},
-#endif
         {"android.database.CursorWindow", REG_JNI(register_android_database_CursorWindow)},
         {"android.database.sqlite.SQLiteConnection",
          REG_JNI(register_android_database_SQLiteConnection)},
@@ -259,35 +261,67 @@
 #endif
 }
 
-// Loads the ICU data file from the location specified in the system property ro.icu.data.path
-static void loadIcuData() {
-    string icuPath = base::GetProperty("ro.icu.data.path", "");
-    if (!icuPath.empty()) {
-        // Set the location of ICU data
-        void* addr = mmapFile(icuPath.c_str());
-        UErrorCode err = U_ZERO_ERROR;
-        udata_setCommonData(addr, &err);
-        if (err != U_ZERO_ERROR) {
-            ALOGE("Unable to load ICU data\n");
-        }
-    }
-}
-
-static int register_android_core_classes(JNIEnv* env) {
+// returns result from java.lang.System.getProperty
+static string getJavaProperty(JNIEnv* env, const char* property_name) {
     jclass system = FindClassOrDie(env, "java/lang/System");
     jmethodID getPropertyMethod =
             GetStaticMethodIDOrDie(env, system, "getProperty",
                                    "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;");
 
-    // Get the names of classes that need to register their native methods
-    auto nativesClassesJString =
-            (jstring)env->CallStaticObjectMethod(system, getPropertyMethod,
-                                                 env->NewStringUTF("core_native_classes"),
-                                                 env->NewStringUTF(""));
-    const char* nativesClassesArray = env->GetStringUTFChars(nativesClassesJString, nullptr);
-    string nativesClassesString(nativesClassesArray);
+    auto jString = (jstring)env->CallStaticObjectMethod(system, getPropertyMethod,
+                                                        env->NewStringUTF(property_name),
+                                                        env->NewStringUTF(""));
+    ScopedUtfChars chars(env, jString);
+    return string(chars.c_str());
+}
+
+static void loadIcuData(string icuPath) {
+    void* addr = mmapFile(icuPath.c_str());
+    UErrorCode err = U_ZERO_ERROR;
+    udata_setCommonData(addr, &err);
+    if (err != U_ZERO_ERROR) {
+        ALOGE("Unable to load ICU data\n");
+    }
+}
+
+// Loads the ICU data file from the location specified in properties.
+// First try specified in the system property ro.icu.data.path,
+// then fallback to java property icu.data.path
+static void loadIcuData() {
+    JNIEnv* env = AndroidRuntime::getJNIEnv();
+    string icuPath = base::GetProperty("ro.icu.data.path", "");
+    if (!icuPath.empty()) {
+        loadIcuData(icuPath);
+    } else {
+        // fallback to read from java.lang.System.getProperty
+        string icuPathFromJava = getJavaProperty(env, "icu.data.path");
+        if (!icuPathFromJava.empty()) {
+            loadIcuData(icuPathFromJava);
+        }
+    }
+
+    // Check for the ICU default locale property. In Libcore, the default ICU
+    // locale is set when ICU.setDefaultLocale is called, which is called by
+    // Libcore's implemenentation of Java's Locale.setDefault. The default
+    // locale is used in cases such as when ucol_open(NULL, ...) is called, for
+    // example in SQLite's 'COLLATE UNICODE'.
+    string icuLocaleDefault = getJavaProperty(env, "icu.locale.default");
+    if (!icuLocaleDefault.empty()) {
+        UErrorCode status = U_ZERO_ERROR;
+        icu::Locale locale = icu::Locale::forLanguageTag(icuLocaleDefault.c_str(), status);
+        if (U_SUCCESS(status)) {
+            icu::Locale::setDefault(locale, status);
+        }
+        if (U_FAILURE(status)) {
+            fprintf(stderr, "Failed to set the ICU default locale to '%s' (error code %d)\n",
+                    icuLocaleDefault.c_str(), status);
+        }
+    }
+}
+
+static int register_android_core_classes(JNIEnv* env) {
+    string nativesClassesString = getJavaProperty(env, "core_native_classes");
     vector<string> classesToRegister = parseCsv(nativesClassesString);
-    env->ReleaseStringUTFChars(nativesClassesJString, nativesClassesArray);
 
     if (register_jni_procs(gRegJNIMap, classesToRegister, env) < 0) {
         return JNI_ERR;
@@ -359,6 +393,11 @@
 
 void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote) {
     JNIEnv* env = AndroidRuntime::getJNIEnv();
+
+    auto method_binding_format = getJavaProperty(env, "method_binding_format");
+
+    setJniMethodFormat(method_binding_format);
+
     // Register native functions.
     if (startReg(env) < 0) {
         ALOGE("Unable to register all android native methods\n");
diff --git a/core/proto/android/providers/settings/system.proto b/core/proto/android/providers/settings/system.proto
index e795e809..9779dc0e 100644
--- a/core/proto/android/providers/settings/system.proto
+++ b/core/proto/android/providers/settings/system.proto
@@ -220,6 +220,15 @@
     }
     optional Touchpad touchpad = 36;
 
+    message Mouse {
+        option (android.msg_privacy).dest = DEST_EXPLICIT;
+
+        optional SettingProto reverse_vertical_scrolling = 1 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto swap_primary_button = 2 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    }
+
+    optional Mouse mouse = 38;
+
     optional SettingProto tty_mode = 31 [ (android.privacy).dest = DEST_AUTOMATIC ];
 
     message Vibrate {
@@ -277,5 +286,5 @@
 
     // Please insert fields in alphabetical order and group them into messages
     // if possible (to avoid reaching the method limit).
-    // Next tag = 38;
+    // Next tag = 39;
 }
diff --git a/core/proto/android/widget/remoteviews.proto b/core/proto/android/widget/remoteviews.proto
index f477d32..6a987a4 100644
--- a/core/proto/android/widget/remoteviews.proto
+++ b/core/proto/android/widget/remoteviews.proto
@@ -32,6 +32,8 @@
  *
  * Do not change the tag number or type of any fields in order to maintain compatibility with
  * previous versions. If a field is deleted, use `reserved` to mark its tag number.
+ *
+ * Next tag: 17
  */
 message RemoteViewsProto {
     option (android.msg_privacy).dest = DEST_AUTOMATIC;
@@ -290,6 +292,7 @@
         }
     }
 
+    // Next tag: 23
     message Action {
         oneof action {
             AttributeReflectionAction attribute_reflection_action = 1;
@@ -307,6 +310,13 @@
             SetRadioGroupCheckedAction set_radio_group_checked_action = 13;
             SetRemoteCollectionItemListAdapterAction set_remote_collection_item_list_adapter_action = 14;
             SetRippleDrawableColorAction set_ripple_drawable_color_action = 15;
+            SetViewOutlinePreferredRadiusAction set_view_outline_preferred_radius_action = 16;
+            TextViewDrawableAction text_view_drawable_action = 17;
+            TextViewSizeAction text_view_size_action = 18;
+            ViewGroupAddAction view_group_add_action = 19;
+            ViewGroupRemoveAction view_group_remove_action = 20;
+            ViewPaddingAction view_padding_action = 21;
+            SetDrawInstructionAction set_draw_instruction_action = 22;
         }
     }
 
@@ -428,6 +438,65 @@
         optional string view_id = 1;
         optional android.content.res.ColorStateListProto color_state_list = 2;
     }
+
+    message SetViewOutlinePreferredRadiusAction {
+        optional string view_id = 1;
+        optional int32 value_type = 2;
+        optional int32 value = 3;
+    }
+
+    message TextViewDrawableAction {
+        optional string view_id = 1;
+        optional bool is_relative = 2;
+        oneof drawables {
+            Resources resources = 3;
+            Icons icons = 4;
+        };
+
+        message Resources {
+            optional string one = 1;
+            optional string two = 2;
+            optional string three = 3;
+            optional string four = 4;
+        }
+
+        message Icons {
+            optional Icon one = 1;
+            optional Icon two = 2;
+            optional Icon three = 3;
+            optional Icon four = 4;
+        }
+    }
+
+    message TextViewSizeAction {
+        optional string view_id = 1;
+        optional int32 units = 2;
+        optional float size = 3;
+    }
+
+    message ViewGroupAddAction {
+        optional string view_id = 1;
+        optional RemoteViewsProto nested_views = 2;
+        optional int32 index = 3;
+        optional int32 stableId = 4;
+    }
+
+    message ViewGroupRemoveAction {
+        optional string view_id = 1;
+        optional string view_id_to_keep = 2;
+    }
+
+    message ViewPaddingAction {
+        optional string view_id = 1;
+        optional int32 left = 2;
+        optional int32 right = 3;
+        optional int32 top = 4;
+        optional int32 bottom = 5;
+    }
+
+    message SetDrawInstructionAction {
+        repeated bytes instructions = 1;
+    }
 }
 
 
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index f067b51..5693d66 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -155,6 +155,7 @@
 
     <protected-broadcast android:name="android.bluetooth.intent.DISCOVERABLE_TIMEOUT" />
     <protected-broadcast android:name="android.bluetooth.action.AUTO_ON_STATE_CHANGED" />
+    <protected-broadcast android:name="android.bluetooth.action.CONNECTION_STATE_CHANGED" />
     <protected-broadcast android:name="android.bluetooth.adapter.action.STATE_CHANGED" />
     <protected-broadcast android:name="android.bluetooth.adapter.action.SCAN_MODE_CHANGED" />
     <protected-broadcast android:name="android.bluetooth.adapter.action.DISCOVERY_STARTED" />
@@ -240,6 +241,8 @@
     <protected-broadcast
         android:name="android.bluetooth.avrcp-controller.profile.action.FOLDER_LIST" />
     <protected-broadcast
+        android:name="android.bluetooth.avrcp-controller.profile.action.PLAYER_SETTING" />
+    <protected-broadcast
         android:name="android.bluetooth.avrcp-controller.profile.action.TRACK_EVENT" />
     <protected-broadcast
         android:name="android.bluetooth.input.profile.action.CONNECTION_STATE_CHANGED" />
@@ -266,6 +269,7 @@
     <protected-broadcast
         android:name="android.bluetooth.pan.profile.action.CONNECTION_STATE_CHANGED" />
     <protected-broadcast android:name="android.bluetooth.action.HAP_CONNECTION_STATE_CHANGED" />
+    <protected-broadcast android:name="android.bluetooth.action.HAP_DEVICE_AVAILABLE" />
     <protected-broadcast android:name="android.bluetooth.action.LE_AUDIO_CONNECTION_STATE_CHANGED" />
     <protected-broadcast android:name="android.bluetooth.action.LE_AUDIO_ACTIVE_DEVICE_CHANGED" />
     <protected-broadcast android:name="android.bluetooth.action.LE_AUDIO_CONF_CHANGED" />
@@ -845,6 +849,8 @@
     <protected-broadcast android:name="android.intent.action.MAIN_USER_LOCKSCREEN_KNOWLEDGE_FACTOR_CHANGED" />
     <protected-broadcast android:name="com.android.uwb.uwbcountrycode.GEOCODE_RETRY" />
     <protected-broadcast android:name="android.telephony.action.ACTION_SATELLITE_SUBSCRIBER_ID_LIST_CHANGED" />
+    <protected-broadcast android:name="android.service.ondeviceintelligence.MODEL_LOADED" />
+    <protected-broadcast android:name="android.service.ondeviceintelligence.MODEL_UNLOADED" />
 
     <!-- ====================================================================== -->
     <!--                          RUNTIME PERMISSIONS                           -->
diff --git a/core/res/OWNERS b/core/res/OWNERS
index 5293131..d109cee 100644
--- a/core/res/OWNERS
+++ b/core/res/OWNERS
@@ -60,6 +60,7 @@
 
 # Wear
 per-file res/*-watch/* = file:/WEAR_OWNERS
+per-file res/*-watch-v*/* = file:/WEAR_OWNERS
 
 # Performance
 per-file res/values/config.xml = file:/PERFORMANCE_OWNERS
diff --git a/core/res/res/color-watch-v36/btn_material_filled_background_color.xml b/core/res/res/color-watch-v36/btn_material_filled_background_color.xml
new file mode 100644
index 0000000..8b2afa8
--- /dev/null
+++ b/core/res/res/color-watch-v36/btn_material_filled_background_color.xml
@@ -0,0 +1,23 @@
+<!--
+  ~ Copyright (C) 2024 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT 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:state_enabled="false"
+          android:alpha="?attr/disabledAlpha"
+          android:color="?attr/materialColorOnSurface" />
+    <item android:state_enabled="true"
+          android:color="?attr/materialColorPrimary" />
+</selector>
\ No newline at end of file
diff --git a/core/res/res/color-watch-v36/btn_material_filled_text_color.xml b/core/res/res/color-watch-v36/btn_material_filled_text_color.xml
new file mode 100644
index 0000000..cefc912
--- /dev/null
+++ b/core/res/res/color-watch-v36/btn_material_filled_text_color.xml
@@ -0,0 +1,23 @@
+<!--
+  ~ Copyright (C) 2024 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT 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:state_enabled="false"
+          android:alpha="?attr/primaryContentAlpha"
+          android:color="?attr/materialColorOnSurface" />
+    <item android:state_enabled="true"
+          android:color="?attr/materialColorOnPrimary" />
+</selector>
\ No newline at end of file
diff --git a/core/res/res/color-watch-v36/btn_material_filled_tonal_background_color.xml b/core/res/res/color-watch-v36/btn_material_filled_tonal_background_color.xml
new file mode 100644
index 0000000..eaf9e7d
--- /dev/null
+++ b/core/res/res/color-watch-v36/btn_material_filled_tonal_background_color.xml
@@ -0,0 +1,23 @@
+<!--
+  ~ Copyright (C) 2024 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT 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:state_enabled="false"
+          android:alpha="?attr/disabledAlpha"
+          android:color="?attr/materialColorOnSurface" />
+    <item android:state_enabled="true"
+          android:color="?attr/materialColorSurfaceContainer" />
+</selector>
\ No newline at end of file
diff --git a/core/res/res/color-watch-v36/btn_material_filled_tonal_text_color.xml b/core/res/res/color-watch-v36/btn_material_filled_tonal_text_color.xml
new file mode 100644
index 0000000..94e50fb
--- /dev/null
+++ b/core/res/res/color-watch-v36/btn_material_filled_tonal_text_color.xml
@@ -0,0 +1,23 @@
+<!--
+  ~ Copyright (C) 2024 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT 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:state_enabled="false"
+          android:alpha="?attr/primaryContentAlpha"
+          android:color="?attr/materialColorOnSurface" />
+    <item android:state_enabled="true"
+          android:color="?attr/materialColorOnSurface" />
+</selector>
\ No newline at end of file
diff --git a/core/res/res/drawable-watch-v36/btn_background_material_filled.xml b/core/res/res/drawable-watch-v36/btn_background_material_filled.xml
new file mode 100644
index 0000000..0029de1
--- /dev/null
+++ b/core/res/res/drawable-watch-v36/btn_background_material_filled.xml
@@ -0,0 +1,28 @@
+<!--
+  ~ Copyright (C) 2024 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<ripple xmlns:android="http://schemas.android.com/apk/res/android"
+        android:color="?attr/colorControlHighlight">
+    <item>
+        <shape android:shape="rectangle">
+            <solid android:color="@color/btn_material_filled_background_color"/>
+            <corners android:radius="?android:attr/buttonCornerRadius"/>
+            <size
+                android:width="@dimen/btn_material_width"
+                android:height="@dimen/btn_material_height" />
+        </shape>
+    </item>
+</ripple>
\ No newline at end of file
diff --git a/core/res/res/drawable-watch-v36/btn_background_material_filled_tonal.xml b/core/res/res/drawable-watch-v36/btn_background_material_filled_tonal.xml
new file mode 100644
index 0000000..105f077
--- /dev/null
+++ b/core/res/res/drawable-watch-v36/btn_background_material_filled_tonal.xml
@@ -0,0 +1,28 @@
+<!--
+  ~ Copyright (C) 2024 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<ripple xmlns:android="http://schemas.android.com/apk/res/android"
+        android:color="?attr/colorControlHighlight">
+    <item>
+        <shape android:shape="rectangle">
+            <solid android:color="@color/btn_material_filled_tonal_background_color"/>
+            <corners android:radius="?android:attr/buttonCornerRadius"/>
+            <size
+                android:width="@dimen/btn_material_width"
+                android:height="@dimen/btn_material_height" />
+        </shape>
+    </item>
+</ripple>
\ No newline at end of file
diff --git a/core/res/res/drawable/notification_progress_icon_background.xml b/core/res/res/drawable/notification_progress_icon_background.xml
new file mode 100644
index 0000000..8e843be
--- /dev/null
+++ b/core/res/res/drawable/notification_progress_icon_background.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
+    <solid android:color="#00000000" />
+    <corners android:radius="4dp" />
+</shape>
\ No newline at end of file
diff --git a/core/res/res/layout/input_method_switch_dialog_new.xml b/core/res/res/layout/input_method_switch_dialog_new.xml
index 058fe3f..118f93b 100644
--- a/core/res/res/layout/input_method_switch_dialog_new.xml
+++ b/core/res/res/layout/input_method_switch_dialog_new.xml
@@ -39,7 +39,7 @@
                 android:id="@+id/list"
                 android:layout_width="match_parent"
                 android:layout_height="match_parent"
-                android:paddingVertical="8dp"
+                android:paddingTop="8dp"
                 android:clipToPadding="false"
                 android:layoutManager="com.android.internal.widget.LinearLayoutManager"/>
 
@@ -74,8 +74,7 @@
             android:text="@string/input_method_switcher_settings_button"
             android:fontFamily="google-sans-text"
             android:textAppearance="?attr/textAppearance"
-            android:contentDescription="@string/input_method_language_settings"
-            android:visibility="gone"/>
+            android:contentDescription="@string/input_method_language_settings"/>
 
     </LinearLayout>
 
diff --git a/core/res/res/layout/input_method_switch_item_divider.xml b/core/res/res/layout/input_method_switch_item_divider.xml
new file mode 100644
index 0000000..4f8c963
--- /dev/null
+++ b/core/res/res/layout/input_method_switch_item_divider.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright (C) 2024 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:orientation="vertical"
+    android:layout_marginHorizontal="16dp"
+    android:layout_marginTop="8dp"
+    android:layout_marginBottom="16dp">
+
+    <View
+        android:layout_width="match_parent"
+        android:layout_height="1dp"
+        android:background="?attr/materialColorOutlineVariant"
+        android:layout_marginStart="20dp"
+        android:layout_marginEnd="24dp"
+        android:importantForAccessibility="no"/>
+
+</LinearLayout>
diff --git a/core/res/res/layout/input_method_switch_item_header.xml b/core/res/res/layout/input_method_switch_item_header.xml
new file mode 100644
index 0000000..f0080a6
--- /dev/null
+++ b/core/res/res/layout/input_method_switch_item_header.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright (C) 2024 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:orientation="vertical"
+    android:layout_marginHorizontal="16dp"
+    android:layout_marginTop="4dp"
+    android:layout_marginBottom="16dp">
+
+    <TextView
+        android:id="@+id/header_text"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginHorizontal="8dp"
+        android:ellipsize="end"
+        android:singleLine="true"
+        android:fontFamily="google-sans-text"
+        android:textAppearance="?attr/textAppearance"
+        android:accessibilityHeading="true"
+        android:textColor="?attr/materialColorPrimary"/>
+
+</LinearLayout>
diff --git a/core/res/res/layout/input_method_switch_item_new.xml b/core/res/res/layout/input_method_switch_item_new.xml
index 10d938c..f8710cc 100644
--- a/core/res/res/layout/input_method_switch_item_new.xml
+++ b/core/res/res/layout/input_method_switch_item_new.xml
@@ -16,76 +16,45 @@
 -->
 
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/list_item"
     android:layout_width="match_parent"
-    android:layout_height="wrap_content"
-    android:orientation="vertical"
-    android:paddingHorizontal="16dp"
-    android:paddingBottom="8dp">
-
-    <View
-        android:id="@+id/divider"
-        android:layout_width="match_parent"
-        android:layout_height="1dp"
-        android:background="?attr/materialColorSurfaceVariant"
-        android:layout_marginStart="20dp"
-        android:layout_marginTop="8dp"
-        android:layout_marginEnd="24dp"
-        android:layout_marginBottom="12dp"
-        android:visibility="gone"
-        android:importantForAccessibility="no"/>
-
-    <TextView
-        android:id="@+id/header_text"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:padding="8dp"
-        android:ellipsize="end"
-        android:singleLine="true"
-        android:fontFamily="google-sans-text"
-        android:textAppearance="?attr/textAppearance"
-        android:textColor="?attr/materialColorPrimary"
-        android:visibility="gone"/>
+    android:layout_height="72dp"
+    android:background="@drawable/input_method_switch_item_background"
+    android:gravity="center_vertical"
+    android:orientation="horizontal"
+    android:layout_marginHorizontal="16dp"
+    android:layout_marginBottom="8dp"
+    android:paddingStart="20dp"
+    android:paddingEnd="24dp">
 
     <LinearLayout
-        android:id="@+id/list_item"
-        android:layout_width="match_parent"
-        android:layout_height="72dp"
-        android:background="@drawable/input_method_switch_item_background"
-        android:gravity="center_vertical"
-        android:orientation="horizontal"
-        android:paddingStart="20dp"
-        android:paddingEnd="24dp">
+        android:layout_width="0dp"
+        android:layout_height="match_parent"
+        android:layout_weight="1"
+        android:gravity="start|center_vertical"
+        android:orientation="vertical">
 
-        <LinearLayout
-            android:layout_width="0dp"
-            android:layout_height="match_parent"
-            android:layout_weight="1"
-            android:gravity="start|center_vertical"
-            android:orientation="vertical">
-
-            <TextView
-                android:id="@+id/text"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:ellipsize="marquee"
-                android:singleLine="true"
-                android:fontFamily="google-sans-text"
-                android:textColor="@color/input_method_switch_on_item"
-                android:textAppearance="?attr/textAppearanceListItem"/>
-
-        </LinearLayout>
-
-        <ImageView
-            android:id="@+id/image"
-            android:layout_width="24dp"
-            android:layout_height="24dp"
-            android:gravity="center_vertical"
-            android:layout_marginStart="12dp"
-            android:src="@drawable/ic_check_24dp"
-            android:tint="@color/input_method_switch_on_item"
-            android:visibility="gone"
-            android:importantForAccessibility="no"/>
+        <TextView
+            android:id="@+id/text"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:ellipsize="marquee"
+            android:singleLine="true"
+            android:fontFamily="google-sans-text"
+            android:textColor="@color/input_method_switch_on_item"
+            android:textAppearance="?attr/textAppearanceListItem"/>
 
     </LinearLayout>
 
+    <ImageView
+        android:id="@+id/image"
+        android:layout_width="24dp"
+        android:layout_height="24dp"
+        android:gravity="center_vertical"
+        android:layout_marginStart="12dp"
+        android:src="@drawable/ic_check_24dp"
+        android:tint="@color/input_method_switch_on_item"
+        android:visibility="gone"
+        android:importantForAccessibility="no"/>
+
 </LinearLayout>
diff --git a/core/res/res/layout/notification_template_material_progress.xml b/core/res/res/layout/notification_template_material_progress.xml
new file mode 100644
index 0000000..fdcefcc
--- /dev/null
+++ b/core/res/res/layout/notification_template_material_progress.xml
@@ -0,0 +1,122 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+  ~ Copyright (C) 2024 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+<FrameLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/status_bar_latest_event_content"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:orientation="vertical"
+    android:clipChildren="false"
+    android:tag="progress"
+    >
+
+    <LinearLayout
+        android:id="@+id/notification_action_list_margin_target"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginBottom="@dimen/notification_content_margin"
+        android:orientation="vertical"
+        >
+
+        <FrameLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_weight="1"
+            android:layout_gravity="top"
+            >
+
+            <include layout="@layout/notification_template_header" />
+
+            <LinearLayout
+                android:id="@+id/notification_main_column"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_marginStart="@dimen/notification_content_margin_start"
+                android:layout_marginEnd="@dimen/notification_content_margin_end"
+                android:layout_marginTop="@dimen/notification_content_margin_top"
+                android:orientation="vertical"
+                >
+
+                <include layout="@layout/notification_template_part_line1" />
+
+                <include layout="@layout/notification_template_text_multiline" />
+
+                <LinearLayout
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:gravity="center_vertical"
+                    android:layout_marginTop="@dimen/notification_progress_margin_top"
+                    android:orientation="horizontal">
+
+                    <com.android.internal.widget.CachingIconView
+                        android:id="@+id/notification_progress_start_icon"
+                        android:layout_width="@dimen/notification_progress_icon_size"
+                        android:layout_height="@dimen/notification_progress_icon_size"
+                        android:background="@drawable/notification_progress_icon_background"
+                        android:clipToOutline="true"
+                        android:importantForAccessibility="no"
+                        android:layout_marginEnd="@dimen/notification_progress_margin_horizontal"
+                        android:scaleType="centerCrop"
+                        android:maxDrawableWidth="@dimen/notification_progress_icon_size"
+                        android:maxDrawableHeight="@dimen/notification_progress_icon_size"
+                        />
+
+
+                    <com.android.internal.widget.NotificationProgressBar
+                        android:id="@+id/progress"
+                        android:layout_width="0dp"
+                        android:layout_height="@dimen/notification_progress_bar_height"
+                        style="@style/Widget.Material.Light.ProgressBar.Horizontal"
+                        android:layout_weight="1"
+                        />
+
+                    <com.android.internal.widget.CachingIconView
+                        android:id="@+id/notification_progress_end_icon"
+                        android:layout_width="@dimen/notification_progress_icon_size"
+                        android:layout_height="@dimen/notification_progress_icon_size"
+                        android:background="@drawable/notification_progress_icon_background"
+                        android:clipToOutline="true"
+                        android:importantForAccessibility="no"
+                        android:scaleType="centerCrop"
+                        android:layout_marginStart="@dimen/notification_progress_margin_horizontal"
+                        android:maxDrawableWidth="@dimen/notification_progress_icon_size"
+                        android:maxDrawableHeight="@dimen/notification_progress_icon_size"
+                        />
+                </LinearLayout>
+            </LinearLayout>
+
+            <include layout="@layout/notification_template_right_icon" />
+        </FrameLayout>
+
+        <ViewStub
+            android:layout="@layout/notification_material_reply_text"
+            android:id="@+id/notification_material_reply_container"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            />
+
+        <include
+            layout="@layout/notification_template_smart_reply_container"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginStart="@dimen/notification_content_margin_start"
+            android:layout_marginEnd="@dimen/notification_content_margin_end"
+            android:layout_marginTop="@dimen/notification_content_margin"
+            />
+
+        <include layout="@layout/notification_material_action_list" />
+    </LinearLayout>
+</FrameLayout>
\ No newline at end of file
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index 1cd2150..cdae265 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -2129,11 +2129,6 @@
     <string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"Oproepe en kennisgewings sal vibreer"</string>
     <string name="volume_dialog_ringer_guidance_silent" msgid="1011246774949993783">"Oproepe en kennisgewings sal gedemp wees"</string>
     <string name="notification_channel_system_changes" msgid="2462010596920209678">"Stelselveranderinge"</string>
-    <string name="notification_channel_do_not_disturb" msgid="7832584281883687653">"Moenie Steur Nie"</string>
-    <string name="zen_upgrade_notification_visd_title" msgid="2001148984371968620">"Nuut: Moenie Steur Nie versteek tans kennisgewings"</string>
-    <string name="zen_upgrade_notification_visd_content" msgid="3683314609114134946">"Tik om meer te wete te kom en te verander."</string>
-    <string name="zen_upgrade_notification_title" msgid="8198167698095298717">"Moenie Steur Nie het verander"</string>
-    <string name="zen_upgrade_notification_content" msgid="5228458567180124005">"Tik om te kyk wat geblokkeer word."</string>
     <string name="review_notification_settings_title" msgid="5102557424459810820">"Gaan kennisgewinginstellings na"</string>
     <string name="review_notification_settings_text" msgid="5916244866751849279">"Vanaf Android 13 het programme wat jy installeer jou toestemming nodig om kennisgewings te stuur. Tik om hierdie toestemming vir bestaande programme te verander."</string>
     <string name="review_notification_settings_remind_me_action" msgid="1081081018678480907">"Herinner my later"</string>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index 484afc3..cc8ab3e 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -2129,11 +2129,6 @@
     <string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"ጥሪዎች እና ማሳወቂያዎች ይነዝራሉ"</string>
     <string name="volume_dialog_ringer_guidance_silent" msgid="1011246774949993783">"ጥሪዎች እና ማሳወቂያዎች ድምፀ-ከል ይሆናሉ"</string>
     <string name="notification_channel_system_changes" msgid="2462010596920209678">"የሥርዓት ለውጦች"</string>
-    <string name="notification_channel_do_not_disturb" msgid="7832584281883687653">"አትረብሽ"</string>
-    <string name="zen_upgrade_notification_visd_title" msgid="2001148984371968620">"አዲስ፦ አትረብሽ ማሳወቂያዎችን እየደበቀ ነው"</string>
-    <string name="zen_upgrade_notification_visd_content" msgid="3683314609114134946">"የበለጠ ለመረዳት እና ለመለወጥ መታ ያድርጉ።"</string>
-    <string name="zen_upgrade_notification_title" msgid="8198167698095298717">"አትረብሽ ተቀይሯል"</string>
-    <string name="zen_upgrade_notification_content" msgid="5228458567180124005">"ምን እንደታገደ ለመፈተሽ መታ ያድርጉ።"</string>
     <string name="review_notification_settings_title" msgid="5102557424459810820">"የማሳወቂያ ቅንብሮችን ይገምግሙ"</string>
     <string name="review_notification_settings_text" msgid="5916244866751849279">"ከAndroid 13 ጀምረው የሚጭኗቸው መተግበሪያዎች ማሳወቂያዎችን ለመላክ የእርስዎ ፈቃድ ያስፈልጋቸዋል። ይህን ፈቃድ ለነባር መተግበሪያዎች ለመቀየር መታ ያድርጉ።"</string>
     <string name="review_notification_settings_remind_me_action" msgid="1081081018678480907">"በኋላ አስታውሰኝ"</string>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index 75e93d1..e81ec89 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -2133,11 +2133,6 @@
     <string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"سيهتز الهاتف عند تلقّي المكالمات والإشعارات."</string>
     <string name="volume_dialog_ringer_guidance_silent" msgid="1011246774949993783">"سيتم كتم صوت الهاتف عند تلقي المكالمات والإشعارات."</string>
     <string name="notification_channel_system_changes" msgid="2462010596920209678">"تغييرات النظام"</string>
-    <string name="notification_channel_do_not_disturb" msgid="7832584281883687653">"عدم الإزعاج"</string>
-    <string name="zen_upgrade_notification_visd_title" msgid="2001148984371968620">"جديد: يؤدي تفعيل ميزة \"عدم الإزعاج\" إلى إخفاء الإشعارات."</string>
-    <string name="zen_upgrade_notification_visd_content" msgid="3683314609114134946">"انقر لمعرفة مزيد من المعلومات وإجراء التغيير."</string>
-    <string name="zen_upgrade_notification_title" msgid="8198167698095298717">"تم تغيير ميزة \"عدم الإزعاج\""</string>
-    <string name="zen_upgrade_notification_content" msgid="5228458567180124005">"انقر للاطّلاع على ما تم حظره."</string>
     <string name="review_notification_settings_title" msgid="5102557424459810820">"مراجعة إعدادات الإشعارات"</string>
     <string name="review_notification_settings_text" msgid="5916244866751849279">"‏بدءً من نظام التشغيل Android 13، يجب أن تحصل التطبيقات التي تُثبِّتها على إذن لإرسال الإشعارات. انقر لتغيير هذا الإذن للتطبيقات الحالية."</string>
     <string name="review_notification_settings_remind_me_action" msgid="1081081018678480907">"تذكيري لاحقًا"</string>
diff --git a/core/res/res/values-as/strings.xml b/core/res/res/values-as/strings.xml
index e64c85e..f36a659 100644
--- a/core/res/res/values-as/strings.xml
+++ b/core/res/res/values-as/strings.xml
@@ -2129,11 +2129,6 @@
     <string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"কল আৰু জাননীসমূহে কম্পন কৰিব"</string>
     <string name="volume_dialog_ringer_guidance_silent" msgid="1011246774949993783">"কল আৰু জাননীসমূহ মিউট কৰা হ\'ব"</string>
     <string name="notification_channel_system_changes" msgid="2462010596920209678">"ছিষ্টেমৰ সালসলনি"</string>
-    <string name="notification_channel_do_not_disturb" msgid="7832584281883687653">"অসুবিধা নিদিব"</string>
-    <string name="zen_upgrade_notification_visd_title" msgid="2001148984371968620">"নতুন: অসুবিধা নিদিব ম\'ডে জাননীসমূহ লুকাই ৰাখিছে"</string>
-    <string name="zen_upgrade_notification_visd_content" msgid="3683314609114134946">"অধিক জানিবলৈ আৰু সলনি কৰিবলৈ টিপক।"</string>
-    <string name="zen_upgrade_notification_title" msgid="8198167698095298717">"অসুবিধা নিদিব সলনি হৈছে"</string>
-    <string name="zen_upgrade_notification_content" msgid="5228458567180124005">"কি কি অৱৰোধ কৰা হৈছে জানিবলৈ টিপক।"</string>
     <string name="review_notification_settings_title" msgid="5102557424459810820">"জাননীৰ ছেটিং পৰ্যালোচনা কৰক"</string>
     <string name="review_notification_settings_text" msgid="5916244866751849279">"Android 13ৰ পৰা, আপুনি ইনষ্টল কৰা এপক জাননী পঠিয়াবলৈ আপোনাৰ অনুমতিৰ প্ৰয়োজন। আগৰে পৰা থকা এপৰ বাবে এই অনুমতিটো সলনি কৰিবলৈ টিপক।"</string>
     <string name="review_notification_settings_remind_me_action" msgid="1081081018678480907">"পাছত মনত পেলাই দিব"</string>
diff --git a/core/res/res/values-az/strings.xml b/core/res/res/values-az/strings.xml
index 25dc429..2a77df2 100644
--- a/core/res/res/values-az/strings.xml
+++ b/core/res/res/values-az/strings.xml
@@ -2129,11 +2129,6 @@
     <string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"Zəng və bildirişlər vibrasiya verəcək"</string>
     <string name="volume_dialog_ringer_guidance_silent" msgid="1011246774949993783">"Zəng və bildirişlər səssiz ediləcək"</string>
     <string name="notification_channel_system_changes" msgid="2462010596920209678">"Sistem dəyişiklikləri"</string>
-    <string name="notification_channel_do_not_disturb" msgid="7832584281883687653">"Narahat Etməyin"</string>
-    <string name="zen_upgrade_notification_visd_title" msgid="2001148984371968620">"Yenilik: \"Narahat etməyin\" rejimi bildirişləri gizlədir"</string>
-    <string name="zen_upgrade_notification_visd_content" msgid="3683314609114134946">"Ətraflı məıumat əldə edərək dəyişmək üçün klikləyin."</string>
-    <string name="zen_upgrade_notification_title" msgid="8198167698095298717">"\"Narahat Etməyin\" rejimi dəyişdirildi"</string>
-    <string name="zen_upgrade_notification_content" msgid="5228458567180124005">"Nəyin blok edildiyini yoxlamaq üçün klikləyin."</string>
     <string name="review_notification_settings_title" msgid="5102557424459810820">"Bildiriş ayarlarını nəzərdən keçirin"</string>
     <string name="review_notification_settings_text" msgid="5916244866751849279">"Android 13-dən başlayaraq quraşdırdığınız tətbiqlər bildiriş göndərmək üçün icazənizi tələb edir. Mövcud tətbiqlər üçün bu icazəni dəyişmək üçün toxunun."</string>
     <string name="review_notification_settings_remind_me_action" msgid="1081081018678480907">"Sonra xatırladın"</string>
diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml
index 7413703..a51aad2 100644
--- a/core/res/res/values-b+sr+Latn/strings.xml
+++ b/core/res/res/values-b+sr+Latn/strings.xml
@@ -2130,11 +2130,6 @@
     <string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"Vibracija za pozive i obaveštenja je uključena"</string>
     <string name="volume_dialog_ringer_guidance_silent" msgid="1011246774949993783">"Melodija zvona za pozive i obaveštenje je isključena"</string>
     <string name="notification_channel_system_changes" msgid="2462010596920209678">"Sistemske promene"</string>
-    <string name="notification_channel_do_not_disturb" msgid="7832584281883687653">"Ne uznemiravaj"</string>
-    <string name="zen_upgrade_notification_visd_title" msgid="2001148984371968620">"Novo: Režim Ne uznemiravaj krije obaveštenja"</string>
-    <string name="zen_upgrade_notification_visd_content" msgid="3683314609114134946">"Dodirnite da biste saznali više i promenili podešavanje."</string>
-    <string name="zen_upgrade_notification_title" msgid="8198167698095298717">"Režim Ne uznemiravaj je promenjen"</string>
-    <string name="zen_upgrade_notification_content" msgid="5228458567180124005">"Dodirnite da biste proverili šta je blokirano."</string>
     <string name="review_notification_settings_title" msgid="5102557424459810820">"Pregledajte podešavanja obaveštenja"</string>
     <string name="review_notification_settings_text" msgid="5916244866751849279">"Od Android-a 13 aplikacije koje instalirate moraju da imaju dozvolu za slanje obaveštenja. Dodirnite da biste promenili ovu dozvolu za postojeće aplikacije."</string>
     <string name="review_notification_settings_remind_me_action" msgid="1081081018678480907">"Podseti me kasnije"</string>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index a5af4b9..26f11df 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -2131,11 +2131,6 @@
     <string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"Для выклікаў і апавяшчэнняў уключаны вібрасігнал"</string>
     <string name="volume_dialog_ringer_guidance_silent" msgid="1011246774949993783">"Для выклікаў і апавяшчэнняў гук выключаны"</string>
     <string name="notification_channel_system_changes" msgid="2462010596920209678">"Сістэмныя змены"</string>
-    <string name="notification_channel_do_not_disturb" msgid="7832584281883687653">"Не турбаваць"</string>
-    <string name="zen_upgrade_notification_visd_title" msgid="2001148984371968620">"Новае: у рэжыме \"Не турбаваць\" апавяшчэнні не паказваюцца"</string>
-    <string name="zen_upgrade_notification_visd_content" msgid="3683314609114134946">"Дакраніцеся, каб даведацца больш і змяніць."</string>
-    <string name="zen_upgrade_notification_title" msgid="8198167698095298717">"Зменены налады рэжыму \"Не турбаваць\""</string>
-    <string name="zen_upgrade_notification_content" msgid="5228458567180124005">"Націсніце, каб паглядзець заблакіраванае."</string>
     <string name="review_notification_settings_title" msgid="5102557424459810820">"Праверце налады апавяшчэнняў"</string>
     <string name="review_notification_settings_text" msgid="5916244866751849279">"Пачынаючы з версіі Android 13 усталяваным вамі праграмам неабходна даваць дазвол на адпраўку апавяшчэнняў. Націсніце, каб змяніць дазвол для існуючых праграм."</string>
     <string name="review_notification_settings_remind_me_action" msgid="1081081018678480907">"Нагадаць пазней"</string>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index 9b5a825..38c9d0b 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -2129,11 +2129,6 @@
     <string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"При обаждания и известия устройството ще вибрира"</string>
     <string name="volume_dialog_ringer_guidance_silent" msgid="1011246774949993783">"Обажданията и известията ще бъдат заглушени"</string>
     <string name="notification_channel_system_changes" msgid="2462010596920209678">"Промени в системата"</string>
-    <string name="notification_channel_do_not_disturb" msgid="7832584281883687653">"Не безпокойте"</string>
-    <string name="zen_upgrade_notification_visd_title" msgid="2001148984371968620">"Ново: Режимът „Не безпокойте“ скрива известията"</string>
-    <string name="zen_upgrade_notification_visd_content" msgid="3683314609114134946">"Докоснете, за да научите повече и да извършите промени."</string>
-    <string name="zen_upgrade_notification_title" msgid="8198167698095298717">"Настройките за „Не безпокойте“ са променени"</string>
-    <string name="zen_upgrade_notification_content" msgid="5228458567180124005">"Докоснете, за да проверите какво е блокирано."</string>
     <string name="review_notification_settings_title" msgid="5102557424459810820">"Преглед на настройките за известия"</string>
     <string name="review_notification_settings_text" msgid="5916244866751849279">"От Android 13 инсталираните от вас приложения трябва да получат разрешението ви, за да изпращат известия. Докоснете, за да промените това разрешение за съществуващите приложения."</string>
     <string name="review_notification_settings_remind_me_action" msgid="1081081018678480907">"Напомняне по-късно"</string>
diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml
index 0871bfd..8a833c8 100644
--- a/core/res/res/values-bn/strings.xml
+++ b/core/res/res/values-bn/strings.xml
@@ -2129,11 +2129,6 @@
     <string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"কল এবং বিজ্ঞপ্তি আসলে ভাইব্রেট হবে"</string>
     <string name="volume_dialog_ringer_guidance_silent" msgid="1011246774949993783">"কল এবং বিজ্ঞপ্তিগুলি মিউট করা হবে"</string>
     <string name="notification_channel_system_changes" msgid="2462010596920209678">"সিস্টেমে হয়ে থাকা পরিবর্তন"</string>
-    <string name="notification_channel_do_not_disturb" msgid="7832584281883687653">"বিরক্ত করবে না"</string>
-    <string name="zen_upgrade_notification_visd_title" msgid="2001148984371968620">"নতুন: \'বিরক্ত করবে না\' মোড চালু আছে, তাই বিজ্ঞপ্তি লুকিয়ে ফেলা হচ্ছে"</string>
-    <string name="zen_upgrade_notification_visd_content" msgid="3683314609114134946">"আরও জানতে এবং পরিবর্তন করতে ট্যাপ করুন।"</string>
-    <string name="zen_upgrade_notification_title" msgid="8198167698095298717">"\'বিরক্ত করবে না\' মোডের সেটিং বদলে গেছে"</string>
-    <string name="zen_upgrade_notification_content" msgid="5228458567180124005">"কী কী ব্লক করা আছে তা দেখতে ট্যাপ করুন।"</string>
     <string name="review_notification_settings_title" msgid="5102557424459810820">"বিজ্ঞপ্তির সেটিংস পর্যালোচনা করুন"</string>
     <string name="review_notification_settings_text" msgid="5916244866751849279">"Android 13 থেকে শুরু করে, বিজ্ঞপ্তি পাঠানোর জন্য আপনার ইনস্টল করা অ্যাপকে অনুমতি নিতে হবে। বর্তমান অ্যাপের জন্য এই অনুমতি পরিবর্তন করতে ট্যাপ করুন।"</string>
     <string name="review_notification_settings_remind_me_action" msgid="1081081018678480907">"পরে মনে করিয়ে দিও"</string>
diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml
index 9d5ecdc..9e29b7f 100644
--- a/core/res/res/values-bs/strings.xml
+++ b/core/res/res/values-bs/strings.xml
@@ -2130,11 +2130,6 @@
     <string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"Pozivi i obavještenja će vibrirati"</string>
     <string name="volume_dialog_ringer_guidance_silent" msgid="1011246774949993783">"Pozivi i obavještenja će se isključiti"</string>
     <string name="notification_channel_system_changes" msgid="2462010596920209678">"Sistemske promjene"</string>
-    <string name="notification_channel_do_not_disturb" msgid="7832584281883687653">"Ne ometaj"</string>
-    <string name="zen_upgrade_notification_visd_title" msgid="2001148984371968620">"Novo: Način rada Ne ometaj sakriva obavještenja"</string>
-    <string name="zen_upgrade_notification_visd_content" msgid="3683314609114134946">"Dodirnite da saznate više i izvršite promjene."</string>
-    <string name="zen_upgrade_notification_title" msgid="8198167698095298717">"Način rada Ne ometaj je promijenjen"</string>
-    <string name="zen_upgrade_notification_content" msgid="5228458567180124005">"Dodirnite da provjerite šta je blokirano."</string>
     <string name="review_notification_settings_title" msgid="5102557424459810820">"Pregledajte postavke obavještenja"</string>
     <string name="review_notification_settings_text" msgid="5916244866751849279">"Počevši od Androida 13, aplikacije koje instalirate trebaju odobrenje da šalju obavještenja. Dodirnite da promijenite ovo odobrenje za postojeće aplikacije."</string>
     <string name="review_notification_settings_remind_me_action" msgid="1081081018678480907">"Podsjeti me kasnije"</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 5728aed..0dd1bca 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -2130,11 +2130,6 @@
     <string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"Les trucades i les notificacions vibraran"</string>
     <string name="volume_dialog_ringer_guidance_silent" msgid="1011246774949993783">"Les trucades i les notificacions se silenciaran"</string>
     <string name="notification_channel_system_changes" msgid="2462010596920209678">"Canvis del sistema"</string>
-    <string name="notification_channel_do_not_disturb" msgid="7832584281883687653">"No molestis"</string>
-    <string name="zen_upgrade_notification_visd_title" msgid="2001148984371968620">"Novetat: el mode No molestis està amagant notificacions"</string>
-    <string name="zen_upgrade_notification_visd_content" msgid="3683314609114134946">"Toca per obtenir més informació i canviar la configuració."</string>
-    <string name="zen_upgrade_notification_title" msgid="8198167698095298717">"S\'ha canviat el mode No molestis"</string>
-    <string name="zen_upgrade_notification_content" msgid="5228458567180124005">"Toca per consultar què s\'ha bloquejat."</string>
     <string name="review_notification_settings_title" msgid="5102557424459810820">"Consulta la configuració de notificacions"</string>
     <string name="review_notification_settings_text" msgid="5916244866751849279">"A partir de la versió Android 13, les aplicacions que instal·les necessiten el teu permís per enviar notificacions. Toca per canviar aquest permís per a les aplicacions existents."</string>
     <string name="review_notification_settings_remind_me_action" msgid="1081081018678480907">"Recorda-m\'ho més tard"</string>
@@ -2394,12 +2389,12 @@
     <string name="connected_display_unavailable_notification_content" msgid="3845903313751217516">"Utilitza un altre cable i torna-ho a provar"</string>
     <string name="connected_display_thermally_unavailable_notification_content" msgid="9205758199439955949">"El dispositiu està massa calent i no pot duplicar a la pantalla fins que es refredi"</string>
     <string name="concurrent_display_notification_name" msgid="1526911253558311131">"Pantalla dual"</string>
-    <string name="concurrent_display_notification_active_title" msgid="4892473462327943673">"La pantalla dual està activada"</string>
+    <string name="concurrent_display_notification_active_title" msgid="4892473462327943673">"Pantalla dual està activada"</string>
     <string name="concurrent_display_notification_active_content" msgid="5889355473710601270">"<xliff:g id="APP_NAME">%1$s</xliff:g> està utilitzant les dues pantalles per mostrar contingut"</string>
     <string name="concurrent_display_notification_thermal_title" msgid="5921609404644739229">"El dispositiu està massa calent"</string>
-    <string name="concurrent_display_notification_thermal_content" msgid="2075484836527609319">"La pantalla dual no està disponible perquè el telèfon està massa calent"</string>
-    <string name="concurrent_display_notification_power_save_title" msgid="1794569070730736281">"Dual Screen no està disponible"</string>
-    <string name="concurrent_display_notification_power_save_content" msgid="2198116070583851493">"Dual Screen no està disponible perquè la funció Estalvi de bateria està activada. Pots desactivar aquesta opció a Configuració."</string>
+    <string name="concurrent_display_notification_thermal_content" msgid="2075484836527609319">"Pantalla dual no està disponible perquè el telèfon està massa calent"</string>
+    <string name="concurrent_display_notification_power_save_title" msgid="1794569070730736281">"Pantalla dual no està disponible"</string>
+    <string name="concurrent_display_notification_power_save_content" msgid="2198116070583851493">"Pantalla dual no està disponible perquè la funció Estalvi de bateria està activada. Pots desactivar aquesta opció a Configuració."</string>
     <string name="device_state_notification_settings_button" msgid="691937505741872749">"Ves a Configuració"</string>
     <string name="device_state_notification_turn_off_button" msgid="6327161707661689232">"Desactiva"</string>
     <string name="keyboard_layout_notification_selected_title" msgid="1202560174252421219">"<xliff:g id="DEVICE_NAME">%s</xliff:g> configurat"</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index 2fea7fb..35f269a 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -2131,11 +2131,6 @@
     <string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"Volání a oznámení budou vibrovat"</string>
     <string name="volume_dialog_ringer_guidance_silent" msgid="1011246774949993783">"Volání a oznámení budou ztlumena"</string>
     <string name="notification_channel_system_changes" msgid="2462010596920209678">"Změny nastavení systému"</string>
-    <string name="notification_channel_do_not_disturb" msgid="7832584281883687653">"Nerušit"</string>
-    <string name="zen_upgrade_notification_visd_title" msgid="2001148984371968620">"Novinka: Režim Nerušit skrývá oznámení"</string>
-    <string name="zen_upgrade_notification_visd_content" msgid="3683314609114134946">"Klepnutím zobrazíte další informace a provedete změny."</string>
-    <string name="zen_upgrade_notification_title" msgid="8198167698095298717">"Nastavení režimu Nerušit se změnilo"</string>
-    <string name="zen_upgrade_notification_content" msgid="5228458567180124005">"Klepnutím zkontrolujete, co je blokováno."</string>
     <string name="review_notification_settings_title" msgid="5102557424459810820">"Zkontrolujte nastavení oznámení"</string>
     <string name="review_notification_settings_text" msgid="5916244866751849279">"Počínaje systémem Android 13 od vás nainstalované aplikace potřebují oprávnění k odesílání oznámení. Klepnutím toto oprávnění změníte pro stávající aplikace."</string>
     <string name="review_notification_settings_remind_me_action" msgid="1081081018678480907">"Připomenout později"</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index a9626a6..833b0c5 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -2129,11 +2129,6 @@
     <string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"Telefonen vibrerer ved opkald og notifikationer"</string>
     <string name="volume_dialog_ringer_guidance_silent" msgid="1011246774949993783">"Der afspilles ikke lyd ved opkald og notifikationer"</string>
     <string name="notification_channel_system_changes" msgid="2462010596920209678">"Systemændringer"</string>
-    <string name="notification_channel_do_not_disturb" msgid="7832584281883687653">"Forstyr ikke"</string>
-    <string name="zen_upgrade_notification_visd_title" msgid="2001148984371968620">"Nyhed! Forstyr ikke skjuler notifikationer"</string>
-    <string name="zen_upgrade_notification_visd_content" msgid="3683314609114134946">"Tryk for at få flere oplysninger og foretage ændringer."</string>
-    <string name="zen_upgrade_notification_title" msgid="8198167698095298717">"Tilstanden Forstyr ikke blev ændret"</string>
-    <string name="zen_upgrade_notification_content" msgid="5228458567180124005">"Tryk for at se, hvad der er blokeret."</string>
     <string name="review_notification_settings_title" msgid="5102557424459810820">"Gennemgå indstillinger for notifikationer"</string>
     <string name="review_notification_settings_text" msgid="5916244866751849279">"Fra og med Android 13 skal de apps, som du installerer, have din tilladelse til at sende notifikationer. Tryk for at ændre denne indstilling for eksisterende apps."</string>
     <string name="review_notification_settings_remind_me_action" msgid="1081081018678480907">"Påmind mig senere"</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index da0e9bd..1318f64 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -2129,11 +2129,6 @@
     <string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"Gerät vibriert bei Anrufen und Benachrichtigungen"</string>
     <string name="volume_dialog_ringer_guidance_silent" msgid="1011246774949993783">"Anrufe und Benachrichtigungen stummgeschaltet"</string>
     <string name="notification_channel_system_changes" msgid="2462010596920209678">"Systemänderungen"</string>
-    <string name="notification_channel_do_not_disturb" msgid="7832584281883687653">"Bitte nicht stören"</string>
-    <string name="zen_upgrade_notification_visd_title" msgid="2001148984371968620">"Neu: Durch „Bitte nicht stören“ werden Benachrichtigungen nicht mehr angezeigt"</string>
-    <string name="zen_upgrade_notification_visd_content" msgid="3683314609114134946">"Für weitere Informationen und zum Ändern tippen."</string>
-    <string name="zen_upgrade_notification_title" msgid="8198167698095298717">"„Bitte nicht stören“ wurde geändert"</string>
-    <string name="zen_upgrade_notification_content" msgid="5228458567180124005">"Tippe, um zu überprüfen, welche Inhalte blockiert werden."</string>
     <string name="review_notification_settings_title" msgid="5102557424459810820">"Benachrichtigungseinstellungen überprüfen"</string>
     <string name="review_notification_settings_text" msgid="5916244866751849279">"Ab Android 13 benötigen Apps, die du installierst, die Berechtigung zum Senden von Benachrichtigungen. Wenn du diese Berechtigung für bereits installierte Apps ändern möchtest, tippe hier."</string>
     <string name="review_notification_settings_remind_me_action" msgid="1081081018678480907">"Später erinnern"</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index 0556a08..bccea8f 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -507,7 +507,7 @@
     <string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"Επιτρέπει στην εφαρμογή την τροποποίηση καθολικών ρυθμίσεων ήχου, όπως η ένταση και ποιο ηχείο χρησιμοποιείται για έξοδο."</string>
     <string name="permlab_recordAudio" msgid="1208457423054219147">"εγγράφει ήχο"</string>
     <string name="permdesc_recordAudio" msgid="5857246765327514062">"Αυτή η εφαρμογή μπορεί να εγγράφει ήχο μέσω του μικροφώνου, όταν τη χρησιμοποιείτε."</string>
-    <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"εγγραφή ήχου στο παρασκήνιο"</string>
+    <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"ηχογράφηση στο παρασκήνιο"</string>
     <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"Αυτή η εφαρμογή μπορεί να εγγράφει ήχο μέσω του μικροφώνου, ανά πάσα στιγμή."</string>
     <string name="permlab_detectScreenCapture" msgid="4447042362828799433">"ανίχνευση καταγραφών οθόνης που περιέχουν τα παράθυρα της εφαρμογής"</string>
     <string name="permdesc_detectScreenCapture" msgid="3485784917960342284">"Η εφαρμογή θα λάβει ειδοποίηση όταν ληφθεί ένα στιγμιότυπο οθόνης ενώ βρίσκεται σε χρήση."</string>
@@ -541,7 +541,7 @@
     <string name="permlab_callCompanionApp" msgid="3654373653014126884">"προβολή και έλεγχος κλήσεων μέσω του συστήματος."</string>
     <string name="permdesc_callCompanionApp" msgid="8474168926184156261">"Επιτρέπει στην εφαρμογή να βλέπει και να ελέγχει τις εισερχόμενες κλήσεις στη συσκευή. Αυτό περιλαμβάνει πληροφορίες όπως τους αριθμούς κλήσεων για τις κλήσεις και την κατάσταση των κλήσεων."</string>
     <string name="permlab_exemptFromAudioRecordRestrictions" msgid="1164725468350759486">"εξαίρεση από περιορισμούς εγγραφής ήχου"</string>
-    <string name="permdesc_exemptFromAudioRecordRestrictions" msgid="2425117015896871976">"Εξαιρέστε την εφαρμογή από περιορισμούς για την εγγραφή ήχου."</string>
+    <string name="permdesc_exemptFromAudioRecordRestrictions" msgid="2425117015896871976">"Εξαιρέστε την εφαρμογή από περιορισμούς για την ηχογράφηση."</string>
     <string name="permlab_acceptHandover" msgid="2925523073573116523">"συνέχιση κλήσης από άλλη συσκευή"</string>
     <string name="permdesc_acceptHandovers" msgid="7129026180128626870">"Επιτρέπει στην εφαρμογή να συνεχίσει μια κλήση η οποία ξεκίνησε σε άλλη εφαρμογή."</string>
     <string name="permlab_readPhoneNumbers" msgid="5668704794723365628">"ανάγνωση αριθμών τηλεφώνου"</string>
@@ -2129,11 +2129,6 @@
     <string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"Θα υπάρχει δόνηση για κλήσεις και ειδοποιήσεις"</string>
     <string name="volume_dialog_ringer_guidance_silent" msgid="1011246774949993783">"Οι κλήσεις και οι ειδοποιήσεις θα τεθούν σε παύση"</string>
     <string name="notification_channel_system_changes" msgid="2462010596920209678">"Αλλαγές στο σύστημα"</string>
-    <string name="notification_channel_do_not_disturb" msgid="7832584281883687653">"Μην ενοχλείτε"</string>
-    <string name="zen_upgrade_notification_visd_title" msgid="2001148984371968620">"Νέο: Η λειτουργία \"Μην ενοχλείτε\" αποκρύπτει ειδοποιήσεις"</string>
-    <string name="zen_upgrade_notification_visd_content" msgid="3683314609114134946">"Πατήστε για να μάθετε περισσότερα και να κάνετε αλλαγές."</string>
-    <string name="zen_upgrade_notification_title" msgid="8198167698095298717">"Η λειτουργία \"Μην ενοχλείτε\" άλλαξε"</string>
-    <string name="zen_upgrade_notification_content" msgid="5228458567180124005">"Πατήστε για να ελέγξετε το περιεχόμενο που έχει αποκλειστεί."</string>
     <string name="review_notification_settings_title" msgid="5102557424459810820">"Έλεγχος ρυθμίσεων ειδοποιήσεων"</string>
     <string name="review_notification_settings_text" msgid="5916244866751849279">"Από το Android 13 και έπειτα, οι εφαρμογές που εγκαθιστάτε θα χρειάζονται την άδειά σας για την αποστολή ειδοποιήσεων. Πατήστε για να αλλάξετε αυτή την άδεια για υπάρχουσες εφαρμογές."</string>
     <string name="review_notification_settings_remind_me_action" msgid="1081081018678480907">"Υπενθύμιση αργότερα"</string>
diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml
index 086835c..e9239e2 100644
--- a/core/res/res/values-en-rAU/strings.xml
+++ b/core/res/res/values-en-rAU/strings.xml
@@ -2129,11 +2129,6 @@
     <string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"Calls and notifications will vibrate"</string>
     <string name="volume_dialog_ringer_guidance_silent" msgid="1011246774949993783">"Calls and notifications will be muted"</string>
     <string name="notification_channel_system_changes" msgid="2462010596920209678">"System changes"</string>
-    <string name="notification_channel_do_not_disturb" msgid="7832584281883687653">"Do not disturb"</string>
-    <string name="zen_upgrade_notification_visd_title" msgid="2001148984371968620">"New: Do Not Disturb is hiding notifications"</string>
-    <string name="zen_upgrade_notification_visd_content" msgid="3683314609114134946">"Tap to find out more and change."</string>
-    <string name="zen_upgrade_notification_title" msgid="8198167698095298717">"Do Not Disturb has changed"</string>
-    <string name="zen_upgrade_notification_content" msgid="5228458567180124005">"Tap to check what\'s blocked."</string>
     <string name="review_notification_settings_title" msgid="5102557424459810820">"Review notification settings"</string>
     <string name="review_notification_settings_text" msgid="5916244866751849279">"Starting in Android 13, apps that you install need your permission to send notifications. Tap to change this permission for existing apps."</string>
     <string name="review_notification_settings_remind_me_action" msgid="1081081018678480907">"Remind me later"</string>
diff --git a/core/res/res/values-en-rCA/strings.xml b/core/res/res/values-en-rCA/strings.xml
index 88a83b5..c624e2a 100644
--- a/core/res/res/values-en-rCA/strings.xml
+++ b/core/res/res/values-en-rCA/strings.xml
@@ -2129,11 +2129,6 @@
     <string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"Calls and notifications will vibrate"</string>
     <string name="volume_dialog_ringer_guidance_silent" msgid="1011246774949993783">"Calls and notifications will be muted"</string>
     <string name="notification_channel_system_changes" msgid="2462010596920209678">"System changes"</string>
-    <string name="notification_channel_do_not_disturb" msgid="7832584281883687653">"Do Not Disturb"</string>
-    <string name="zen_upgrade_notification_visd_title" msgid="2001148984371968620">"New: Do Not Disturb is hiding notifications"</string>
-    <string name="zen_upgrade_notification_visd_content" msgid="3683314609114134946">"Tap to learn more and change."</string>
-    <string name="zen_upgrade_notification_title" msgid="8198167698095298717">"Do Not Disturb has changed"</string>
-    <string name="zen_upgrade_notification_content" msgid="5228458567180124005">"Tap to check what\'s blocked."</string>
     <string name="review_notification_settings_title" msgid="5102557424459810820">"Review notification settings"</string>
     <string name="review_notification_settings_text" msgid="5916244866751849279">"Starting in Android 13, apps that you install need your permission to send notifications. Tap to change this permission for existing apps."</string>
     <string name="review_notification_settings_remind_me_action" msgid="1081081018678480907">"Remind me later"</string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index ef399b7..9ffaa5d 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -2129,11 +2129,6 @@
     <string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"Calls and notifications will vibrate"</string>
     <string name="volume_dialog_ringer_guidance_silent" msgid="1011246774949993783">"Calls and notifications will be muted"</string>
     <string name="notification_channel_system_changes" msgid="2462010596920209678">"System changes"</string>
-    <string name="notification_channel_do_not_disturb" msgid="7832584281883687653">"Do not disturb"</string>
-    <string name="zen_upgrade_notification_visd_title" msgid="2001148984371968620">"New: Do Not Disturb is hiding notifications"</string>
-    <string name="zen_upgrade_notification_visd_content" msgid="3683314609114134946">"Tap to find out more and change."</string>
-    <string name="zen_upgrade_notification_title" msgid="8198167698095298717">"Do Not Disturb has changed"</string>
-    <string name="zen_upgrade_notification_content" msgid="5228458567180124005">"Tap to check what\'s blocked."</string>
     <string name="review_notification_settings_title" msgid="5102557424459810820">"Review notification settings"</string>
     <string name="review_notification_settings_text" msgid="5916244866751849279">"Starting in Android 13, apps that you install need your permission to send notifications. Tap to change this permission for existing apps."</string>
     <string name="review_notification_settings_remind_me_action" msgid="1081081018678480907">"Remind me later"</string>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index 94ddc43..23441bb 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -2129,11 +2129,6 @@
     <string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"Calls and notifications will vibrate"</string>
     <string name="volume_dialog_ringer_guidance_silent" msgid="1011246774949993783">"Calls and notifications will be muted"</string>
     <string name="notification_channel_system_changes" msgid="2462010596920209678">"System changes"</string>
-    <string name="notification_channel_do_not_disturb" msgid="7832584281883687653">"Do not disturb"</string>
-    <string name="zen_upgrade_notification_visd_title" msgid="2001148984371968620">"New: Do Not Disturb is hiding notifications"</string>
-    <string name="zen_upgrade_notification_visd_content" msgid="3683314609114134946">"Tap to find out more and change."</string>
-    <string name="zen_upgrade_notification_title" msgid="8198167698095298717">"Do Not Disturb has changed"</string>
-    <string name="zen_upgrade_notification_content" msgid="5228458567180124005">"Tap to check what\'s blocked."</string>
     <string name="review_notification_settings_title" msgid="5102557424459810820">"Review notification settings"</string>
     <string name="review_notification_settings_text" msgid="5916244866751849279">"Starting in Android 13, apps that you install need your permission to send notifications. Tap to change this permission for existing apps."</string>
     <string name="review_notification_settings_remind_me_action" msgid="1081081018678480907">"Remind me later"</string>
diff --git a/core/res/res/values-en-rXC/strings.xml b/core/res/res/values-en-rXC/strings.xml
index a0a891e..b1ba09c 100644
--- a/core/res/res/values-en-rXC/strings.xml
+++ b/core/res/res/values-en-rXC/strings.xml
@@ -2129,11 +2129,6 @@
     <string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‎‎‏‎‎‎‏‎‎‎‎‎‎‏‏‏‏‏‏‎‎‎‎‎‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‎‎‎‏‎‎‎‎‎‏‏‎‎‏‏‏‎Calls and notifications will vibrate‎‏‎‎‏‎"</string>
     <string name="volume_dialog_ringer_guidance_silent" msgid="1011246774949993783">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‏‎‎‎‎‎‏‎‎‎‏‎‏‎‏‎‏‏‏‎‎‏‎‏‎‏‏‎‎‎‎‎‎‏‎‎‏‎‎‏‏‏‎‏‎‏‏‏‎‏‎‎‏‏‎‏‏‏‎Calls and notifications will be muted‎‏‎‎‏‎"</string>
     <string name="notification_channel_system_changes" msgid="2462010596920209678">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‎‏‎‎‎‏‎‏‎‏‎‏‏‎‏‎‎‎‏‏‎‎‏‎‏‏‏‏‏‏‏‎‏‏‎‏‎‏‎‏‏‎‏‎‎‏‏‎‎‎‏‎‎‎‎‏‏‏‎‎System changes‎‏‎‎‏‎"</string>
-    <string name="notification_channel_do_not_disturb" msgid="7832584281883687653">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‎‎‏‎‏‏‎‎‏‎‏‏‏‎‏‏‎‏‏‏‏‎‎‏‏‏‏‏‎‏‎‎‏‎‏‏‏‏‏‏‎‎‎‎‏‏‏‎‏‎‏‏‏‎‎‏‎‏‎Do Not Disturb‎‏‎‎‏‎"</string>
-    <string name="zen_upgrade_notification_visd_title" msgid="2001148984371968620">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‏‏‏‏‎‎‎‏‎‏‏‎‎‎‎‎‏‎‎‏‏‎‎‏‏‎‎‎‎‏‎‏‎‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‏‎‎‏‏‎‏‏‎‎‎New: Do Not Disturb is hiding notifications‎‏‎‎‏‎"</string>
-    <string name="zen_upgrade_notification_visd_content" msgid="3683314609114134946">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‏‏‎‎‎‏‏‏‎‏‏‏‎‎‎‎‏‏‎‎‎‏‏‏‏‏‎‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‎‎‏‏‏‎‎‏‏‎‏‎‎‎‏‎‎Tap to learn more and change.‎‏‎‎‏‎"</string>
-    <string name="zen_upgrade_notification_title" msgid="8198167698095298717">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‎‏‏‏‎‎‎‏‎‏‏‎‏‏‏‏‏‎‎‎‎‏‎‏‎‏‏‏‏‎‏‏‏‎‎‎‎‎‏‏‎‏‎‏‎‏‏‎‎‎‏‎‎‏‏‏‎‏‎Do Not Disturb has changed‎‏‎‎‏‎"</string>
-    <string name="zen_upgrade_notification_content" msgid="5228458567180124005">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‎‎‎‏‎‎‎‏‏‏‏‎‎‏‏‎‏‏‏‎‏‎‏‏‏‎‏‏‎‎‎‎‎‏‏‏‎‎‏‏‏‏‎‎‏‏‏‏‏‏‏‎‏‏‎‎‏‎‏‎Tap to check what\'s blocked.‎‏‎‎‏‎"</string>
     <string name="review_notification_settings_title" msgid="5102557424459810820">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‏‎‏‏‎‎‏‏‏‏‏‏‏‎‏‏‎‎‏‏‏‏‎‎‎‏‎‏‏‎‏‎‏‎‏‏‏‏‎‏‎‏‏‎‎‎‏‎‎‎‎‎‎‎‎‏‎‎‎Review notification settings‎‏‎‎‏‎"</string>
     <string name="review_notification_settings_text" msgid="5916244866751849279">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‎‏‎‎‎‎‏‏‎‏‎‏‎‏‏‏‎‎‏‎‏‎‏‏‏‎‎‎‏‎‏‎‏‏‎‏‏‏‏‏‎‎‎‏‏‏‎‎‎‏‏‎‎‏‏‏‏‏‏‎Starting in Android 13, apps that you install need your permission to send notifications. Tap to change this permission for existing apps.‎‏‎‎‏‎"</string>
     <string name="review_notification_settings_remind_me_action" msgid="1081081018678480907">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‏‏‎‎‎‎‎‎‎‎‏‏‎‎‎‏‎‏‎‏‏‏‎‏‎‏‎‏‏‎‏‎‏‏‏‎‏‏‏‏‏‏‏‎‎‏‎‎‎‎‎‎‎‎‏‎‏‏‎Remind me later‎‏‎‎‏‎"</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index cbb30fd..89b22b9 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -2130,11 +2130,6 @@
     <string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"Vibrarán las llamadas y notificaciones"</string>
     <string name="volume_dialog_ringer_guidance_silent" msgid="1011246774949993783">"Se silenciarán las llamadas y notificaciones"</string>
     <string name="notification_channel_system_changes" msgid="2462010596920209678">"Cambios del sistema"</string>
-    <string name="notification_channel_do_not_disturb" msgid="7832584281883687653">"No interrumpir"</string>
-    <string name="zen_upgrade_notification_visd_title" msgid="2001148984371968620">"Nuevo: No interrumpir oculta las notificaciones"</string>
-    <string name="zen_upgrade_notification_visd_content" msgid="3683314609114134946">"Presiona para obtener más información y realizar cambios."</string>
-    <string name="zen_upgrade_notification_title" msgid="8198167698095298717">"Se modificó la opción No interrumpir"</string>
-    <string name="zen_upgrade_notification_content" msgid="5228458567180124005">"Presiona para consultar lo que está bloqueado."</string>
     <string name="review_notification_settings_title" msgid="5102557424459810820">"Revisa la configuración de notificaciones"</string>
     <string name="review_notification_settings_text" msgid="5916244866751849279">"A partir de Android 13, las apps que instales necesitarán tu permiso a fin de enviar notificaciones. Presiona para cambiar este permiso para las apps existentes."</string>
     <string name="review_notification_settings_remind_me_action" msgid="1081081018678480907">"Recordarme más tarde"</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 23024f0..0082ade 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -1407,7 +1407,7 @@
     <string name="usb_unsupported_audio_accessory_title" msgid="2335775548086533065">"Se ha detectado un accesorio de audio analógico"</string>
     <string name="usb_unsupported_audio_accessory_message" msgid="1300168007129796621">"El dispositivo adjunto no es compatible con este teléfono. Toca para obtener más información."</string>
     <string name="adb_active_notification_title" msgid="408390247354560331">"Depuración por USB activa"</string>
-    <string name="adb_active_notification_message" msgid="5617264033476778211">"Toca para desactivar la depuración por USB"</string>
+    <string name="adb_active_notification_message" msgid="5617264033476778211">"Toca para desactivar depuración USB"</string>
     <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"Seleccionar para inhabilitar la depuración por USB"</string>
     <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Depuración inalámbrica conectada"</string>
     <string name="adbwifi_active_notification_message" msgid="930987922852867972">"Toca para desactivar la depuración inalámbrica"</string>
@@ -2130,11 +2130,6 @@
     <string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"Las llamadas y las notificaciones vibrarán"</string>
     <string name="volume_dialog_ringer_guidance_silent" msgid="1011246774949993783">"Las llamadas y las notificaciones se silenciarán"</string>
     <string name="notification_channel_system_changes" msgid="2462010596920209678">"Cambios del sistema"</string>
-    <string name="notification_channel_do_not_disturb" msgid="7832584281883687653">"No molestar"</string>
-    <string name="zen_upgrade_notification_visd_title" msgid="2001148984371968620">"Novedad: El modo No molestar oculta las notificaciones"</string>
-    <string name="zen_upgrade_notification_visd_content" msgid="3683314609114134946">"Toca para obtener más información y hacer cambios."</string>
-    <string name="zen_upgrade_notification_title" msgid="8198167698095298717">"Ha cambiado el modo No molestar"</string>
-    <string name="zen_upgrade_notification_content" msgid="5228458567180124005">"Toca para consultar lo que se está bloqueando."</string>
     <string name="review_notification_settings_title" msgid="5102557424459810820">"Consulta los ajustes de notificaciones"</string>
     <string name="review_notification_settings_text" msgid="5916244866751849279">"A partir de Android 13, las aplicaciones que instalas necesitan tu permiso para enviar notificaciones. Toca para cambiar este permiso en las aplicaciones que ya tengas."</string>
     <string name="review_notification_settings_remind_me_action" msgid="1081081018678480907">"Recordar más tarde"</string>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index 326b3db..44f1055 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -2129,11 +2129,6 @@
     <string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"Kõnede ja märguannete puhul seade vibreerib"</string>
     <string name="volume_dialog_ringer_guidance_silent" msgid="1011246774949993783">"Kõned ja märguanded on vaigistatud"</string>
     <string name="notification_channel_system_changes" msgid="2462010596920209678">"Süsteemi muudatused"</string>
-    <string name="notification_channel_do_not_disturb" msgid="7832584281883687653">"Mitte segada"</string>
-    <string name="zen_upgrade_notification_visd_title" msgid="2001148984371968620">"Uus: režiim Mitte segada peidab märguandeid"</string>
-    <string name="zen_upgrade_notification_visd_content" msgid="3683314609114134946">"Puudutage lisateabe vaatamiseks ja muutmiseks."</string>
-    <string name="zen_upgrade_notification_title" msgid="8198167698095298717">"Režiimi Mitte segada muudeti"</string>
-    <string name="zen_upgrade_notification_content" msgid="5228458567180124005">"Puudutage, et kontrollida, mis on blokeeritud."</string>
     <string name="review_notification_settings_title" msgid="5102557424459810820">"Vaadake üle märguandeseaded"</string>
     <string name="review_notification_settings_text" msgid="5916244866751849279">"Alates operatsioonisüsteemist Android 13 vajavad installitavad rakendused märguannete saatmiseks teie luba. Puudutage, et muuta seda luba olemasolevate rakenduste jaoks."</string>
     <string name="review_notification_settings_remind_me_action" msgid="1081081018678480907">"Tuleta hiljem meelde"</string>
diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml
index d092f46..d017a05 100644
--- a/core/res/res/values-eu/strings.xml
+++ b/core/res/res/values-eu/strings.xml
@@ -745,7 +745,7 @@
     <string name="face_error_lockout_screen_lock" msgid="5062609811636860928">"Saiakera gehiegi egin dira. Horren ordez, erabili pantailaren blokeoa."</string>
     <string name="face_error_unable_to_process" msgid="5723292697366130070">"Ezin da egiaztatu aurpegia. Saiatu berriro."</string>
     <string name="face_error_not_enrolled" msgid="1134739108536328412">"Ez duzu konfiguratu aurpegi bidez desblokeatzeko eginbidea"</string>
-    <string name="face_error_hw_not_present" msgid="7940978724978763011">"Aurpegi bidez desblokeatzeko eginbidea ez da bateragarria gailu honekin"</string>
+    <string name="face_error_hw_not_present" msgid="7940978724978763011">"Aurpegi bidez desblokeatzeko eginbidea ez da onartzen gailu honetan"</string>
     <string name="face_error_security_update_required" msgid="5076017208528750161">"Sentsorea aldi baterako desgaitu da."</string>
     <string name="face_name_template" msgid="3877037340223318119">"<xliff:g id="FACEID">%d</xliff:g> aurpegia"</string>
     <string name="face_app_setting_name" msgid="5854024256907828015">"Erabili aurpegi bidez desblokeatzeko eginbidea"</string>
@@ -2129,11 +2129,6 @@
     <string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"Dar-dar egingo du deiak eta jakinarazpenak jasotzean"</string>
     <string name="volume_dialog_ringer_guidance_silent" msgid="1011246774949993783">"Ez da joko tonurik deiak eta jakinarazpenak jasotzean"</string>
     <string name="notification_channel_system_changes" msgid="2462010596920209678">"Sistema-aldaketak"</string>
-    <string name="notification_channel_do_not_disturb" msgid="7832584281883687653">"Ez molestatzeko modua"</string>
-    <string name="zen_upgrade_notification_visd_title" msgid="2001148984371968620">"Berria: Ez molestatzeko modua jakinarazpenak ezkutatzen ari da"</string>
-    <string name="zen_upgrade_notification_visd_content" msgid="3683314609114134946">"Sakatu informazio gehiago lortzeko eta portaera aldatzeko."</string>
-    <string name="zen_upgrade_notification_title" msgid="8198167698095298717">"Ez molestatzeko modua aldatu da"</string>
-    <string name="zen_upgrade_notification_content" msgid="5228458567180124005">"Sakatu zer dagoen blokeatuta ikusteko."</string>
     <string name="review_notification_settings_title" msgid="5102557424459810820">"Berrikusi jakinarazpen-ezarpenak"</string>
     <string name="review_notification_settings_text" msgid="5916244866751849279">"Android 13 ezkero, jakinarazpenak bidaltzeko baimena eman behar diezu instalatzen dituzun aplikazioei. Sakatu hau lehendik dauden aplikazioen baimenak aldatzeko."</string>
     <string name="review_notification_settings_remind_me_action" msgid="1081081018678480907">"Gogorarazi geroago"</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index 6933a16..ad8f056 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -458,7 +458,7 @@
     <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"اجرای سرویس پیش‌نما از نوع «استفاده ویژه»"</string>
     <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"به برنامه اجازه می‌دهد از سرویس‌های پیش‌نما از نوع «استفاده ویژه» استفاده کند"</string>
     <string name="permlab_getPackageSize" msgid="375391550792886641">"اندازه‌گیری اندازه فضای ذخیره‌سازی برنامه"</string>
-    <string name="permdesc_getPackageSize" msgid="742743530909966782">"‏به برنامه اجازه می‎دهد تا کدها، داده‎ها و اندازه‎های حافظهٔ پنهان خود را بازیابی کند"</string>
+    <string name="permdesc_getPackageSize" msgid="742743530909966782">"‏به برنامه اجازه می‎دهد تا کدها، داده‎ها و اندازه‎های حافظه نهان خود را بازیابی کند"</string>
     <string name="permlab_writeSettings" msgid="8057285063719277394">"تغییر تنظیمات سیستم"</string>
     <string name="permdesc_writeSettings" msgid="8293047411196067188">"‏به برنامه اجازه می‎دهد تا داده‎های تنظیم سیستم را تغییر دهد. برنامه‌های مخرب می‎توانند پیکربندی سیستم شما را خراب کنند."</string>
     <string name="permlab_receiveBootCompleted" msgid="6643339400247325379">"اجرا شدن در هنگام راه‌اندازی"</string>
@@ -2129,11 +2129,6 @@
     <string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"دستگاهتان برای تماس‌ها و اعلان‌ها می‌لرزد"</string>
     <string name="volume_dialog_ringer_guidance_silent" msgid="1011246774949993783">"دستگاهتان برای تماس‌ها و اعلان‌ها بی‌صدا خواهد شد"</string>
     <string name="notification_channel_system_changes" msgid="2462010596920209678">"تغییرات سیستم"</string>
-    <string name="notification_channel_do_not_disturb" msgid="7832584281883687653">"مزاحم نشوید"</string>
-    <string name="zen_upgrade_notification_visd_title" msgid="2001148984371968620">"جدید: «مزاحم نشوید» اعلان‌ها را پنهان می‌کند"</string>
-    <string name="zen_upgrade_notification_visd_content" msgid="3683314609114134946">"برای اطلاعات بیشتر و تغییر دادن، تک‌ضرب بزنید."</string>
-    <string name="zen_upgrade_notification_title" msgid="8198167698095298717">"«مزاحم نشوید» تغییر کرده است"</string>
-    <string name="zen_upgrade_notification_content" msgid="5228458567180124005">"برای بررسی موارد مسدودشده تک‌ضرب بزنید."</string>
     <string name="review_notification_settings_title" msgid="5102557424459810820">"مرور تنظیمات اعلان"</string>
     <string name="review_notification_settings_text" msgid="5916244866751849279">"‏از Android نسخه ۱۳ به بعد، برنامه‌هایی که نصب می‌کنید برای ارسال اعلان به اجازه شما نیاز دارند. برای تغییر دادن این اجازه در برنامه‌های موجود، تک‌ضرب بزنید."</string>
     <string name="review_notification_settings_remind_me_action" msgid="1081081018678480907">"بعداً یادآوری شود"</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index 18c7902..196db12 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -2129,11 +2129,6 @@
     <string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"Puhelut ja ilmoitukset värisevät"</string>
     <string name="volume_dialog_ringer_guidance_silent" msgid="1011246774949993783">"Puhelut ja ilmoitukset mykistetään"</string>
     <string name="notification_channel_system_changes" msgid="2462010596920209678">"Järjestelmän muutokset"</string>
-    <string name="notification_channel_do_not_disturb" msgid="7832584281883687653">"Älä häiritse"</string>
-    <string name="zen_upgrade_notification_visd_title" msgid="2001148984371968620">"Uutta: Älä häiritse ‑tila piilottaa ilmoitukset"</string>
-    <string name="zen_upgrade_notification_visd_content" msgid="3683314609114134946">"Napauta, jos haluat lukea lisää ja tehdä muutoksia."</string>
-    <string name="zen_upgrade_notification_title" msgid="8198167698095298717">"Älä häiritse ‑tila muuttui"</string>
-    <string name="zen_upgrade_notification_content" msgid="5228458567180124005">"Napauta niin näet, mitä on estetty."</string>
     <string name="review_notification_settings_title" msgid="5102557424459810820">"Tarkista ilmoitusasetukset"</string>
     <string name="review_notification_settings_text" msgid="5916244866751849279">"Asentamasi sovellukset tarvitsevat sinulta luvan ilmoitusten lähettämiseen Android 13 ‑käyttöjärjestelmästä alkaen. Napauta muuttaaksesi nykyisten sovellusten lupia."</string>
     <string name="review_notification_settings_remind_me_action" msgid="1081081018678480907">"Muistuta myöhemmin"</string>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index bc11e547..ac87d3b 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -2130,11 +2130,6 @@
     <string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"Les appels et les notifications vibreront"</string>
     <string name="volume_dialog_ringer_guidance_silent" msgid="1011246774949993783">"Les appels et les notifications seront silencieux"</string>
     <string name="notification_channel_system_changes" msgid="2462010596920209678">"Changements système"</string>
-    <string name="notification_channel_do_not_disturb" msgid="7832584281883687653">"Ne pas déranger"</string>
-    <string name="zen_upgrade_notification_visd_title" msgid="2001148984371968620">"Nouveau : Le mode Ne pas déranger masque les notifications"</string>
-    <string name="zen_upgrade_notification_visd_content" msgid="3683314609114134946">"Touchez ici pour en savoir plus et changer les paramètres"</string>
-    <string name="zen_upgrade_notification_title" msgid="8198167698095298717">"Les paramètres du mode Ne pas déranger ont changé"</string>
-    <string name="zen_upgrade_notification_content" msgid="5228458567180124005">"Touchez l\'écran pour vérifier ce qui est bloqué."</string>
     <string name="review_notification_settings_title" msgid="5102557424459810820">"Examiner les paramètres de notification"</string>
     <string name="review_notification_settings_text" msgid="5916244866751849279">"À partir d\'Android 13, les applis que vous installez ont besoin de votre autorisation pour envoyer des notifications. Touchez pour modifier cette autorisation pour les applis existantes."</string>
     <string name="review_notification_settings_remind_me_action" msgid="1081081018678480907">"Me rappeler plus tard"</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index 03cf463..2368c88 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -1407,7 +1407,7 @@
     <string name="usb_unsupported_audio_accessory_title" msgid="2335775548086533065">"Accessoire audio analogique détecté"</string>
     <string name="usb_unsupported_audio_accessory_message" msgid="1300168007129796621">"L\'appareil connecté n\'est pas compatible avec ce téléphone. Appuyez ici pour en savoir plus."</string>
     <string name="adb_active_notification_title" msgid="408390247354560331">"Débogage USB activé"</string>
-    <string name="adb_active_notification_message" msgid="5617264033476778211">"Appuyez pour désactiver le débogage USB"</string>
+    <string name="adb_active_notification_message" msgid="5617264033476778211">"Appuyez pour le désactiver"</string>
     <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"Sélectionnez cette option pour désactiver le débogage USB."</string>
     <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Débogage sans fil connecté"</string>
     <string name="adbwifi_active_notification_message" msgid="930987922852867972">"Appuyez pour désactiver le débogage sans fil"</string>
@@ -2130,11 +2130,6 @@
     <string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"Les appels et les notifications vibreront"</string>
     <string name="volume_dialog_ringer_guidance_silent" msgid="1011246774949993783">"Les appels et les notifications seront silencieux"</string>
     <string name="notification_channel_system_changes" msgid="2462010596920209678">"Modifications du système"</string>
-    <string name="notification_channel_do_not_disturb" msgid="7832584281883687653">"Ne pas déranger"</string>
-    <string name="zen_upgrade_notification_visd_title" msgid="2001148984371968620">"Nouveau : Le mode Ne pas déranger masque les notifications"</string>
-    <string name="zen_upgrade_notification_visd_content" msgid="3683314609114134946">"Appuyez pour en savoir plus et pour modifier les paramètres."</string>
-    <string name="zen_upgrade_notification_title" msgid="8198167698095298717">"Le mode Ne pas déranger a été modifié"</string>
-    <string name="zen_upgrade_notification_content" msgid="5228458567180124005">"Appuyez pour vérifier les contenus bloqués."</string>
     <string name="review_notification_settings_title" msgid="5102557424459810820">"Vérifiez les paramètres de notification"</string>
     <string name="review_notification_settings_text" msgid="5916244866751849279">"À partir d\'Android 13, les applications que vous installez ont besoin de votre autorisation pour envoyer des notifications. Appuyez pour modifier cette autorisation pour les applications déjà installées."</string>
     <string name="review_notification_settings_remind_me_action" msgid="1081081018678480907">"Plus tard"</string>
diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml
index 430d649..2aba790 100644
--- a/core/res/res/values-gl/strings.xml
+++ b/core/res/res/values-gl/strings.xml
@@ -2129,11 +2129,6 @@
     <string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"As chamadas e as notificacións vibrarán"</string>
     <string name="volume_dialog_ringer_guidance_silent" msgid="1011246774949993783">"As chamadas e as notificacións estarán silenciadas"</string>
     <string name="notification_channel_system_changes" msgid="2462010596920209678">"Cambios no sistema"</string>
-    <string name="notification_channel_do_not_disturb" msgid="7832584281883687653">"Non molestar"</string>
-    <string name="zen_upgrade_notification_visd_title" msgid="2001148984371968620">"Novidade! O modo Non molestar oculta as notificacións"</string>
-    <string name="zen_upgrade_notification_visd_content" msgid="3683314609114134946">"Toca para obter máis información e facer cambios."</string>
-    <string name="zen_upgrade_notification_title" msgid="8198167698095298717">"O modo Non molestar cambiou"</string>
-    <string name="zen_upgrade_notification_content" msgid="5228458567180124005">"Toca para comprobar o contido bloqueado."</string>
     <string name="review_notification_settings_title" msgid="5102557424459810820">"Consulta a configuración de notificacións"</string>
     <string name="review_notification_settings_text" msgid="5916244866751849279">"Desde Android 13, as aplicacións que instales necesitan o teu permiso para enviar notificacións. Toca para cambiar este permiso nas aplicacións que xa teñas."</string>
     <string name="review_notification_settings_remind_me_action" msgid="1081081018678480907">"Lembrarmo máis tarde"</string>
diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml
index f40fb93..8d90e3b 100644
--- a/core/res/res/values-gu/strings.xml
+++ b/core/res/res/values-gu/strings.xml
@@ -2129,11 +2129,6 @@
     <string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"કૉલ અને નોટિફિકેશન માટે ઉપકરણ વાઇબ્રેટ થશે"</string>
     <string name="volume_dialog_ringer_guidance_silent" msgid="1011246774949993783">"કૉલ અને નોટિફિકેશન મ્યૂટ કરવામાં આવશે"</string>
     <string name="notification_channel_system_changes" msgid="2462010596920209678">"સિસ્ટમના ફેરફારો"</string>
-    <string name="notification_channel_do_not_disturb" msgid="7832584281883687653">"ખલેલ પાડશો નહીં"</string>
-    <string name="zen_upgrade_notification_visd_title" msgid="2001148984371968620">"નવું: ખલેલ પાડશો નહીં હવે નોટિફિકેશન છુપાવી શકે છે"</string>
-    <string name="zen_upgrade_notification_visd_content" msgid="3683314609114134946">"વધુ જાણવા અને બદલવા માટે ટૅપ કરો."</string>
-    <string name="zen_upgrade_notification_title" msgid="8198167698095298717">"ખલેલ પાડશો નહીંમાં ફેરફાર થયો છે"</string>
-    <string name="zen_upgrade_notification_content" msgid="5228458567180124005">"શું બ્લૉક કરેલ છે તે તપાસવા માટે ટૅપ કરો."</string>
     <string name="review_notification_settings_title" msgid="5102557424459810820">"નોટિફિકેશનના સેટિંગ રિવ્યૂ કરો"</string>
     <string name="review_notification_settings_text" msgid="5916244866751849279">"Android 13થી શરૂઆત કરીને, તમે જે પણ ઍપ ઇન્સ્ટૉલ કરશો, તેને નોટિફિકેશન મોકલવા માટે તમારી પરવાનગીની જરૂર રહેશે. હાલની બધી ઍપ માટે આ પરવાનગીમાં ફેરફાર કરવા માટે ટૅપ કરો."</string>
     <string name="review_notification_settings_remind_me_action" msgid="1081081018678480907">"મને પછી યાદ અપાવજો"</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index 0386387f..12ffe87 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -2129,11 +2129,6 @@
     <string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"कॉल और सूचनाओं आने पर डिवाइस वाइब्रेट हाेगा"</string>
     <string name="volume_dialog_ringer_guidance_silent" msgid="1011246774949993783">"कॉल और सूचनाओं के लिए डिवाइस म्यूट रहेगा"</string>
     <string name="notification_channel_system_changes" msgid="2462010596920209678">"सिस्टम में हुए बदलाव"</string>
-    <string name="notification_channel_do_not_disturb" msgid="7832584281883687653">"परेशान न करें"</string>
-    <string name="zen_upgrade_notification_visd_title" msgid="2001148984371968620">"नई सुविधा: परेशान न करें सुविधा चालू होने की वजह से सूचनाएं नहीं दिखाई जा रही हैं"</string>
-    <string name="zen_upgrade_notification_visd_content" msgid="3683314609114134946">"ज़्यादा जानने और बदलाव करने के लिए टैप करें."</string>
-    <string name="zen_upgrade_notification_title" msgid="8198167698095298717">"परेशान न करें की सुविधा बदल गई है"</string>
-    <string name="zen_upgrade_notification_content" msgid="5228458567180124005">"टैप करके देखें कि किन चीज़ों पर रोक लगाई गई है."</string>
     <string name="review_notification_settings_title" msgid="5102557424459810820">"सूचना सेटिंग देखें"</string>
     <string name="review_notification_settings_text" msgid="5916244866751849279">"Android 13 में जो ऐप्लिकेशन इंस्टॉल किए जाएंगे, उन्हें आपको सूचनाएं भेजने के लिए अनुमति लेनी होगी. पहले से इंस्टॉल किए गए ऐप्लिकेशन को दी गई अनुमति बदलने के लिए टैप करें."</string>
     <string name="review_notification_settings_remind_me_action" msgid="1081081018678480907">"बाद में याद दिलाएं"</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index 54dc55d..895c3fa 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -2130,11 +2130,6 @@
     <string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"Uređaj će vibrirati za pozive i obavijesti"</string>
     <string name="volume_dialog_ringer_guidance_silent" msgid="1011246774949993783">"Zvučni signal poziva i obavijesti bit će isključen"</string>
     <string name="notification_channel_system_changes" msgid="2462010596920209678">"Promjene sustava"</string>
-    <string name="notification_channel_do_not_disturb" msgid="7832584281883687653">"Ne uznemiravaj"</string>
-    <string name="zen_upgrade_notification_visd_title" msgid="2001148984371968620">"Novo: način Ne uznemiravaj sakriva obavijesti"</string>
-    <string name="zen_upgrade_notification_visd_content" msgid="3683314609114134946">"Dodirnite da biste saznali više i promijenili postavke."</string>
-    <string name="zen_upgrade_notification_title" msgid="8198167698095298717">"Promijenjena je postavka Ne uznemiravaj"</string>
-    <string name="zen_upgrade_notification_content" msgid="5228458567180124005">"Dodirnite da biste provjerili što je blokirano."</string>
     <string name="review_notification_settings_title" msgid="5102557424459810820">"Pregledajte postavke obavijesti"</string>
     <string name="review_notification_settings_text" msgid="5916244866751849279">"Od Androida 13 aplikacije koje instalirate trebaju vaše dopuštenje za slanje obavijesti. Dodirnite da biste promijenili to dopuštenje za postojeće aplikacije."</string>
     <string name="review_notification_settings_remind_me_action" msgid="1081081018678480907">"Podsjeti me kasnije"</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index 179de20..3bbaef2 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -2129,11 +2129,6 @@
     <string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"A hívások és az értesítések rezegnek"</string>
     <string name="volume_dialog_ringer_guidance_silent" msgid="1011246774949993783">"A hívások és az értesítések némák"</string>
     <string name="notification_channel_system_changes" msgid="2462010596920209678">"Rendszermódosítások"</string>
-    <string name="notification_channel_do_not_disturb" msgid="7832584281883687653">"Ne zavarjanak"</string>
-    <string name="zen_upgrade_notification_visd_title" msgid="2001148984371968620">"Újdonság: A Ne zavarjanak mód elrejti az értesítéseket"</string>
-    <string name="zen_upgrade_notification_visd_content" msgid="3683314609114134946">"Koppintással további információhoz juthat, és elvégezheti a módosítást."</string>
-    <string name="zen_upgrade_notification_title" msgid="8198167698095298717">"Módosultak a Ne zavarjanak mód beállításai"</string>
-    <string name="zen_upgrade_notification_content" msgid="5228458567180124005">"Koppintson a letiltott elemek megtekintéséhez."</string>
     <string name="review_notification_settings_title" msgid="5102557424459810820">"Értesítési beállítások áttekintése"</string>
     <string name="review_notification_settings_text" msgid="5916244866751849279">"Az Android 13-as rendszertől kezdődően a telepített alkalmazásoknak engedélyre van szükségük értesítések küldéséhez. Koppintással módosíthatja ezt az engedélyt a meglévő alkalmazások esetében."</string>
     <string name="review_notification_settings_remind_me_action" msgid="1081081018678480907">"Emlékeztessen később"</string>
diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml
index 312a105..d341adaf 100644
--- a/core/res/res/values-hy/strings.xml
+++ b/core/res/res/values-hy/strings.xml
@@ -2129,11 +2129,6 @@
     <string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"Զանգերի և ծանուցումների համար թրթռոցը միացված է"</string>
     <string name="volume_dialog_ringer_guidance_silent" msgid="1011246774949993783">"Զանգերի և ծանուցումների համար ձայնն անջատված է"</string>
     <string name="notification_channel_system_changes" msgid="2462010596920209678">"Համակարգի փոփոխություններ"</string>
-    <string name="notification_channel_do_not_disturb" msgid="7832584281883687653">"Չանհանգստացնել"</string>
-    <string name="zen_upgrade_notification_visd_title" msgid="2001148984371968620">"Այժմ «Չանհանգստացնել» ռեժիմում ծանուցումները թաքցվում են"</string>
-    <string name="zen_upgrade_notification_visd_content" msgid="3683314609114134946">"Հպեք՝ ավելին իմանալու և կարգավորումները փոխելու համար:"</string>
-    <string name="zen_upgrade_notification_title" msgid="8198167698095298717">"«Չանհանգստացնել» ռեժիմի կարգավորումները փոխվել են"</string>
-    <string name="zen_upgrade_notification_content" msgid="5228458567180124005">"Հպեք՝ տեսնելու, թե ինչ է արգելափակվել:"</string>
     <string name="review_notification_settings_title" msgid="5102557424459810820">"Ստուգեք ծանուցումների կարգավորումները"</string>
     <string name="review_notification_settings_text" msgid="5916244866751849279">"Հավելվածներին, որոնք տեղադրում եք Android 13 և ավելի նոր տարբերակներով սարքերում, անհրաժեշտ է տրամադրել ծանուցումներ ուղարկելու թույլտվություն։ Հպեք և փոխեք այս թույլտվությունն արդեն տեղադրված հավելվածների համար։"</string>
     <string name="review_notification_settings_remind_me_action" msgid="1081081018678480907">"Հիշեցնել ավելի ուշ"</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index e830d6d..957e835 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -1904,7 +1904,7 @@
     <string name="managed_profile_label_badge_2" msgid="5673187309555352550">"Upaya ke-2 <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="managed_profile_label_badge_3" msgid="6882151970556391957">"Upaya ke-3 <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="clone_profile_label_badge" msgid="1871997694718793964">"Clone <xliff:g id="LABEL">%1$s</xliff:g>"</string>
-    <string name="private_profile_label_badge" msgid="1712086003787839183">"<xliff:g id="LABEL">%1$s</xliff:g> Pribadi"</string>
+    <string name="private_profile_label_badge" msgid="1712086003787839183">"<xliff:g id="LABEL">%1$s</xliff:g> Privasi"</string>
     <string name="lock_to_app_unlock_pin" msgid="3890940811866290782">"Meminta PIN sebelum melepas sematan"</string>
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Meminta pola pembukaan kunci sebelum melepas sematan"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Meminta sandi sebelum melepas sematan"</string>
@@ -2129,11 +2129,6 @@
     <string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"Panggilan dan notifikasi akan bergetar"</string>
     <string name="volume_dialog_ringer_guidance_silent" msgid="1011246774949993783">"Suara panggilan dan notifikasi akan dinonaktifkan"</string>
     <string name="notification_channel_system_changes" msgid="2462010596920209678">"Perubahan sistem"</string>
-    <string name="notification_channel_do_not_disturb" msgid="7832584281883687653">"Jangan Ganggu"</string>
-    <string name="zen_upgrade_notification_visd_title" msgid="2001148984371968620">"Baru: Mode Jangan Ganggu menyembunyikan notifikasi"</string>
-    <string name="zen_upgrade_notification_visd_content" msgid="3683314609114134946">"Ketuk untuk mempelajari lebih lanjut dan mengubah."</string>
-    <string name="zen_upgrade_notification_title" msgid="8198167698095298717">"Jangan Ganggu telah berubah"</string>
-    <string name="zen_upgrade_notification_content" msgid="5228458567180124005">"Ketuk untuk memeriksa item yang diblokir."</string>
     <string name="review_notification_settings_title" msgid="5102557424459810820">"Tinjau setelan notifikasi"</string>
     <string name="review_notification_settings_text" msgid="5916244866751849279">"Mulai Android 13, aplikasi yang Anda instal memerlukan izin untuk mengirim notifikasi. Ketuk guna mengubah izin ini untuk aplikasi yang sudah ada."</string>
     <string name="review_notification_settings_remind_me_action" msgid="1081081018678480907">"Ingatkan saya nanti"</string>
diff --git a/core/res/res/values-is/strings.xml b/core/res/res/values-is/strings.xml
index 307fb52..b6d1c12 100644
--- a/core/res/res/values-is/strings.xml
+++ b/core/res/res/values-is/strings.xml
@@ -2129,11 +2129,6 @@
     <string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"Titringur er virkur fyrir símtöl og tilkynningar"</string>
     <string name="volume_dialog_ringer_guidance_silent" msgid="1011246774949993783">"Slökkt verður á hljóði símtala og tilkynninga"</string>
     <string name="notification_channel_system_changes" msgid="2462010596920209678">"Breytingar á kerfi"</string>
-    <string name="notification_channel_do_not_disturb" msgid="7832584281883687653">"Ónáðið ekki"</string>
-    <string name="zen_upgrade_notification_visd_title" msgid="2001148984371968620">"Nýtt: „Ónáðið ekki“ er að fela tilkynningar"</string>
-    <string name="zen_upgrade_notification_visd_content" msgid="3683314609114134946">"Ýttu til að fá frekari upplýsingar og breyta."</string>
-    <string name="zen_upgrade_notification_title" msgid="8198167698095298717">"„Ónáðið ekki“ var breytt"</string>
-    <string name="zen_upgrade_notification_content" msgid="5228458567180124005">"Ýttu til að skoða hvað lokað hefur verið á."</string>
     <string name="review_notification_settings_title" msgid="5102557424459810820">"Yfirfara tilkynningastillingar"</string>
     <string name="review_notification_settings_text" msgid="5916244866751849279">"Frá og með Android 13 þurfa forrit sem þú setur upp heimild frá þér til að senda tilkynningar. Ýttu til að breyta þessari heimild fyrir forrit sem fyrir eru."</string>
     <string name="review_notification_settings_remind_me_action" msgid="1081081018678480907">"Minna mig á seinna"</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 08ea1f1..66e5f72 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -2130,11 +2130,6 @@
     <string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"La vibrazione sarà attiva per chiamate e notifiche"</string>
     <string name="volume_dialog_ringer_guidance_silent" msgid="1011246774949993783">"L\'audio di chiamate e notifiche sarà disattivato"</string>
     <string name="notification_channel_system_changes" msgid="2462010596920209678">"Modifiche al sistema"</string>
-    <string name="notification_channel_do_not_disturb" msgid="7832584281883687653">"Non disturbare"</string>
-    <string name="zen_upgrade_notification_visd_title" msgid="2001148984371968620">"Novità: la modalità Non disturbare nasconde le notifiche"</string>
-    <string name="zen_upgrade_notification_visd_content" msgid="3683314609114134946">"Tocca per avere ulteriori informazioni e modificare."</string>
-    <string name="zen_upgrade_notification_title" msgid="8198167698095298717">"L\'impostazione Non disturbare è cambiata"</string>
-    <string name="zen_upgrade_notification_content" msgid="5228458567180124005">"Tocca per controllare le notifiche bloccate."</string>
     <string name="review_notification_settings_title" msgid="5102557424459810820">"Controlla le impostazioni di notifica"</string>
     <string name="review_notification_settings_text" msgid="5916244866751849279">"A partire da Android 13, le app che installi devono avere la tua autorizzazione per poter inviare notifiche. Tocca per cambiare questa autorizzazione per le app esistenti."</string>
     <string name="review_notification_settings_remind_me_action" msgid="1081081018678480907">"Ricordamelo dopo"</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index 1c1918c..8f4fbcd 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -2130,11 +2130,6 @@
     <string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"שיחות והודעות ירטטו"</string>
     <string name="volume_dialog_ringer_guidance_silent" msgid="1011246774949993783">"שיחות והתראות יושתקו"</string>
     <string name="notification_channel_system_changes" msgid="2462010596920209678">"שינויים במערכת"</string>
-    <string name="notification_channel_do_not_disturb" msgid="7832584281883687653">"נא לא להפריע"</string>
-    <string name="zen_upgrade_notification_visd_title" msgid="2001148984371968620">"חדש: מצב \'נא לא להפריע\' מסתיר התראות"</string>
-    <string name="zen_upgrade_notification_visd_content" msgid="3683314609114134946">"אפשר להקיש כדי לקבל מידע נוסף ולבצע שינויים."</string>
-    <string name="zen_upgrade_notification_title" msgid="8198167698095298717">"ההגדרה \'נא לא להפריע\' השתנתה"</string>
-    <string name="zen_upgrade_notification_content" msgid="5228458567180124005">"יש להקיש כדי לבדוק מה חסום."</string>
     <string name="review_notification_settings_title" msgid="5102557424459810820">"בדיקת הגדרת ההתראות"</string>
     <string name="review_notification_settings_text" msgid="5916244866751849279">"‏החל מגרסת Android 13, אפליקציות שיותקנו יוכלו לשלוח התראות רק אם יקבלו ממך הרשאה. אפשר להקיש כדי לשנות את ההרשאה הזו באפליקציות קיימות."</string>
     <string name="review_notification_settings_remind_me_action" msgid="1081081018678480907">"תזכירו לי מאוחר יותר"</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 36d956c..cd5527c 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -2129,11 +2129,6 @@
     <string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"着信や通知をバイブレーションで知らせます"</string>
     <string name="volume_dialog_ringer_guidance_silent" msgid="1011246774949993783">"着信音と通知音が鳴りません"</string>
     <string name="notification_channel_system_changes" msgid="2462010596920209678">"システムの変更"</string>
-    <string name="notification_channel_do_not_disturb" msgid="7832584281883687653">"サイレント モード"</string>
-    <string name="zen_upgrade_notification_visd_title" msgid="2001148984371968620">"新機能: サイレント モードでは通知が非表示になります"</string>
-    <string name="zen_upgrade_notification_visd_content" msgid="3683314609114134946">"タップすると、詳細を確認して設定を変更できます。"</string>
-    <string name="zen_upgrade_notification_title" msgid="8198167698095298717">"サイレント モードが変わりました"</string>
-    <string name="zen_upgrade_notification_content" msgid="5228458567180124005">"タップしてブロック対象をご確認ください。"</string>
     <string name="review_notification_settings_title" msgid="5102557424459810820">"通知設定の確認"</string>
     <string name="review_notification_settings_text" msgid="5916244866751849279">"Android 13 以降では、インストールするアプリに、通知を送信する権限を付与する必要があります。既存のアプリのこの権限を変更するには、タップしてください。"</string>
     <string name="review_notification_settings_remind_me_action" msgid="1081081018678480907">"後で"</string>
diff --git a/core/res/res/values-ka/strings.xml b/core/res/res/values-ka/strings.xml
index 9a88e54..9b1c07f 100644
--- a/core/res/res/values-ka/strings.xml
+++ b/core/res/res/values-ka/strings.xml
@@ -2129,11 +2129,6 @@
     <string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"ზარების და შეტყობინებების მიღებისას ვიბრაცია ჩაირთვება"</string>
     <string name="volume_dialog_ringer_guidance_silent" msgid="1011246774949993783">"ზარები და შეტყობინებები დადუმებული იქნება"</string>
     <string name="notification_channel_system_changes" msgid="2462010596920209678">"სისტემის ცვლილებები"</string>
-    <string name="notification_channel_do_not_disturb" msgid="7832584281883687653">"არ შემაწუხოთ"</string>
-    <string name="zen_upgrade_notification_visd_title" msgid="2001148984371968620">"ახალი: „არ შემაწუხოთ“ რეჟიმი მალავს შეტყობინებებს"</string>
-    <string name="zen_upgrade_notification_visd_content" msgid="3683314609114134946">"შეეხეთ მეტის გასაგებად და შესაცვლელად."</string>
-    <string name="zen_upgrade_notification_title" msgid="8198167698095298717">"„არ შემაწუხოთ“ რეჟიმი შეცვლილია"</string>
-    <string name="zen_upgrade_notification_content" msgid="5228458567180124005">"შეეხეთ იმის სანახავად, თუ რა არის დაბლოკილი."</string>
     <string name="review_notification_settings_title" msgid="5102557424459810820">"შეტყობინების პარამეტრების შემოწმება"</string>
     <string name="review_notification_settings_text" msgid="5916244866751849279">"Android 13-ზე შეტყობინებების გასაგზავნად საჭიროა თქვენ მიერ დაინსტალირებული აპებისთვის ნებართვის მინიჭება. არსებული აპებისთვის ამ ნებართვის შესაცვლელად შეეხეთ."</string>
     <string name="review_notification_settings_remind_me_action" msgid="1081081018678480907">"შემახსენე მოგვიან."</string>
diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml
index 595b9ba..ebf627f 100644
--- a/core/res/res/values-kk/strings.xml
+++ b/core/res/res/values-kk/strings.xml
@@ -2129,11 +2129,6 @@
     <string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"Қоңыраулар мен хабарландырулардың дірілі болады."</string>
     <string name="volume_dialog_ringer_guidance_silent" msgid="1011246774949993783">"Қоңыраулар мен хабарландырулардың дыбыстық сигналы өшіріледі"</string>
     <string name="notification_channel_system_changes" msgid="2462010596920209678">"Жүйе өзгерістері"</string>
-    <string name="notification_channel_do_not_disturb" msgid="7832584281883687653">"Мазаламау режимі"</string>
-    <string name="zen_upgrade_notification_visd_title" msgid="2001148984371968620">"Жаңа: Мазаламау режимі хабарландыруларды жасыруда"</string>
-    <string name="zen_upgrade_notification_visd_content" msgid="3683314609114134946">"Толығырақ ақпарат алу және өзгерту үшін түртіңіз."</string>
-    <string name="zen_upgrade_notification_title" msgid="8198167698095298717">"Мазаламау режимі өзгерді"</string>
-    <string name="zen_upgrade_notification_content" msgid="5228458567180124005">"Түймені түртіп, неге тыйым салынатынын көріңіз."</string>
     <string name="review_notification_settings_title" msgid="5102557424459810820">"Хабарландыру параметрлерін қарау"</string>
     <string name="review_notification_settings_text" msgid="5916244866751849279">"Android 13 нұсқасынан бастап орнатылатын қолданбалар үшін хабарландыру жіберу рұқсаты керек. Бұрынғы қолданбаларда осы рұқсатты өзгерту үшін түртіңіз."</string>
     <string name="review_notification_settings_remind_me_action" msgid="1081081018678480907">"Кейінірек еске салу"</string>
diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml
index 696bd79..df7006a 100644
--- a/core/res/res/values-km/strings.xml
+++ b/core/res/res/values-km/strings.xml
@@ -2129,11 +2129,6 @@
     <string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"ការហៅ​ទូរសព្ទ និងការជូន​ដំណឹងនឹងញ័រ"</string>
     <string name="volume_dialog_ringer_guidance_silent" msgid="1011246774949993783">"ការហៅ​ទូរសព្ទ និងការជូន​ដំណឹងនឹង​បិទសំឡេង"</string>
     <string name="notification_channel_system_changes" msgid="2462010596920209678">"ការផ្លាស់ប្ដូរ​ប្រព័ន្ធ"</string>
-    <string name="notification_channel_do_not_disturb" msgid="7832584281883687653">"កុំ​រំខាន"</string>
-    <string name="zen_upgrade_notification_visd_title" msgid="2001148984371968620">"ថ្មី៖ មុខងារ​កុំរំខាន​កំពុងលាក់​ការជូនដំណឹង"</string>
-    <string name="zen_upgrade_notification_visd_content" msgid="3683314609114134946">"ចុចដើម្បីស្វែងយល់បន្ថែម និងផ្លាស់ប្ដូរ។"</string>
-    <string name="zen_upgrade_notification_title" msgid="8198167698095298717">"មុខងារ​កុំ​រំខាន​ត្រូវ​បាន​ប្ដូរ"</string>
-    <string name="zen_upgrade_notification_content" msgid="5228458567180124005">"សូមចុច​ដើម្បី​មើល​ថា​​បានទប់ស្កាត់អ្វីខ្លះ។"</string>
     <string name="review_notification_settings_title" msgid="5102557424459810820">"ពិនិត្យមើលការកំណត់ការជូនដំណឹង"</string>
     <string name="review_notification_settings_text" msgid="5916244866751849279">"ចាប់ពី Android 13 ឡើងទៅ កម្មវិធីដែលអ្នកដំឡើងត្រូវការ​ការអនុញ្ញាតរបស់អ្នក ដើម្បីផ្ញើការជូនដំណឹង។ សូមចុចដើម្បីផ្លាស់ប្ដូរការអនុញ្ញាតនេះសម្រាប់កម្មវិធីដែលមានស្រាប់។"</string>
     <string name="review_notification_settings_remind_me_action" msgid="1081081018678480907">"រំលឹក​ខ្ញុំ​ពេលក្រោយ"</string>
diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml
index 419dd17..5ddb586 100644
--- a/core/res/res/values-kn/strings.xml
+++ b/core/res/res/values-kn/strings.xml
@@ -2129,11 +2129,6 @@
     <string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"ಕರೆಗಳು ಮತ್ತು ಅಧಿಸೂಚನೆಗಳು ವೈಬ್ರೇಟ್‌ ಆಗುತ್ತವೆ"</string>
     <string name="volume_dialog_ringer_guidance_silent" msgid="1011246774949993783">"ಕರೆಗಳು ಮತ್ತು ಅಧಿಸೂಚನೆಗಳನ್ನು ಮ್ಯೂಟ್ ಮಾಡಲಾಗುತ್ತದೆ"</string>
     <string name="notification_channel_system_changes" msgid="2462010596920209678">"ಸಿಸ್ಟಂ ಬದಲಾವಣೆಗಳು"</string>
-    <string name="notification_channel_do_not_disturb" msgid="7832584281883687653">"ಅಡಚಣೆ ಮಾಡಬೇಡಿ"</string>
-    <string name="zen_upgrade_notification_visd_title" msgid="2001148984371968620">"ಅಡಚಣೆ ಮಾಡಬೇಡಿ ಮೋಡ್ ಅಧಿಸೂಚನೆಗಳನ್ನು ಮರೆಮಾಡುತ್ತಿದೆ"</string>
-    <string name="zen_upgrade_notification_visd_content" msgid="3683314609114134946">"ಇನ್ನಷ್ಟು ತಿಳಿಯಲು ಮತ್ತು ಬದಲಿಸಲು ಟ್ಯಾಪ್ ಮಾಡಿ."</string>
-    <string name="zen_upgrade_notification_title" msgid="8198167698095298717">"ಅಡಚಣೆ ಮಾಡಬೇಡಿ ಬದಲಾಗಿದೆ"</string>
-    <string name="zen_upgrade_notification_content" msgid="5228458567180124005">"ಏನನ್ನು ನಿರ್ಬಂಧಿಸಲಾಗಿದೆ ಎಂಬುದನ್ನು ಪರೀಕ್ಷಿಸಲು ಟ್ಯಾಪ್ ಮಾಡಿ."</string>
     <string name="review_notification_settings_title" msgid="5102557424459810820">"ನೋಟಿಫಿಕೇಶನ್ ಸೆಟ್ಟಿಂಗ್‌ಗಳನ್ನು ಪರಿಶೀಲಿಸಿ"</string>
     <string name="review_notification_settings_text" msgid="5916244866751849279">"Android 13 ನಿಂದ ಪ್ರಾರಂಭಿಸಿ, ನೀವು ಇನ್‌ಸ್ಟಾಲ್ ಮಾಡುವ ಆ್ಯಪ್‌ಗಳಿಗೆ, ಅಧಿಸೂಚನೆಗಳನ್ನು ಕಳುಹಿಸಲು ನಿಮ್ಮ ಅನುಮತಿಯ ಅಗತ್ಯವಿದೆ. ಅಸ್ತಿತ್ವದಲ್ಲಿರುವ ಆ್ಯಪ್‌ಗಳಿಗಾಗಿ ಈ ಅನುಮತಿಯನ್ನು ಬದಲಾಯಿಸಲು ಟ್ಯಾಪ್ ಮಾಡಿ."</string>
     <string name="review_notification_settings_remind_me_action" msgid="1081081018678480907">"ನಂತರ ರಿಮೈಂಡ್ ಮಾಡಿ"</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 5f0e1f9..92ca1d5 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -2129,11 +2129,6 @@
     <string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"전화 및 알림이 오면 진동이 사용됩니다."</string>
     <string name="volume_dialog_ringer_guidance_silent" msgid="1011246774949993783">"전화 및 알림 소리가 음소거됩니다."</string>
     <string name="notification_channel_system_changes" msgid="2462010596920209678">"시스템 변경사항"</string>
-    <string name="notification_channel_do_not_disturb" msgid="7832584281883687653">"방해 금지 모드"</string>
-    <string name="zen_upgrade_notification_visd_title" msgid="2001148984371968620">"새로운 기능: 방해 금지 모드로 알림 숨기기"</string>
-    <string name="zen_upgrade_notification_visd_content" msgid="3683314609114134946">"자세히 알아보고 변경하려면 탭하세요."</string>
-    <string name="zen_upgrade_notification_title" msgid="8198167698095298717">"방해 금지 모드 변경"</string>
-    <string name="zen_upgrade_notification_content" msgid="5228458567180124005">"차단된 항목을 확인하려면 탭하세요."</string>
     <string name="review_notification_settings_title" msgid="5102557424459810820">"알림 설정 검토"</string>
     <string name="review_notification_settings_text" msgid="5916244866751849279">"Android 13부터 설치된 앱에는 알림을 전송하기 위한 권한이 필요합니다. 기존 앱의 알림 전송 권한을 변경하려면 탭하세요."</string>
     <string name="review_notification_settings_remind_me_action" msgid="1081081018678480907">"나중에 알림"</string>
diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml
index 14e1064..a4380253 100644
--- a/core/res/res/values-ky/strings.xml
+++ b/core/res/res/values-ky/strings.xml
@@ -2129,11 +2129,6 @@
     <string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"Чалуулар менен билдирмелер дирилдөө режиминде иштейт"</string>
     <string name="volume_dialog_ringer_guidance_silent" msgid="1011246774949993783">"Чалуулар менен эскертмелердин үнү өчүрүлөт"</string>
     <string name="notification_channel_system_changes" msgid="2462010596920209678">"Система өзгөрүүлөрү"</string>
-    <string name="notification_channel_do_not_disturb" msgid="7832584281883687653">"Тынчымды алба"</string>
-    <string name="zen_upgrade_notification_visd_title" msgid="2001148984371968620">"Жаңы: \"Тынчымды алба\" режими билдирмелерди жашырууда"</string>
-    <string name="zen_upgrade_notification_visd_content" msgid="3683314609114134946">"Көбүрөөк маалымат алып, өзгөртүү үчүн таптаңыз."</string>
-    <string name="zen_upgrade_notification_title" msgid="8198167698095298717">"\"Тынчымды алба\" режими өзгөрдү"</string>
-    <string name="zen_upgrade_notification_content" msgid="5228458567180124005">"Бөгөттөлгөн нерселерди көрүү үчүн таптаңыз."</string>
     <string name="review_notification_settings_title" msgid="5102557424459810820">"Билдирмелердин параметрлерин карап чыгуу"</string>
     <string name="review_notification_settings_text" msgid="5916244866751849279">"Android 13 версиясынан баштап билдирмелерди жөнөтүү үчүн орноткон колдонмолоруңузга уруксат берүү керек. Учурдагы колдонмолор үчүн бул уруксатты өзгөртүү үчүн таптап коюңуз."</string>
     <string name="review_notification_settings_remind_me_action" msgid="1081081018678480907">"Кийинчерээк эскертүү"</string>
diff --git a/core/res/res/values-lo/strings.xml b/core/res/res/values-lo/strings.xml
index fb677cf..be09c10 100644
--- a/core/res/res/values-lo/strings.xml
+++ b/core/res/res/values-lo/strings.xml
@@ -2129,11 +2129,6 @@
     <string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"ການໂທ ແລະ ການແຈ້ງເຕືອນຈະສັ່ນ"</string>
     <string name="volume_dialog_ringer_guidance_silent" msgid="1011246774949993783">"ການໂທ ແລະ ການແຈ້ງເຕືອນຈະບໍ່ມີສຽງ"</string>
     <string name="notification_channel_system_changes" msgid="2462010596920209678">"ການປ່ຽນແປງລະບົບ"</string>
-    <string name="notification_channel_do_not_disturb" msgid="7832584281883687653">"ຫ້າມລົບກວນ"</string>
-    <string name="zen_upgrade_notification_visd_title" msgid="2001148984371968620">"ໃໝ່: ໂໝດຫ້າມລົບກວນຈະເຊື່ອງການແຈ້ງເຕືອນໄວ້"</string>
-    <string name="zen_upgrade_notification_visd_content" msgid="3683314609114134946">"ແຕະເພື່ອສຶກສາເພີ່ມເຕີມ ແລະ ປ່ຽນແປງ."</string>
-    <string name="zen_upgrade_notification_title" msgid="8198167698095298717">"ປ່ຽນໂໝດຫ້າມລົບກວນແລ້ວ"</string>
-    <string name="zen_upgrade_notification_content" msgid="5228458567180124005">"ແຕະເພື່ອກວດສອບວ່າມີຫຍັງຖືກບລັອກໄວ້ແດ່."</string>
     <string name="review_notification_settings_title" msgid="5102557424459810820">"ກວດສອບ​ການ​ຕັ້ງ​ຄ່າ​ການ​ແຈ້ງ​ເຕືອນ"</string>
     <string name="review_notification_settings_text" msgid="5916244866751849279">"ເລີ່ມຕົ້ນໃນ Android 13, ແອັບຕ່າງໆທີ່ທ່ານຕິດຕັ້ງຈະຕ້ອງໃຊ້ການອະນຸຍາດຂອງທ່ານເພື່ອສົ່ງການແຈ້ງເຕືອນ. ແຕະເພື່ອປ່ຽນການອະນຸຍາດນີ້ສຳລັບແອັບທີ່ມີຢູ່ກ່ອນແລ້ວ."</string>
     <string name="review_notification_settings_remind_me_action" msgid="1081081018678480907">"ແຈ້ງເຕືອນຂ້ອຍພາຍຫຼັງ"</string>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index e617a4c..45998ee 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -2131,11 +2131,6 @@
     <string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"Skambučiai ir pranešimai vibruos"</string>
     <string name="volume_dialog_ringer_guidance_silent" msgid="1011246774949993783">"Skambučiai ir pranešimai bus nutildyti"</string>
     <string name="notification_channel_system_changes" msgid="2462010596920209678">"Sistemos pakeitimai"</string>
-    <string name="notification_channel_do_not_disturb" msgid="7832584281883687653">"Netrukdymo režimas"</string>
-    <string name="zen_upgrade_notification_visd_title" msgid="2001148984371968620">"Naujiena: naudojant netrukdymo režimą pranešimai slepiami"</string>
-    <string name="zen_upgrade_notification_visd_content" msgid="3683314609114134946">"Palieskite, kad sužinotumėte daugiau ir pakeistumėte."</string>
-    <string name="zen_upgrade_notification_title" msgid="8198167698095298717">"Netrukdymo režimas pakeistas"</string>
-    <string name="zen_upgrade_notification_content" msgid="5228458567180124005">"Palieskite, kad patikrintumėte, kas blokuojama."</string>
     <string name="review_notification_settings_title" msgid="5102557424459810820">"Peržiūrėkite pranešimų nustatymus"</string>
     <string name="review_notification_settings_text" msgid="5916244866751849279">"Tryliktos ir naujesnių versijų „Android” jūsų įdiegtoms programoms reikia suteikti leidimą siųsti pranešimus. Palieskite, kad pakeistumėte šį leidimą esamoms programoms."</string>
     <string name="review_notification_settings_remind_me_action" msgid="1081081018678480907">"Priminti vėliau"</string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index b04dd45..973d8e2 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -2130,11 +2130,6 @@
     <string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"Zvaniem un paziņojumiem tiks aktivizēta vibrācija."</string>
     <string name="volume_dialog_ringer_guidance_silent" msgid="1011246774949993783">"Zvanu un paziņojumu signāla skaņa būs izslēgta."</string>
     <string name="notification_channel_system_changes" msgid="2462010596920209678">"Sistēmas izmaiņas"</string>
-    <string name="notification_channel_do_not_disturb" msgid="7832584281883687653">"Netraucēt"</string>
-    <string name="zen_upgrade_notification_visd_title" msgid="2001148984371968620">"Jaunums: režīmā “Netraucēt” paziņojumi tiek paslēpti"</string>
-    <string name="zen_upgrade_notification_visd_content" msgid="3683314609114134946">"Pieskarieties, lai uzzinātu vairāk un veiktu izmaiņas."</string>
-    <string name="zen_upgrade_notification_title" msgid="8198167698095298717">"Režīms “Netraucēt” ir mainīts"</string>
-    <string name="zen_upgrade_notification_content" msgid="5228458567180124005">"Pieskarieties, lai uzzinātu, kas tiek bloķēts."</string>
     <string name="review_notification_settings_title" msgid="5102557424459810820">"Pārskatīt paziņojumu iestatījumus"</string>
     <string name="review_notification_settings_text" msgid="5916244866751849279">"Operētājsistēmā Android 13 un jaunākās versijās jūsu instalētajām lietotnēm ir nepieciešama atļauja sūtīt paziņojumus. Pieskarieties, lai mainītu šo atļauju esošajām lietotnēm."</string>
     <string name="review_notification_settings_remind_me_action" msgid="1081081018678480907">"Atgādināt vēlāk"</string>
diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml
index b0d6351..3943dc3 100644
--- a/core/res/res/values-mk/strings.xml
+++ b/core/res/res/values-mk/strings.xml
@@ -2129,11 +2129,6 @@
     <string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"Повиците и известувањата ќе вибрираат"</string>
     <string name="volume_dialog_ringer_guidance_silent" msgid="1011246774949993783">"Повиците и известувањата нема да имаат звук"</string>
     <string name="notification_channel_system_changes" msgid="2462010596920209678">"Системски промени"</string>
-    <string name="notification_channel_do_not_disturb" msgid="7832584281883687653">"Не вознемирувај"</string>
-    <string name="zen_upgrade_notification_visd_title" msgid="2001148984371968620">"Ново: режимот „Не вознемирувај“ ги крие известувањата"</string>
-    <string name="zen_upgrade_notification_visd_content" msgid="3683314609114134946">"Допрете за да дознаете повеќе и да ги промените поставките."</string>
-    <string name="zen_upgrade_notification_title" msgid="8198167698095298717">"Поставките за „Не вознемирувај“ се изменија"</string>
-    <string name="zen_upgrade_notification_content" msgid="5228458567180124005">"Допрете за да проверите што е блокирано."</string>
     <string name="review_notification_settings_title" msgid="5102557424459810820">"Прегледајте ги поставките за известувања"</string>
     <string name="review_notification_settings_text" msgid="5916244866751849279">"Почнувајќи од Android 13, на апликациите што ги инсталирате им е потребна ваша дозвола за испраќање известувања. Допрете за да ја промените оваа дозвола за постојни апликации."</string>
     <string name="review_notification_settings_remind_me_action" msgid="1081081018678480907">"Потсети ме подоцна"</string>
diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml
index cc545e2..242e967 100644
--- a/core/res/res/values-ml/strings.xml
+++ b/core/res/res/values-ml/strings.xml
@@ -2129,11 +2129,6 @@
     <string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"കോളുകളും അറിയിപ്പുകളും വൈബ്രേറ്റ് ചെയ്യും"</string>
     <string name="volume_dialog_ringer_guidance_silent" msgid="1011246774949993783">"കോളുകളും അറിയിപ്പുകളും മ്യൂട്ട് ചെയ്യപ്പെടും"</string>
     <string name="notification_channel_system_changes" msgid="2462010596920209678">"സിസ്‌റ്റത്തിലെ മാറ്റങ്ങൾ"</string>
-    <string name="notification_channel_do_not_disturb" msgid="7832584281883687653">"ശല്യപ്പെടുത്തരുത്"</string>
-    <string name="zen_upgrade_notification_visd_title" msgid="2001148984371968620">"പുതിയത്: അറിയിപ്പുകളെ \'ശല്യപ്പെടുത്തരുത്\' അദൃശ്യമാക്കുന്നു"</string>
-    <string name="zen_upgrade_notification_visd_content" msgid="3683314609114134946">"കൂടുതലറിയാനും മാറ്റാനും ടാപ്പ് ചെയ്യുക."</string>
-    <string name="zen_upgrade_notification_title" msgid="8198167698095298717">"\'ശല്യപ്പെടുത്തരുത്\' മാറ്റി"</string>
-    <string name="zen_upgrade_notification_content" msgid="5228458567180124005">"എന്തിനെയാണ് ബ്ലോക്ക് ചെയ്‌തതെന്ന് പരിശോധിക്കാൻ ടാപ്പ് ചെയ്യുക."</string>
     <string name="review_notification_settings_title" msgid="5102557424459810820">"അറിയിപ്പ് ക്രമീകരണം അവലോകനം ചെയ്യുക"</string>
     <string name="review_notification_settings_text" msgid="5916244866751849279">"Android 13 മുതൽ, നിങ്ങൾ ഇൻസ്‌റ്റാൾ ചെയ്യുന്ന ആപ്പുകൾക്ക് അറിയിപ്പുകൾ അയയ്‌ക്കാൻ നിങ്ങളുടെ അനുമതി വേണം. നിലവിലുള്ള ആപ്പുകൾക്ക് ഈ അനുമതി മാറ്റാൻ ടാപ്പ് ചെയ്യുക."</string>
     <string name="review_notification_settings_remind_me_action" msgid="1081081018678480907">"പിന്നീട് ഓർമ്മിപ്പിക്കൂ"</string>
diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml
index 87ce94b..c8f2eaa 100644
--- a/core/res/res/values-mn/strings.xml
+++ b/core/res/res/values-mn/strings.xml
@@ -2129,11 +2129,6 @@
     <string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"Дуудлага болон мэдэгдэл чичирнэ"</string>
     <string name="volume_dialog_ringer_guidance_silent" msgid="1011246774949993783">"Дуудлага болон мэдэгдлийн дууг хаана"</string>
     <string name="notification_channel_system_changes" msgid="2462010596920209678">"Системийн өөрчлөлт"</string>
-    <string name="notification_channel_do_not_disturb" msgid="7832584281883687653">"Бүү саад бол"</string>
-    <string name="zen_upgrade_notification_visd_title" msgid="2001148984371968620">"Шинэ: Бүү саад бол горим мэдэгдлийг нууж байна"</string>
-    <string name="zen_upgrade_notification_visd_content" msgid="3683314609114134946">"Илүү ихийг мэдэж, өөрчлөхийн тулд товшино уу."</string>
-    <string name="zen_upgrade_notification_title" msgid="8198167698095298717">"Бүү саад бол горимыг өөрчилсөн"</string>
-    <string name="zen_upgrade_notification_content" msgid="5228458567180124005">"Блоклосон зүйлийг шалгахын тулд товшино уу."</string>
     <string name="review_notification_settings_title" msgid="5102557424459810820">"Мэдэгдлийн тохиргоог шалгах"</string>
     <string name="review_notification_settings_text" msgid="5916244866751849279">"Android 13-аас эхлэн таны суулгасан аппууд мэдэгдэл илгээхийн тулд танаас зөвшөөрөл авах шаардлагатай. Одоо байгаа аппуудын уг зөвшөөрлийг өөрчлөхийн тулд товшино уу."</string>
     <string name="review_notification_settings_remind_me_action" msgid="1081081018678480907">"Надад дараа сануул"</string>
diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml
index 03cabc3..9980d9f 100644
--- a/core/res/res/values-mr/strings.xml
+++ b/core/res/res/values-mr/strings.xml
@@ -2129,11 +2129,6 @@
     <string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"कॉल आणि सूचनांवर व्हायब्रेट होईल"</string>
     <string name="volume_dialog_ringer_guidance_silent" msgid="1011246774949993783">"कॉल आणि सूचना म्यूट केल्या जातील"</string>
     <string name="notification_channel_system_changes" msgid="2462010596920209678">"सिस्टम बदल"</string>
-    <string name="notification_channel_do_not_disturb" msgid="7832584281883687653">"व्यत्यय आणू नका"</string>
-    <string name="zen_upgrade_notification_visd_title" msgid="2001148984371968620">"व्यत्यय आणू नका सूचना लपवत आहे"</string>
-    <string name="zen_upgrade_notification_visd_content" msgid="3683314609114134946">"अधिक जाणून घेण्‍यासाठी आणि बदलण्‍यासाठी टॅप करा."</string>
-    <string name="zen_upgrade_notification_title" msgid="8198167698095298717">"व्यत्यय आणू नका बदलले आहे"</string>
-    <string name="zen_upgrade_notification_content" msgid="5228458567180124005">"काय ब्लॉक केले आहे हे तपासण्यासाठी टॅप करा."</string>
     <string name="review_notification_settings_title" msgid="5102557424459810820">"सूचना सेटिंग्जचे पुनरावलोकन करा"</string>
     <string name="review_notification_settings_text" msgid="5916244866751849279">"Android 13 पासून, तुम्ही त्यामध्ये इंस्टॉल केलेल्या अ‍ॅप्सना सूचना पाठवण्यासाठी तुमच्या परवानगीची आवश्यकता आहे. सध्याच्या अ‍ॅप्ससाठी ही परवानगी बदलण्याकरिता टॅप करा."</string>
     <string name="review_notification_settings_remind_me_action" msgid="1081081018678480907">"मला आठवण करून द्या"</string>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index 57f1472..e811635 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -2129,11 +2129,6 @@
     <string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"Panggilan dan pemberitahuan akan bergetar"</string>
     <string name="volume_dialog_ringer_guidance_silent" msgid="1011246774949993783">"Panggilan dan pemberitahuan akan diredamkan"</string>
     <string name="notification_channel_system_changes" msgid="2462010596920209678">"Perubahan sistem"</string>
-    <string name="notification_channel_do_not_disturb" msgid="7832584281883687653">"Jangan Ganggu"</string>
-    <string name="zen_upgrade_notification_visd_title" msgid="2001148984371968620">"Baharu: Jangan Ganggu menyembunyikan pemberitahuan"</string>
-    <string name="zen_upgrade_notification_visd_content" msgid="3683314609114134946">"Ketik untuk mengetahui lebih lanjut dan menukar tetapan."</string>
-    <string name="zen_upgrade_notification_title" msgid="8198167698095298717">"Jangan Ganggu telah berubah"</string>
-    <string name="zen_upgrade_notification_content" msgid="5228458567180124005">"Ketik untuk menyemak item yang disekat."</string>
     <string name="review_notification_settings_title" msgid="5102557424459810820">"Semak tetapan pemberitahuan"</string>
     <string name="review_notification_settings_text" msgid="5916244866751849279">"Bermula dengan Android 13, apl yang anda pasang memerlukan kebenaran anda untuk menghantar pemberitahuan. Ketik untuk menukar kebenaran ini bagi apl sedia ada."</string>
     <string name="review_notification_settings_remind_me_action" msgid="1081081018678480907">"Ingatkan saya nanti"</string>
diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml
index f568d711..7088a15 100644
--- a/core/res/res/values-my/strings.xml
+++ b/core/res/res/values-my/strings.xml
@@ -322,7 +322,7 @@
     <string name="permgrouplab_location" msgid="1858277002233964394">"တည်နေရာ"</string>
     <string name="permgroupdesc_location" msgid="1995955142118450685">"ဤစက်ပစ္စည်း၏ တည်နေရာကို ရယူရန်"</string>
     <string name="permgrouplab_calendar" msgid="6426860926123033230">"ပြက္ခဒိန်"</string>
-    <string name="permgroupdesc_calendar" msgid="6762751063361489379">"သင့်ပြက္ခဒိန်အား ဝင်ရောက်သုံးရန်"</string>
+    <string name="permgroupdesc_calendar" msgid="6762751063361489379">"သင့်ပြက္ခဒိန်အား ဝင်သုံးရန်"</string>
     <string name="permgrouplab_sms" msgid="795737735126084874">"SMS စာတိုစနစ်"</string>
     <string name="permgroupdesc_sms" msgid="5726462398070064542">"SMS စာများကို ပို့ကာ ကြည့်မည်"</string>
     <string name="permgrouplab_storage" msgid="17339216290379241">"ဖိုင်များ"</string>
@@ -2129,11 +2129,6 @@
     <string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"ခေါ်ဆိုမှုများနှင့် အကြောင်းကြားချက်များ တုန်ခါပါမည်"</string>
     <string name="volume_dialog_ringer_guidance_silent" msgid="1011246774949993783">"ခေါ်ဆိုမှုများနှင့် အကြောင်းကြားချက်များကို အသံပိတ်ထားပါမည်"</string>
     <string name="notification_channel_system_changes" msgid="2462010596920209678">"စနစ် အပြောင်းအလဲများ"</string>
-    <string name="notification_channel_do_not_disturb" msgid="7832584281883687653">"မနှောင့်ယှက်ရ"</string>
-    <string name="zen_upgrade_notification_visd_title" msgid="2001148984371968620">"အသစ်− \'မနှောင့်ယှက်ရ\' က အကြောင်းကြားချက်များကို ဖျောက်ထားသည်"</string>
-    <string name="zen_upgrade_notification_visd_content" msgid="3683314609114134946">"ပိုမိုလေ့လာရန်နှင့် ပြောင်းလဲရန် တို့ပါ။"</string>
-    <string name="zen_upgrade_notification_title" msgid="8198167698095298717">"\'မနှောင့်ယှက်ရ\' ပြောင်းလဲသွားပါပြီ"</string>
-    <string name="zen_upgrade_notification_content" msgid="5228458567180124005">"ပိတ်ထားသည့်အရာများကို ကြည့်ရန် တို့ပါ။"</string>
     <string name="review_notification_settings_title" msgid="5102557424459810820">"အကြောင်းကြားချက် ဆက်တင်များ စိစစ်ရန်"</string>
     <string name="review_notification_settings_text" msgid="5916244866751849279">"Android 13 မှစ၍ ထည့်သွင်းသော အက်ပ်များသည် အကြောင်းကြားချက်များပို့ရန် သင်၏ခွင့်ပြုချက် လိုအပ်ပါမည်။ ရှိပြီးသားအက်ပ်များအတွက် ဤခွင့်ပြုချက်ကိုပြောင်းရန် တို့ပါ။"</string>
     <string name="review_notification_settings_remind_me_action" msgid="1081081018678480907">"နောက်မှ သတိပေးပါ"</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index 6d24bdf..f39a4f8 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -2129,11 +2129,6 @@
     <string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"Anrop og varsler vibrerer"</string>
     <string name="volume_dialog_ringer_guidance_silent" msgid="1011246774949993783">"Anrop og varsler er lydløse"</string>
     <string name="notification_channel_system_changes" msgid="2462010596920209678">"Systemendringer"</string>
-    <string name="notification_channel_do_not_disturb" msgid="7832584281883687653">"Ikke forstyrr"</string>
-    <string name="zen_upgrade_notification_visd_title" msgid="2001148984371968620">"Nytt: «Ikke forstyrr» skjuler varsler"</string>
-    <string name="zen_upgrade_notification_visd_content" msgid="3683314609114134946">"Trykk for å finne ut mer og endre."</string>
-    <string name="zen_upgrade_notification_title" msgid="8198167698095298717">"Ikke forstyrr er endret"</string>
-    <string name="zen_upgrade_notification_content" msgid="5228458567180124005">"Trykk for å sjekke hva som er blokkert."</string>
     <string name="review_notification_settings_title" msgid="5102557424459810820">"Gjennomgå varslingsinnstillingene"</string>
     <string name="review_notification_settings_text" msgid="5916244866751849279">"Fra og med Android 13 må apper du installerer, få tillatelse til å sende varsler. Trykk for å endre denne tillatelsen for eksisterende apper."</string>
     <string name="review_notification_settings_remind_me_action" msgid="1081081018678480907">"Påminn meg senere"</string>
diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml
index 914c04c..82052b5 100644
--- a/core/res/res/values-ne/strings.xml
+++ b/core/res/res/values-ne/strings.xml
@@ -2129,11 +2129,6 @@
     <string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"कल तथा सूचनाहरू आउँदा कम्पन हुने छ"</string>
     <string name="volume_dialog_ringer_guidance_silent" msgid="1011246774949993783">"कल तथा सूचनाहरूलाई म्युट गरिने छ"</string>
     <string name="notification_channel_system_changes" msgid="2462010596920209678">"प्रणालीसम्बन्धी परिवर्तनहरू"</string>
-    <string name="notification_channel_do_not_disturb" msgid="7832584281883687653">"बाधा नपुऱ्याउनुहोस्"</string>
-    <string name="zen_upgrade_notification_visd_title" msgid="2001148984371968620">"नयाँ: बाधा नपुर्‍याउनुहोस् नामक मोडले सूचनाहरू लुकाइरहेको छ"</string>
-    <string name="zen_upgrade_notification_visd_content" msgid="3683314609114134946">"थप जान्न र परिवर्तन गर्न ट्याप गर्नुहोस्।"</string>
-    <string name="zen_upgrade_notification_title" msgid="8198167698095298717">"बाधा नपुर्‍याउनुहोस् मोड परिवर्तन भएको छ"</string>
-    <string name="zen_upgrade_notification_content" msgid="5228458567180124005">"रोक लगाइएका कुराहरू जाँच गर्न ट्याप गर्नुहोस्‌।"</string>
     <string name="review_notification_settings_title" msgid="5102557424459810820">"सूचनाका सेटिङको समीक्षा गर्नुहोस्"</string>
     <string name="review_notification_settings_text" msgid="5916244866751849279">"Android १३ मा तपाईंले अनुमति दिनुभएका खण्डमा मात्र तपाईंले इन्स्टल गर्नुभएका एपले सूचना पठाउन सक्छन्। यसअघि इन्स्टल गरिसकिएका एपका हकमा यो अनुमति परिवर्तन गर्न ट्याप गर्नुहोस्।"</string>
     <string name="review_notification_settings_remind_me_action" msgid="1081081018678480907">"मलाई पछि स्मरण गराइयोस्"</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index d2ec4ba..f591754 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -2129,11 +2129,6 @@
     <string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"Trillen bij gesprekken en meldingen"</string>
     <string name="volume_dialog_ringer_guidance_silent" msgid="1011246774949993783">"Telefoon- en meldingsgeluid wordt uitgezet"</string>
     <string name="notification_channel_system_changes" msgid="2462010596920209678">"Systeemwijzigingen"</string>
-    <string name="notification_channel_do_not_disturb" msgid="7832584281883687653">"Niet storen"</string>
-    <string name="zen_upgrade_notification_visd_title" msgid="2001148984371968620">"Nieuw: \'Niet storen\' verbergt meldingen"</string>
-    <string name="zen_upgrade_notification_visd_content" msgid="3683314609114134946">"Tik voor meer informatie en om te wijzigen."</string>
-    <string name="zen_upgrade_notification_title" msgid="8198167698095298717">"\'Niet storen\' is gewijzigd"</string>
-    <string name="zen_upgrade_notification_content" msgid="5228458567180124005">"Tik om te controleren wat er is geblokkeerd."</string>
     <string name="review_notification_settings_title" msgid="5102557424459810820">"Instellingen voor meldingen bekijken"</string>
     <string name="review_notification_settings_text" msgid="5916244866751849279">"Vanaf Android 13 hebben de apps die je installeert je toestemming nodig om meldingen te sturen. Tik om deze toestemming voor bestaande apps te wijzigen."</string>
     <string name="review_notification_settings_remind_me_action" msgid="1081081018678480907">"Later herinneren"</string>
diff --git a/core/res/res/values-or/strings.xml b/core/res/res/values-or/strings.xml
index 85a6aec..1a952a3 100644
--- a/core/res/res/values-or/strings.xml
+++ b/core/res/res/values-or/strings.xml
@@ -2129,11 +2129,6 @@
     <string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"କଲ୍ ଓ ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକ ଭାଇବ୍ରେଟ୍ ହେବ"</string>
     <string name="volume_dialog_ringer_guidance_silent" msgid="1011246774949993783">"କଲ୍ ଓ ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକୁ ନିଃଶବ୍ଦ କରିଦିଆଯିବ"</string>
     <string name="notification_channel_system_changes" msgid="2462010596920209678">"ସିଷ୍ଟମ୍‌ରେ ପରିବର୍ତ୍ତନ"</string>
-    <string name="notification_channel_do_not_disturb" msgid="7832584281883687653">"ବିରକ୍ତ କରନ୍ତୁ ନାହିଁ"</string>
-    <string name="zen_upgrade_notification_visd_title" msgid="2001148984371968620">"ନୂଆ: \"ବିରକ୍ତ କରନ୍ତୁ ନାହିଁ\" ମୋଡ୍‌ ଅନ୍‌ ଥିବା ଯୋଗୁଁ ବିଜ୍ଞପ୍ତି ଲୁଚାଇ ଦିଆଯାଉଛି"</string>
-    <string name="zen_upgrade_notification_visd_content" msgid="3683314609114134946">"ଅଧିକ ଜାଣିବାକୁ ଟ୍ୟାପ୍‌ କରନ୍ତୁ ଏବଂ ବଦଳାନ୍ତୁ।"</string>
-    <string name="zen_upgrade_notification_title" msgid="8198167698095298717">"’ବିରକ୍ତ କରନ୍ତୁ ନାହିଁ’ ବଦଳିଯାଇଛି"</string>
-    <string name="zen_upgrade_notification_content" msgid="5228458567180124005">"କ’ଣ ଅବରୋଧ ହୋଇଛି ଯାଞ୍ଚ କରିବା ପାଇଁ ଟାପ୍ କରନ୍ତୁ।"</string>
     <string name="review_notification_settings_title" msgid="5102557424459810820">"ବିଜ୍ଞପ୍ତି ସେଟିଂସକୁ ସମୀକ୍ଷା କରନ୍ତୁ"</string>
     <string name="review_notification_settings_text" msgid="5916244866751849279">"Android 13ଠାରୁ, ଆପଣ ଇନଷ୍ଟଲ କରୁଥିବା ଆପ୍ସ ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକୁ ପଠାଇବା ପାଇଁ ଆପଣଙ୍କ ଅନୁମତି ଆବଶ୍ୟକ କରେ। ପୂର୍ବରୁ ଥିବା ଆପ୍ସ ପାଇଁ ଏହି ଅନୁମତିକୁ ପରିବର୍ତ୍ତନ କରିବାକୁ ଟାପ କରନ୍ତୁ।"</string>
     <string name="review_notification_settings_remind_me_action" msgid="1081081018678480907">"ମୋତେ ପରେ ରିମାଇଣ୍ଡ କର"</string>
diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml
index 51d71ff..6953509 100644
--- a/core/res/res/values-pa/strings.xml
+++ b/core/res/res/values-pa/strings.xml
@@ -2129,11 +2129,6 @@
     <string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"ਕਾਲਾਂ ਅਤੇ ਸੂਚਨਾਵਾਂ ਦੀ ਥਰਥਰਾਹਟ ਹੋਵੇਗੀ"</string>
     <string name="volume_dialog_ringer_guidance_silent" msgid="1011246774949993783">"ਕਾਲਾਂ ਅਤੇ ਸੂਚਨਾਵਾਂ ਨੂੰ ਮਿਊਟ ਕੀਤਾ ਜਾਵੇਗਾ"</string>
     <string name="notification_channel_system_changes" msgid="2462010596920209678">"ਸਿਸਟਮ ਬਦਲਾਅ"</string>
-    <string name="notification_channel_do_not_disturb" msgid="7832584281883687653">"ਪਰੇਸ਼ਾਨ ਨਾ ਕਰੋ"</string>
-    <string name="zen_upgrade_notification_visd_title" msgid="2001148984371968620">"ਨਵਾਂ: \'ਪਰੇਸ਼ਾਨ ਨਾ ਕਰੋ\' ਮੋਡ ਸੂਚਨਾਵਾਂ ਨੂੰ ਲੁਕਾ ਰਿਹਾ ਹੈ"</string>
-    <string name="zen_upgrade_notification_visd_content" msgid="3683314609114134946">"ਹੋਰ ਜਾਣਨ ਲਈ ਅਤੇ ਬਦਲਾਅ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ।"</string>
-    <string name="zen_upgrade_notification_title" msgid="8198167698095298717">"\'ਪਰੇਸ਼ਾਨ ਨਾ ਕਰੋ\' ਵਿਕਲਪ ਬਦਲ ਗਿਆ ਹੈ"</string>
-    <string name="zen_upgrade_notification_content" msgid="5228458567180124005">"ਟੈਪ ਕਰਕੇ ਦੋਖੋ ਕਿ ਕਿਹੜੀਆਂ ਚੀਜ਼ਾਂ ਬਲਾਕ ਕੀਤੀਆਂ ਗਈਆਂ ਹਨ।"</string>
     <string name="review_notification_settings_title" msgid="5102557424459810820">"ਸੂਚਨਾ ਸੈਟਿੰਗਾਂ ਦੀ ਸਮੀਖਿਆ ਕਰੋ"</string>
     <string name="review_notification_settings_text" msgid="5916244866751849279">"Android 13 ਜਾਂ ਇਸ ਤੋਂ ਬਾਅਦ ਵਾਲੇ ਵਰਜਨਾਂ ਵਿੱਚ, ਤੁਹਾਡੇ ਵੱਲੋਂ ਸਥਾਪਤ ਕੀਤੀਆਂ ਜਾਣ ਵਾਲੀਆਂ ਐਪਾਂ ਨੂੰ ਸੂਚਨਾਵਾਂ ਭੇਜਣ ਲਈ ਤੁਹਾਡੀ ਇਜਾਜ਼ਤ ਦੀ ਲੋੜ ਹੁੰਦੀ ਹੈ। ਮੌਜੂਦਾ ਐਪਾਂ ਲਈ ਇਸ ਇਜਾਜ਼ਤ ਨੂੰ ਬਦਲਣ ਵਾਸਤੇ ਟੈਪ ਕਰੋ।"</string>
     <string name="review_notification_settings_remind_me_action" msgid="1081081018678480907">"ਬਾਅਦ ਵਿੱਚ ਯਾਦ ਕਰਵਾਓ"</string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index 49c30c7..065e9ba 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -2131,11 +2131,6 @@
     <string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"Wibracje przy połączeniach i powiadomieniach"</string>
     <string name="volume_dialog_ringer_guidance_silent" msgid="1011246774949993783">"Wyciszenie połączeń i powiadomień"</string>
     <string name="notification_channel_system_changes" msgid="2462010596920209678">"Zmiany w systemie"</string>
-    <string name="notification_channel_do_not_disturb" msgid="7832584281883687653">"Nie przeszkadzać"</string>
-    <string name="zen_upgrade_notification_visd_title" msgid="2001148984371968620">"Nowość: w trybie Nie przeszkadzać powiadomienia są ukrywane"</string>
-    <string name="zen_upgrade_notification_visd_content" msgid="3683314609114134946">"Kliknij, by dowiedzieć się więcej i zmienić ustawienia."</string>
-    <string name="zen_upgrade_notification_title" msgid="8198167698095298717">"Zmiany w trybie Nie przeszkadzać"</string>
-    <string name="zen_upgrade_notification_content" msgid="5228458567180124005">"Kliknij, by sprawdzić, co jest zablokowane."</string>
     <string name="review_notification_settings_title" msgid="5102557424459810820">"Sprawdź ustawienia powiadomień"</string>
     <string name="review_notification_settings_text" msgid="5916244866751849279">"W Androidzie 13 i nowszych zainstalowane aplikacje będą potrzebowały zezwolenia na wysyłanie powiadomień. Kliknij, aby zmienić uprawnienia dla istniejących aplikacji."</string>
     <string name="review_notification_settings_remind_me_action" msgid="1081081018678480907">"Przypomnij później"</string>
diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index 99ef604..c972e7a 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -2130,11 +2130,6 @@
     <string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"Chamadas e notificações farão o dispositivo vibrar"</string>
     <string name="volume_dialog_ringer_guidance_silent" msgid="1011246774949993783">"Chamadas e notificações ficarão silenciadas"</string>
     <string name="notification_channel_system_changes" msgid="2462010596920209678">"Alterações do sistema"</string>
-    <string name="notification_channel_do_not_disturb" msgid="7832584281883687653">"Não perturbe"</string>
-    <string name="zen_upgrade_notification_visd_title" msgid="2001148984371968620">"Novo: o modo Não perturbe está ocultando as notificações"</string>
-    <string name="zen_upgrade_notification_visd_content" msgid="3683314609114134946">"Toque para saber mais e fazer alterações."</string>
-    <string name="zen_upgrade_notification_title" msgid="8198167698095298717">"O modo \"Não perturbe\" foi alterado"</string>
-    <string name="zen_upgrade_notification_content" msgid="5228458567180124005">"Toque para verificar o que está bloqueado."</string>
     <string name="review_notification_settings_title" msgid="5102557424459810820">"Revise as configurações de notificação"</string>
     <string name="review_notification_settings_text" msgid="5916244866751849279">"No Android 13 ou em versões mais recentes, os apps que você instala precisam de permissão para enviar notificações. Toque para mudar essa permissão para os apps já instalados."</string>
     <string name="review_notification_settings_remind_me_action" msgid="1081081018678480907">"Lembrar mais tarde"</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 12245b9..8dddd95 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -2130,11 +2130,6 @@
     <string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"As chamadas e as notificações vibram."</string>
     <string name="volume_dialog_ringer_guidance_silent" msgid="1011246774949993783">"É desativado o som das chamadas e das notificações."</string>
     <string name="notification_channel_system_changes" msgid="2462010596920209678">"Alterações ao sistema"</string>
-    <string name="notification_channel_do_not_disturb" msgid="7832584281883687653">"Não incomodar"</string>
-    <string name="zen_upgrade_notification_visd_title" msgid="2001148984371968620">"Novo: o modo Não incomodar está a ocultar as notificações"</string>
-    <string name="zen_upgrade_notification_visd_content" msgid="3683314609114134946">"Toque para saber mais e alterar."</string>
-    <string name="zen_upgrade_notification_title" msgid="8198167698095298717">"O modo Não incomodar foi alterado"</string>
-    <string name="zen_upgrade_notification_content" msgid="5228458567180124005">"Toque para verificar o que está bloqueado."</string>
     <string name="review_notification_settings_title" msgid="5102557424459810820">"Analise as definições de notificação"</string>
     <string name="review_notification_settings_text" msgid="5916244866751849279">"A partir do Android 13, as apps que instalar precisam da sua autorização para enviar notificações. Toque para alterar esta autorização para as apps existentes."</string>
     <string name="review_notification_settings_remind_me_action" msgid="1081081018678480907">"Lembrar mais tarde"</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index 99ef604..c972e7a 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -2130,11 +2130,6 @@
     <string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"Chamadas e notificações farão o dispositivo vibrar"</string>
     <string name="volume_dialog_ringer_guidance_silent" msgid="1011246774949993783">"Chamadas e notificações ficarão silenciadas"</string>
     <string name="notification_channel_system_changes" msgid="2462010596920209678">"Alterações do sistema"</string>
-    <string name="notification_channel_do_not_disturb" msgid="7832584281883687653">"Não perturbe"</string>
-    <string name="zen_upgrade_notification_visd_title" msgid="2001148984371968620">"Novo: o modo Não perturbe está ocultando as notificações"</string>
-    <string name="zen_upgrade_notification_visd_content" msgid="3683314609114134946">"Toque para saber mais e fazer alterações."</string>
-    <string name="zen_upgrade_notification_title" msgid="8198167698095298717">"O modo \"Não perturbe\" foi alterado"</string>
-    <string name="zen_upgrade_notification_content" msgid="5228458567180124005">"Toque para verificar o que está bloqueado."</string>
     <string name="review_notification_settings_title" msgid="5102557424459810820">"Revise as configurações de notificação"</string>
     <string name="review_notification_settings_text" msgid="5916244866751849279">"No Android 13 ou em versões mais recentes, os apps que você instala precisam de permissão para enviar notificações. Toque para mudar essa permissão para os apps já instalados."</string>
     <string name="review_notification_settings_remind_me_action" msgid="1081081018678480907">"Lembrar mais tarde"</string>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 85f8592..014a115 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -2130,11 +2130,6 @@
     <string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"Apelurile și notificările vor vibra"</string>
     <string name="volume_dialog_ringer_guidance_silent" msgid="1011246774949993783">"Apelurile și notificările vor avea sunetul dezactivat"</string>
     <string name="notification_channel_system_changes" msgid="2462010596920209678">"Modificări de sistem"</string>
-    <string name="notification_channel_do_not_disturb" msgid="7832584281883687653">"Nu deranja"</string>
-    <string name="zen_upgrade_notification_visd_title" msgid="2001148984371968620">"Funcția nouă Nu deranja ascunde notificările"</string>
-    <string name="zen_upgrade_notification_visd_content" msgid="3683314609114134946">"Atinge ca să afli mai multe și să modifici"</string>
-    <string name="zen_upgrade_notification_title" msgid="8198167698095298717">"Funcția Nu deranja s-a schimbat"</string>
-    <string name="zen_upgrade_notification_content" msgid="5228458567180124005">"Atinge pentru a verifica ce este blocat."</string>
     <string name="review_notification_settings_title" msgid="5102557424459810820">"Verifică setările pentru notificări"</string>
     <string name="review_notification_settings_text" msgid="5916244866751849279">"Începând cu Android 13, aplicațiile pe care le instalezi necesită permisiunea de a trimite notificări. Atinge ca să modifici permisiunea pentru aplicațiile existente."</string>
     <string name="review_notification_settings_remind_me_action" msgid="1081081018678480907">"Mai târziu"</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 6559764..1e819d6 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -2131,11 +2131,6 @@
     <string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"Для звонков и уведомлений включен вибросигнал."</string>
     <string name="volume_dialog_ringer_guidance_silent" msgid="1011246774949993783">"Для звонков и уведомлений отключен звук."</string>
     <string name="notification_channel_system_changes" msgid="2462010596920209678">"Системные изменения"</string>
-    <string name="notification_channel_do_not_disturb" msgid="7832584281883687653">"Не беспокоить"</string>
-    <string name="zen_upgrade_notification_visd_title" msgid="2001148984371968620">"Теперь в режиме \"Не беспокоить\" уведомления не приходят"</string>
-    <string name="zen_upgrade_notification_visd_content" msgid="3683314609114134946">"Нажмите, чтобы узнать больше и изменить настройки."</string>
-    <string name="zen_upgrade_notification_title" msgid="8198167698095298717">"Настройки режима \"Не беспокоить\" изменены"</string>
-    <string name="zen_upgrade_notification_content" msgid="5228458567180124005">"Нажмите, чтобы проверить настройки."</string>
     <string name="review_notification_settings_title" msgid="5102557424459810820">"Проверьте настройки уведомлений"</string>
     <string name="review_notification_settings_text" msgid="5916244866751849279">"В Android 13 и более поздних версий приложения могут отправлять вам уведомления только в том случае, если вы предоставили им такое разрешение. Нажмите, чтобы настроить разрешения для установленных приложений."</string>
     <string name="review_notification_settings_remind_me_action" msgid="1081081018678480907">"Напомнить позже"</string>
diff --git a/core/res/res/values-si/strings.xml b/core/res/res/values-si/strings.xml
index be41512..8c80803 100644
--- a/core/res/res/values-si/strings.xml
+++ b/core/res/res/values-si/strings.xml
@@ -2129,11 +2129,6 @@
     <string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"ඇමතුම් සහ දැනුම්දීම් කම්පනය වනු ඇත"</string>
     <string name="volume_dialog_ringer_guidance_silent" msgid="1011246774949993783">"ඇමතුම් සහ දැනුම්දීම් නිහඬ වනු ඇත"</string>
     <string name="notification_channel_system_changes" msgid="2462010596920209678">"පද්ධති වෙනස් කිරීම්"</string>
-    <string name="notification_channel_do_not_disturb" msgid="7832584281883687653">"බාධා නොකරන්න"</string>
-    <string name="zen_upgrade_notification_visd_title" msgid="2001148984371968620">"නව: බාධා නොකරන්න දැනුම්දීම් සඟවමින්"</string>
-    <string name="zen_upgrade_notification_visd_content" msgid="3683314609114134946">"තව දැන ගැනීමට සහ වෙනස් කිරීමට තට්ටු කරන්න."</string>
-    <string name="zen_upgrade_notification_title" msgid="8198167698095298717">"බාධා නොකරන්න වෙනස් කර ඇත"</string>
-    <string name="zen_upgrade_notification_content" msgid="5228458567180124005">"අවහිර කර ඇති දේ පරීක්ෂා කිරීමට තට්ටු කරන්න."</string>
     <string name="review_notification_settings_title" msgid="5102557424459810820">"දැනුම්දීම් සැකසීම් සමාලෝචනය කරන්න"</string>
     <string name="review_notification_settings_text" msgid="5916244866751849279">"Android 13 හි සිට ආරම්භ වෙමින්, ඔබ ස්ථාපනය කරන යෙදුම්වලට දැනුම්දීම් යැවීමට ඔබගේ අවසරය අවශ්‍ය වේ. තිබෙන යෙදුම් සඳහා මෙම අවසරය වෙනස් කිරීමට තට්ටු කරන්න."</string>
     <string name="review_notification_settings_remind_me_action" msgid="1081081018678480907">"මට පසුව මතක් කරන්න"</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index 61d3229..cb3cd61 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -2131,11 +2131,6 @@
     <string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"Hovory a upozornenia budú vibrovať"</string>
     <string name="volume_dialog_ringer_guidance_silent" msgid="1011246774949993783">"Hovory a upozornenia budú stlmené"</string>
     <string name="notification_channel_system_changes" msgid="2462010596920209678">"Zmeny systému"</string>
-    <string name="notification_channel_do_not_disturb" msgid="7832584281883687653">"Režim bez vyrušení"</string>
-    <string name="zen_upgrade_notification_visd_title" msgid="2001148984371968620">"Novinka: režim bez vyrušení skrýva upozornenia"</string>
-    <string name="zen_upgrade_notification_visd_content" msgid="3683314609114134946">"Klepnutím získate ďalšie informácie a budete môcť vykonať zmeny."</string>
-    <string name="zen_upgrade_notification_title" msgid="8198167698095298717">"Režim bez vyrušení sa zmenil"</string>
-    <string name="zen_upgrade_notification_content" msgid="5228458567180124005">"Klepnutím skontrolujete, čo je blokované."</string>
     <string name="review_notification_settings_title" msgid="5102557424459810820">"Kontrola nastavení upozornení"</string>
     <string name="review_notification_settings_text" msgid="5916244866751849279">"V Androide verzie 13 a novších vyžadujú nainštalované aplikácie povolenie, aby mohli odosielať upozornenia. Klepnutím môžete zmeniť toto povolenie pre existujúce aplikácie."</string>
     <string name="review_notification_settings_remind_me_action" msgid="1081081018678480907">"Pripomenúť neskôr"</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index ed8cf50..5378875 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -2131,11 +2131,6 @@
     <string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"Vibriranje bo vklopljeno za klice in obvestila"</string>
     <string name="volume_dialog_ringer_guidance_silent" msgid="1011246774949993783">"Zvonjenje bo izklopljeno za klice in obvestila"</string>
     <string name="notification_channel_system_changes" msgid="2462010596920209678">"Sistemske spremembe"</string>
-    <string name="notification_channel_do_not_disturb" msgid="7832584281883687653">"Ne moti"</string>
-    <string name="zen_upgrade_notification_visd_title" msgid="2001148984371968620">"Novi način »ne moti« skriva obvestila"</string>
-    <string name="zen_upgrade_notification_visd_content" msgid="3683314609114134946">"Dotaknite se, če želite izvedeti več in spremeniti."</string>
-    <string name="zen_upgrade_notification_title" msgid="8198167698095298717">"Način »ne moti« je spremenjen"</string>
-    <string name="zen_upgrade_notification_content" msgid="5228458567180124005">"Dotaknite se, da preverite, kaj je blokirano."</string>
     <string name="review_notification_settings_title" msgid="5102557424459810820">"Preglejte nastavitve obvestil"</string>
     <string name="review_notification_settings_text" msgid="5916244866751849279">"V Androidu 13 in novejših različicah bodo aplikacije, ki jih namestite, za pošiljanje obvestil potrebovale vaše dovoljenje. Dotaknite se, če želite spremeniti to dovoljenje za obstoječe aplikacije."</string>
     <string name="review_notification_settings_remind_me_action" msgid="1081081018678480907">"Opomni me pozneje"</string>
diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml
index e24e310..4c8dfbc 100644
--- a/core/res/res/values-sq/strings.xml
+++ b/core/res/res/values-sq/strings.xml
@@ -2129,11 +2129,6 @@
     <string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"Do të lëshojë dridhje për telefonatat dhe njoftimet"</string>
     <string name="volume_dialog_ringer_guidance_silent" msgid="1011246774949993783">"Do të hiqet zëri për telefonatat dhe njoftimet"</string>
     <string name="notification_channel_system_changes" msgid="2462010596920209678">"Ndryshimet e sistemit"</string>
-    <string name="notification_channel_do_not_disturb" msgid="7832584281883687653">"Mos shqetëso"</string>
-    <string name="zen_upgrade_notification_visd_title" msgid="2001148984371968620">"E re: Modaliteti \"Mos shqetëso\" po fsheh njoftimet"</string>
-    <string name="zen_upgrade_notification_visd_content" msgid="3683314609114134946">"Trokit për të mësuar më shumë dhe për të ndryshuar."</string>
-    <string name="zen_upgrade_notification_title" msgid="8198167698095298717">"\"Mos shqetëso\" ka ndryshuar"</string>
-    <string name="zen_upgrade_notification_content" msgid="5228458567180124005">"Trokit për të shënuar atë që është bllokuar"</string>
     <string name="review_notification_settings_title" msgid="5102557424459810820">"Rishiko cilësimet e njoftimeve"</string>
     <string name="review_notification_settings_text" msgid="5916244866751849279">"Nga Android 13, aplikacionet që instalon kanë nevojë për lejen tënde për të dërguar njoftime. Trokit për ta ndryshuar këtë leje për aplikacionet ekzistuese."</string>
     <string name="review_notification_settings_remind_me_action" msgid="1081081018678480907">"Më kujto më vonë"</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index 915486e..c9f44db 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -2130,11 +2130,6 @@
     <string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"Вибрација за позиве и обавештења је укључена"</string>
     <string name="volume_dialog_ringer_guidance_silent" msgid="1011246774949993783">"Мелодија звона за позиве и обавештење је искључена"</string>
     <string name="notification_channel_system_changes" msgid="2462010596920209678">"Системске промене"</string>
-    <string name="notification_channel_do_not_disturb" msgid="7832584281883687653">"Не узнемиравај"</string>
-    <string name="zen_upgrade_notification_visd_title" msgid="2001148984371968620">"Ново: Режим Не узнемиравај крије обавештења"</string>
-    <string name="zen_upgrade_notification_visd_content" msgid="3683314609114134946">"Додирните да бисте сазнали више и променили подешавање."</string>
-    <string name="zen_upgrade_notification_title" msgid="8198167698095298717">"Режим Не узнемиравај је промењен"</string>
-    <string name="zen_upgrade_notification_content" msgid="5228458567180124005">"Додирните да бисте проверили шта је блокирано."</string>
     <string name="review_notification_settings_title" msgid="5102557424459810820">"Прегледајте подешавања обавештења"</string>
     <string name="review_notification_settings_text" msgid="5916244866751849279">"Од Android-а 13 апликације које инсталирате морају да имају дозволу за слање обавештења. Додирните да бисте променили ову дозволу за постојеће апликације."</string>
     <string name="review_notification_settings_remind_me_action" msgid="1081081018678480907">"Подсети ме касније"</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index 0c5b6ac..574b4e8 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -202,7 +202,7 @@
     <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"För många försök med lösenord"</string>
     <string name="device_ownership_relinquished" msgid="4080886992183195724">"Administratören tillåter inte längre privat bruk av enheten"</string>
     <string name="private_space_deleted_by_admin" msgid="1484365588862066939">"Privat område har tagits bort"</string>
-    <string name="private_space_deleted_by_admin_details" msgid="7007781735201818689">"Din organisation tillåter inte privata områden på den här hanterade enheten."</string>
+    <string name="private_space_deleted_by_admin_details" msgid="7007781735201818689">"Din organisation tillåter inte privata utrymmen på den här hanterade enheten."</string>
     <string name="network_logging_notification_title" msgid="554983187553845004">"Enheten hanteras"</string>
     <string name="network_logging_notification_text" msgid="1327373071132562512">"Organisationen hanterar den här enheten och kan övervaka nätverkstrafiken. Tryck om du vill veta mer."</string>
     <string name="location_changed_notification_title" msgid="3620158742816699316">"Appar har åtkomst till din plats"</string>
@@ -2009,8 +2009,8 @@
     <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"Nödsituation"</string>
     <string name="set_up_screen_lock_title" msgid="8346083801616474030">"Ställ in ett skärmlås"</string>
     <string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Ställ in skärmlås"</string>
-    <string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Ställ in ett skärmlås för enheten om du vill använda ditt privata område."</string>
-    <string name="private_space_set_up_screen_lock_for_reset" msgid="7817091386408432097">"Ange ett skärmlås för enheten om du vill radera privat område"</string>
+    <string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Ställ in ett skärmlås för enheten om du vill använda ditt privata utrymme."</string>
+    <string name="private_space_set_up_screen_lock_for_reset" msgid="7817091386408432097">"Ange ett skärmlås för enheten om du vill radera privat utrymme"</string>
     <string name="app_blocked_title" msgid="7353262160455028160">"Appen är inte tillgänglig"</string>
     <string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> är inte tillgängligt just nu."</string>
     <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> är inte tillgänglig"</string>
@@ -2129,11 +2129,6 @@
     <string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"Vibrerar vid samtal och aviseringar"</string>
     <string name="volume_dialog_ringer_guidance_silent" msgid="1011246774949993783">"Ljudet stängs av för samtal och aviseringar"</string>
     <string name="notification_channel_system_changes" msgid="2462010596920209678">"Systemändringar"</string>
-    <string name="notification_channel_do_not_disturb" msgid="7832584281883687653">"Stör ej"</string>
-    <string name="zen_upgrade_notification_visd_title" msgid="2001148984371968620">"Nytt: Aviseringar döljs av Stör ej"</string>
-    <string name="zen_upgrade_notification_visd_content" msgid="3683314609114134946">"Tryck här om du vill läsa mer och ändra inställningarna."</string>
-    <string name="zen_upgrade_notification_title" msgid="8198167698095298717">"Stör ej har ändrats"</string>
-    <string name="zen_upgrade_notification_content" msgid="5228458567180124005">"Tryck om du vill se vad som blockeras."</string>
     <string name="review_notification_settings_title" msgid="5102557424459810820">"Granska aviseringsinställningarna"</string>
     <string name="review_notification_settings_text" msgid="5916244866751849279">"I Android 13 behöver appar som du installerar behörighet att skicka aviseringar. Tryck om du vill ändra denna behörighet för befintliga appar."</string>
     <string name="review_notification_settings_remind_me_action" msgid="1081081018678480907">"Påminn mig senare"</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index c002866..676e7ab 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -2129,11 +2129,6 @@
     <string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"Itatetema arifa ikitumwa au simu ikipigwa"</string>
     <string name="volume_dialog_ringer_guidance_silent" msgid="1011246774949993783">"Haitatoa mlio arifa ikitumwa au simu ikipigwa"</string>
     <string name="notification_channel_system_changes" msgid="2462010596920209678">"Mabadiliko kwenye mfumo"</string>
-    <string name="notification_channel_do_not_disturb" msgid="7832584281883687653">"Usinisumbue"</string>
-    <string name="zen_upgrade_notification_visd_title" msgid="2001148984371968620">"Mpya: Kipengele cha Usinisumbue kinaficha arifa"</string>
-    <string name="zen_upgrade_notification_visd_content" msgid="3683314609114134946">"Gusa ili upate maelezo zaidi na ubadilishe."</string>
-    <string name="zen_upgrade_notification_title" msgid="8198167698095298717">"Kipengele cha Usinisumbue kimebadilishwa"</string>
-    <string name="zen_upgrade_notification_content" msgid="5228458567180124005">"Gusa ili uangalie kipengee ambacho kimezuiwa."</string>
     <string name="review_notification_settings_title" msgid="5102557424459810820">"Kagua mipangilio ya arifa"</string>
     <string name="review_notification_settings_text" msgid="5916244866751849279">"Kuanzia Android toleo la 13, programu unazosakinisha zitahitaji ruhusa yako ili zitume arifa. Gusa ili ubadilishe ruhusa hii kwa programu zilizopo."</string>
     <string name="review_notification_settings_remind_me_action" msgid="1081081018678480907">"Nikumbushe baadaye"</string>
diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml
index dfc6a79..35cad78 100644
--- a/core/res/res/values-ta/strings.xml
+++ b/core/res/res/values-ta/strings.xml
@@ -2129,11 +2129,6 @@
     <string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"அழைப்புகள் மற்றும் அறிவிப்புகளுக்கு அதிரும்"</string>
     <string name="volume_dialog_ringer_guidance_silent" msgid="1011246774949993783">"அழைப்புகள் மற்றும் அறிவிப்புகளுக்கு ஒலியை முடக்கும்"</string>
     <string name="notification_channel_system_changes" msgid="2462010596920209678">"சிஸ்டம் மாற்றங்கள்"</string>
-    <string name="notification_channel_do_not_disturb" msgid="7832584281883687653">"தொந்தரவு செய்ய வேண்டாம்"</string>
-    <string name="zen_upgrade_notification_visd_title" msgid="2001148984371968620">"புதியது: \'தொந்தரவு செய்ய வேண்டாம்\' பயன்முறையானது அறிவிப்புகளைக் காட்டாமல் மறைக்கிறது"</string>
-    <string name="zen_upgrade_notification_visd_content" msgid="3683314609114134946">"மேலும் அறிந்து மாற்ற, தட்டவும்."</string>
-    <string name="zen_upgrade_notification_title" msgid="8198167698095298717">"தொந்தரவு செய்ய வேண்டாம் அமைப்புகள் மாற்றப்பட்டன"</string>
-    <string name="zen_upgrade_notification_content" msgid="5228458567180124005">"எவற்றையெல்லாம் தடுக்கிறது என்பதைப் பார்க்க, தட்டவும்."</string>
     <string name="review_notification_settings_title" msgid="5102557424459810820">"அறிவிப்பு அமைப்புகளை மதிப்பாய்வு செய்யுங்கள்"</string>
     <string name="review_notification_settings_text" msgid="5916244866751849279">"Android 13 பதிப்பு முதல், நீங்கள் நிறுவுகின்ற ஆப்ஸ் உங்களுக்கு அறிவிப்புகளை அனுப்ப அனுமதி தேவை. ஏற்கெனவே உள்ள ஆப்ஸுக்கு இந்த அனுமதியை மாற்ற தட்டவும்."</string>
     <string name="review_notification_settings_remind_me_action" msgid="1081081018678480907">"பின்னர் நினைவூட்டு"</string>
diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml
index 7073266..fd78f1d 100644
--- a/core/res/res/values-te/strings.xml
+++ b/core/res/res/values-te/strings.xml
@@ -2129,11 +2129,6 @@
     <string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"కాల్స్‌ మరియు నోటిఫికేషన్‌లు వైబ్రేట్ అవుతాయి"</string>
     <string name="volume_dialog_ringer_guidance_silent" msgid="1011246774949993783">"కాల్స్‌ మరియు నోటిఫికేషన్‌లు మ్యూట్ చేయబడతాయి"</string>
     <string name="notification_channel_system_changes" msgid="2462010596920209678">"సిస్టమ్ మార్పులు"</string>
-    <string name="notification_channel_do_not_disturb" msgid="7832584281883687653">"అంతరాయం కలిగించవద్దు"</string>
-    <string name="zen_upgrade_notification_visd_title" msgid="2001148984371968620">"కొత్తది: అంతరాయం కలిగించవద్దు నోటిఫికేషన్‌లను దాస్తోంది"</string>
-    <string name="zen_upgrade_notification_visd_content" msgid="3683314609114134946">"మరింత తెలుసుకోవడానికి మరియు మార్చడానికి నొక్కండి."</string>
-    <string name="zen_upgrade_notification_title" msgid="8198167698095298717">"అంతరాయం కలిగించవద్దు మార్చబడింది"</string>
-    <string name="zen_upgrade_notification_content" msgid="5228458567180124005">"బ్లాక్ చేయబడిన దాన్ని చెక్ చేయడానికి నొక్కండి."</string>
     <string name="review_notification_settings_title" msgid="5102557424459810820">"నోటిఫికేషన్ సెట్టింగ్‌లను రివ్యూ చేయండి"</string>
     <string name="review_notification_settings_text" msgid="5916244866751849279">"Android 13తో మొదలుకుని, మీరు ఇన్‌స్టాల్ చేసే యాప్‌లకు నోటిఫికేషన్‌లను పంపడానికి మీ అనుమతి అవసరం. ఇప్పటికే ఉన్న యాప్‌ల కోసం ఈ అనుమతిని మార్చడానికి ట్యాప్ చేయండి."</string>
     <string name="review_notification_settings_remind_me_action" msgid="1081081018678480907">"తర్వాత గుర్తు చేయి"</string>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index 5ee187f..cbac93d 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -2129,11 +2129,6 @@
     <string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"สายเรียกเข้าและการแจ้งเตือนจะสั่น"</string>
     <string name="volume_dialog_ringer_guidance_silent" msgid="1011246774949993783">"สายเรียกเข้าและการแจ้งเตือนจะไม่ส่งเสียง"</string>
     <string name="notification_channel_system_changes" msgid="2462010596920209678">"การเปลี่ยนแปลงระบบ"</string>
-    <string name="notification_channel_do_not_disturb" msgid="7832584281883687653">"ห้ามรบกวน"</string>
-    <string name="zen_upgrade_notification_visd_title" msgid="2001148984371968620">"ใหม่: โหมดห้ามรบกวนซ่อนการแจ้งเตือนไว้"</string>
-    <string name="zen_upgrade_notification_visd_content" msgid="3683314609114134946">"แตะเพื่อดูข้อมูลเพิ่มเติมและเปลี่ยนแปลง"</string>
-    <string name="zen_upgrade_notification_title" msgid="8198167698095298717">"เปลี่ยน \"ห้ามรบกวน\" แล้ว"</string>
-    <string name="zen_upgrade_notification_content" msgid="5228458567180124005">"แตะเพื่อดูรายการที่ถูกบล็อก"</string>
     <string name="review_notification_settings_title" msgid="5102557424459810820">"ตรวจสอบการตั้งค่าการแจ้งเตือน"</string>
     <string name="review_notification_settings_text" msgid="5916244866751849279">"ตั้งแต่ Android 13 เป็นต้นไป แอปที่คุณติดตั้งจะต้องได้รับสิทธิ์จากคุณเพื่อส่งการแจ้งเตือน แตะเพื่อเปลี่ยนแปลงสิทธิ์นี้สำหรับแอปที่มีอยู่"</string>
     <string name="review_notification_settings_remind_me_action" msgid="1081081018678480907">"เตือนภายหลัง"</string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index e76dacd..f9edcdc 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -2129,11 +2129,6 @@
     <string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"Magva-vibrate ang mga tawag at notification"</string>
     <string name="volume_dialog_ringer_guidance_silent" msgid="1011246774949993783">"Mamu-mute ang mga tawag at notification"</string>
     <string name="notification_channel_system_changes" msgid="2462010596920209678">"Mga pagbabago sa system"</string>
-    <string name="notification_channel_do_not_disturb" msgid="7832584281883687653">"Huwag Istorbohin"</string>
-    <string name="zen_upgrade_notification_visd_title" msgid="2001148984371968620">"Bago: Itinatago ng Huwag Istorbohin ang mga notification"</string>
-    <string name="zen_upgrade_notification_visd_content" msgid="3683314609114134946">"I-tap para matuto pa at baguhin."</string>
-    <string name="zen_upgrade_notification_title" msgid="8198167698095298717">"Binago ang Huwag Istorbohin"</string>
-    <string name="zen_upgrade_notification_content" msgid="5228458567180124005">"I-tap para tingnan kung ano ang naka-block."</string>
     <string name="review_notification_settings_title" msgid="5102557424459810820">"Suriin ang mga setting ng notification"</string>
     <string name="review_notification_settings_text" msgid="5916244866751849279">"Simula sa Android 13, kakailanganin na ng mga app na ii-install mo ang iyong pahintulot para makapagpadala ng mga notification. I-tap para baguhin ang pahintulot na ito para sa mga kasalukuyang app."</string>
     <string name="review_notification_settings_remind_me_action" msgid="1081081018678480907">"Ipaalala mamaya"</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index ad6fc0d..fea0951 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -2129,11 +2129,6 @@
     <string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"Aramalar ve bildirimler titreşim yapacak"</string>
     <string name="volume_dialog_ringer_guidance_silent" msgid="1011246774949993783">"Aramalar ve bildirimlerin sesi kapalı olacak"</string>
     <string name="notification_channel_system_changes" msgid="2462010596920209678">"Sistem değişiklikleri"</string>
-    <string name="notification_channel_do_not_disturb" msgid="7832584281883687653">"Rahatsız Etmeyin"</string>
-    <string name="zen_upgrade_notification_visd_title" msgid="2001148984371968620">"Yeni: Rahatsız Etmeyin ayarı bildirimleri gizliyor"</string>
-    <string name="zen_upgrade_notification_visd_content" msgid="3683314609114134946">"Daha fazla bilgi edinmek ve değiştirmek için dokunun."</string>
-    <string name="zen_upgrade_notification_title" msgid="8198167698095298717">"Rahatsız Etmeyin modu değişti"</string>
-    <string name="zen_upgrade_notification_content" msgid="5228458567180124005">"Nelerin engellendiğini kontrol etmek için dokunun."</string>
     <string name="review_notification_settings_title" msgid="5102557424459810820">"Bildirim ayarlarını inceleyin"</string>
     <string name="review_notification_settings_text" msgid="5916244866751849279">"Android 13\'te başlayarak yüklediğiniz uygulamaların bildirim gönderebilmesi için izniniz gereklidir. Mevcut uygulamalarda bu izni değiştirmek için dokunun."</string>
     <string name="review_notification_settings_remind_me_action" msgid="1081081018678480907">"Sonra hatırlat"</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index a63f3fb..68f85b8 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -2131,11 +2131,6 @@
     <string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"Вібросигнал для викликів і сповіщень увімкнено"</string>
     <string name="volume_dialog_ringer_guidance_silent" msgid="1011246774949993783">"Звуковий сигнал для викликів і сповіщень вимкнено"</string>
     <string name="notification_channel_system_changes" msgid="2462010596920209678">"Системні зміни"</string>
-    <string name="notification_channel_do_not_disturb" msgid="7832584281883687653">"Не турбувати"</string>
-    <string name="zen_upgrade_notification_visd_title" msgid="2001148984371968620">"Нове: у режимі \"Не турбувати\" сповіщення ховаються"</string>
-    <string name="zen_upgrade_notification_visd_content" msgid="3683314609114134946">"Торкніться, щоб дізнатися більше та змінити."</string>
-    <string name="zen_upgrade_notification_title" msgid="8198167698095298717">"Налаштування режиму \"Не турбувати\" змінено"</string>
-    <string name="zen_upgrade_notification_content" msgid="5228458567180124005">"Торкніться, щоб перевірити, що заблоковано."</string>
     <string name="review_notification_settings_title" msgid="5102557424459810820">"Перегляньте налаштування сповіщень"</string>
     <string name="review_notification_settings_text" msgid="5916244866751849279">"Починаючи з ОС Android 13, установленим додаткам потрібно надати дозвіл, щоб вони могли надсилати сповіщення. Натисніть, щоб змінити цей дозвіл для наявних додатків."</string>
     <string name="review_notification_settings_remind_me_action" msgid="1081081018678480907">"Нагадати пізніше"</string>
diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml
index 52d9e3b..4f09717 100644
--- a/core/res/res/values-ur/strings.xml
+++ b/core/res/res/values-ur/strings.xml
@@ -2129,11 +2129,6 @@
     <string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"کالز اور اطلاعات پر وائبریٹ کرے گا"</string>
     <string name="volume_dialog_ringer_guidance_silent" msgid="1011246774949993783">"کالز اور اطلاعات کی آواز خاموش کر دی جائے گی"</string>
     <string name="notification_channel_system_changes" msgid="2462010596920209678">"سسٹم کی تبدیلیاں"</string>
-    <string name="notification_channel_do_not_disturb" msgid="7832584281883687653">"ڈسٹرب نہ کریں"</string>
-    <string name="zen_upgrade_notification_visd_title" msgid="2001148984371968620">"نئی: \'ڈسٹرب نہ کریں\' اطلاعات کو چھپا رہی ہے"</string>
-    <string name="zen_upgrade_notification_visd_content" msgid="3683314609114134946">"مزید جاننے اور تبدیل کرنے کیلئے تھپتھپائیں۔"</string>
-    <string name="zen_upgrade_notification_title" msgid="8198167698095298717">"\'ڈسٹرب نہ کریں\' تبدیل ہو گيا ہے"</string>
-    <string name="zen_upgrade_notification_content" msgid="5228458567180124005">"مسدود کی گئی چیزوں کو چیک کرنے کے لیے تھپتھپائیں۔"</string>
     <string name="review_notification_settings_title" msgid="5102557424459810820">"اطلاع کی ترتیبات کا جائزہ لیں"</string>
     <string name="review_notification_settings_text" msgid="5916244866751849279">"‏Android 13 کے ساتھ اب آپ جو بھی ایپس انسٹال کریں گے انہیں اطلاعات بھیجنے کے لیے آپ کی اجازت درکار ہوگی۔ موجودہ ایپس کے لیے اس اجازت کو تبدیل کرنے کی خاطر تھپتھپائیں۔"</string>
     <string name="review_notification_settings_remind_me_action" msgid="1081081018678480907">"بعد میں یاد دلائیں"</string>
diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml
index f62074e..1bb3bcdc 100644
--- a/core/res/res/values-uz/strings.xml
+++ b/core/res/res/values-uz/strings.xml
@@ -2129,11 +2129,6 @@
     <string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"Chaqiruvlar va bildirishnomalar tebranadi"</string>
     <string name="volume_dialog_ringer_guidance_silent" msgid="1011246774949993783">"Chaqiruvlar va bildirishnomalar ovozsiz qilinadi"</string>
     <string name="notification_channel_system_changes" msgid="2462010596920209678">"Tizimga oid o‘zgarishlar"</string>
-    <string name="notification_channel_do_not_disturb" msgid="7832584281883687653">"Bezovta qilinmasin"</string>
-    <string name="zen_upgrade_notification_visd_title" msgid="2001148984371968620">"Yangi: Bezovta qilinmasin rejimi bildirishnomalarni berkitmoqda"</string>
-    <string name="zen_upgrade_notification_visd_content" msgid="3683314609114134946">"Batafsil axborot olish va o‘zgartirish uchun bosing."</string>
-    <string name="zen_upgrade_notification_title" msgid="8198167698095298717">"Bezovta qilinmasin rejimi sozlamalari o‘zgartirildi"</string>
-    <string name="zen_upgrade_notification_content" msgid="5228458567180124005">"Nimalar bloklanganini tekshirish uchun bosing"</string>
     <string name="review_notification_settings_title" msgid="5102557424459810820">"Bildirishnoma sozlamalarini tekshiring"</string>
     <string name="review_notification_settings_text" msgid="5916244866751849279">"Android 13 versiyasidan boshlab, oʻrnatiladigan ilovalar bildirishnoma yuborish uchun sizdan ruxsat oladi. Mavjud ilovalarda ushbu ruxsatni oʻzgartirish uchun bosing."</string>
     <string name="review_notification_settings_remind_me_action" msgid="1081081018678480907">"Keyinroq eslatilsin"</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index 3b08a22..3b1b21d 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -2129,11 +2129,6 @@
     <string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"Cuộc gọi và thông báo sẽ rung"</string>
     <string name="volume_dialog_ringer_guidance_silent" msgid="1011246774949993783">"Cuộc gọi và thông báo sẽ tắt tiếng"</string>
     <string name="notification_channel_system_changes" msgid="2462010596920209678">"Thay đổi hệ thống"</string>
-    <string name="notification_channel_do_not_disturb" msgid="7832584281883687653">"Không làm phiền"</string>
-    <string name="zen_upgrade_notification_visd_title" msgid="2001148984371968620">"Mới: Chế độ Không làm phiền sẽ ẩn thông báo"</string>
-    <string name="zen_upgrade_notification_visd_content" msgid="3683314609114134946">"Nhấn để tìm hiểu thêm và thay đổi."</string>
-    <string name="zen_upgrade_notification_title" msgid="8198167698095298717">"Cài đặt Không làm phiền đã thay đổi"</string>
-    <string name="zen_upgrade_notification_content" msgid="5228458567180124005">"Nhấn để xem những thông báo bị chặn."</string>
     <string name="review_notification_settings_title" msgid="5102557424459810820">"Xem lại chế độ cài đặt thông báo"</string>
     <string name="review_notification_settings_text" msgid="5916244866751849279">"Bắt đầu trên Android 13, các ứng dụng bạn cài đặt sẽ cần bạn cấp quyền để gửi thông báo. Hãy nhấn để thay đổi quyền này cho các ứng dụng hiện có."</string>
     <string name="review_notification_settings_remind_me_action" msgid="1081081018678480907">"Nhắc tôi sau"</string>
diff --git a/core/res/res/values-watch-v36/colors.xml b/core/res/res/values-watch-v36/colors.xml
new file mode 100644
index 0000000..4bc2a66
--- /dev/null
+++ b/core/res/res/values-watch-v36/colors.xml
@@ -0,0 +1,18 @@
+<!--
+  ~ Copyright (C) 2024 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<!-- TODO(b/372524566): update color token's value to match material3 design. -->
+<resources>
+</resources>
\ No newline at end of file
diff --git a/core/res/res/values-watch-v36/config.xml b/core/res/res/values-watch-v36/config.xml
new file mode 100644
index 0000000..c8f347af
--- /dev/null
+++ b/core/res/res/values-watch-v36/config.xml
@@ -0,0 +1,20 @@
+<!--
+  ~ Copyright (C) 2024 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<resources>
+    <!-- Overrides system value -->
+    <dimen name="config_buttonCornerRadius">26dp</dimen>
+</resources>
diff --git a/core/res/res/values-watch-v36/dimens_material.xml b/core/res/res/values-watch-v36/dimens_material.xml
new file mode 100644
index 0000000..ad3c1a3
--- /dev/null
+++ b/core/res/res/values-watch-v36/dimens_material.xml
@@ -0,0 +1,28 @@
+<!--
+  ~ Copyright (C) 2024 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<resources>
+    <!-- values for material3 button -->
+    <dimen name="btn_material_width">172dp</dimen>
+    <dimen name="btn_material_height">52dp</dimen>
+    <dimen name="btn_horizontal_edge_padding">14dp</dimen>
+    <dimen name="btn_drawable_padding">6dp</dimen>
+    <dimen name="btn_lineHeight">18sp</dimen>
+    <dimen name="btn_textSize">15sp</dimen>
+
+    <!-- Opacity factor for disabled material3 widget -->
+    <dimen name="disabled_alpha_device_default">0.12</dimen>
+    <dimen name="primary_content_alpha_device_default">0.38</dimen>
+</resources>
diff --git a/core/res/res/values-watch-v36/styles_material.xml b/core/res/res/values-watch-v36/styles_material.xml
new file mode 100644
index 0000000..32a22bb
--- /dev/null
+++ b/core/res/res/values-watch-v36/styles_material.xml
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2024 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<resources>
+    <!--  Button Styles  -->
+    <!-- Material Button - Filled  -->
+    <style name="Widget.DeviceDefault.Button.Filled" parent="Widget.DeviceDefault.Button">
+        <item name="android:background">@drawable/btn_background_material_filled</item>
+        <item name="textAppearance">@style/TextAppearance.Widget.Button.Material.Filled</item>
+    </style>
+
+    <!-- Material Button - Filled Tonal(Override system default button styles) -->
+    <style name="Widget.DeviceDefault.Button">
+        <item name="background">@drawable/btn_background_material_filled_tonal</item>
+        <item name="textAppearance">@style/TextAppearance.Widget.Button.Material</item>
+        <item name="minHeight">@dimen/btn_material_height</item>
+        <item name="maxWidth">@dimen/btn_material_width</item>
+        <item name="android:paddingStart">@dimen/btn_horizontal_edge_padding</item>
+        <item name="android:paddingEnd">@dimen/btn_horizontal_edge_padding</item>
+        <item name="android:drawablePadding">@dimen/btn_drawable_padding</item>
+        <item name="android:maxLines">2</item>
+        <item name="android:ellipsize">end</item>
+        <item name="android:breakStrategy">simple</item>
+        <item name="stateListAnimator">@anim/button_state_list_anim_material</item>
+        <item name="focusable">true</item>
+        <item name="clickable">true</item>
+        <item name="gravity">center_vertical</item>
+    </style>
+
+    <!--  Text Styles  -->
+    <!-- TextAppearance for Material Button - Filled  -->
+    <style name="TextAppearance.Widget.Button.Material.Filled" parent="TextAppearance.Widget.Button.Material">
+        <item name="textColor">@color/btn_material_filled_text_color</item>
+    </style>
+
+    <!-- TextAppearance for Material Button - Filled Tonal  -->
+    <style name="TextAppearance.Widget.Button.Material" parent="TextAppearance.DeviceDefault">
+        <item name="android:fontFamily">font-family-flex-device-default</item>
+        <item name="android:fontVariationSettings">"'wdth' 90, 'wght' 500, 'ROND' 100, 'opsz' 15, 'GRAD' 0"</item>
+        <item name="textSize">@dimen/btn_textSize</item>
+        <item name="textColor">@color/btn_material_filled_tonal_text_color</item>
+        <item name="lineHeight">@dimen/btn_lineHeight</item>
+    </style>
+</resources>
\ No newline at end of file
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 95753eb..e7ebb6c 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -2129,11 +2129,6 @@
     <string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"有来电和通知时会振动"</string>
     <string name="volume_dialog_ringer_guidance_silent" msgid="1011246774949993783">"有来电和通知时会静音"</string>
     <string name="notification_channel_system_changes" msgid="2462010596920209678">"系统变更"</string>
-    <string name="notification_channel_do_not_disturb" msgid="7832584281883687653">"勿扰"</string>
-    <string name="zen_upgrade_notification_visd_title" msgid="2001148984371968620">"新功能:勿扰模式目前可隐藏通知"</string>
-    <string name="zen_upgrade_notification_visd_content" msgid="3683314609114134946">"点按即可了解详情以及进行更改。"</string>
-    <string name="zen_upgrade_notification_title" msgid="8198167698095298717">"“勿扰”设置有变更"</string>
-    <string name="zen_upgrade_notification_content" msgid="5228458567180124005">"点按即可查看屏蔽内容。"</string>
     <string name="review_notification_settings_title" msgid="5102557424459810820">"查看通知设置"</string>
     <string name="review_notification_settings_text" msgid="5916244866751849279">"从 Android 13 开始,您安装的应用需要您授予相应权限才能发送通知。点按即可为现有应用更改此权限。"</string>
     <string name="review_notification_settings_remind_me_action" msgid="1081081018678480907">"稍后提醒我"</string>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index df04ec8..8f7e17c 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -2129,11 +2129,6 @@
     <string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"有來電和通知時會震動"</string>
     <string name="volume_dialog_ringer_guidance_silent" msgid="1011246774949993783">"有來電和通知時會靜音"</string>
     <string name="notification_channel_system_changes" msgid="2462010596920209678">"系統變更"</string>
-    <string name="notification_channel_do_not_disturb" msgid="7832584281883687653">"請勿騷擾"</string>
-    <string name="zen_upgrade_notification_visd_title" msgid="2001148984371968620">"新通知:「請勿騷擾」模式目前隱藏通知"</string>
-    <string name="zen_upgrade_notification_visd_content" msgid="3683314609114134946">"輕按即可瞭解詳情和作出變更。"</string>
-    <string name="zen_upgrade_notification_title" msgid="8198167698095298717">"請勿騷擾已變更"</string>
-    <string name="zen_upgrade_notification_content" msgid="5228458567180124005">"輕按即可查看封鎖內容。"</string>
     <string name="review_notification_settings_title" msgid="5102557424459810820">"查看通知設定"</string>
     <string name="review_notification_settings_text" msgid="5916244866751849279">"由 Android 13 開始,你安裝的應用程式須獲得授權才能傳送通知。輕按即可變更現有應用程式的這項權限。"</string>
     <string name="review_notification_settings_remind_me_action" msgid="1081081018678480907">"稍後提醒我"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index f0351ce..76c581c 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -2129,11 +2129,6 @@
     <string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"有來電和通知時會震動"</string>
     <string name="volume_dialog_ringer_guidance_silent" msgid="1011246774949993783">"有來電和通知時會靜音"</string>
     <string name="notification_channel_system_changes" msgid="2462010596920209678">"系統變更"</string>
-    <string name="notification_channel_do_not_disturb" msgid="7832584281883687653">"零打擾"</string>
-    <string name="zen_upgrade_notification_visd_title" msgid="2001148984371968620">"新功能:「零打擾」模式現在可以隱藏通知"</string>
-    <string name="zen_upgrade_notification_visd_content" msgid="3683314609114134946">"輕觸即可瞭解詳情及進行變更。"</string>
-    <string name="zen_upgrade_notification_title" msgid="8198167698095298717">"「零打擾」設定已變更"</string>
-    <string name="zen_upgrade_notification_content" msgid="5228458567180124005">"輕觸即可查看遭封鎖的項目。"</string>
     <string name="review_notification_settings_title" msgid="5102557424459810820">"查看通知設定"</string>
     <string name="review_notification_settings_text" msgid="5916244866751849279">"從 Android 13 開始,你安裝的應用程式必須獲得授權,才能傳送通知。輕觸即可為現有應用程式變更這項權限。"</string>
     <string name="review_notification_settings_remind_me_action" msgid="1081081018678480907">"稍後提醒我"</string>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index f051a45..5aab13b 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -2129,11 +2129,6 @@
     <string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"Amakholi nezaziso zizodlidliza"</string>
     <string name="volume_dialog_ringer_guidance_silent" msgid="1011246774949993783">"Amakholi nezaziso zizothuliswa"</string>
     <string name="notification_channel_system_changes" msgid="2462010596920209678">"Ushintsho lwesistimu"</string>
-    <string name="notification_channel_do_not_disturb" msgid="7832584281883687653">"Ungaphazamisi"</string>
-    <string name="zen_upgrade_notification_visd_title" msgid="2001148984371968620">"Ukungaphazamisi kufihle izaziso"</string>
-    <string name="zen_upgrade_notification_visd_content" msgid="3683314609114134946">"Thepha ukuze ufunde kabanzi futhi ushintshe."</string>
-    <string name="zen_upgrade_notification_title" msgid="8198167698095298717">"Ukungaphazamisi kushintshile"</string>
-    <string name="zen_upgrade_notification_content" msgid="5228458567180124005">"Thepha ukuze uhlole ukuthi yini evinjelwe."</string>
     <string name="review_notification_settings_title" msgid="5102557424459810820">"Buyekeza amasethingi wesaziso"</string>
     <string name="review_notification_settings_text" msgid="5916244866751849279">"Kusukela ku-Android 13, ama-app owafakayo adinga imvume yakho yokuthumela izaziso. Thepha ukuze ushintshe le mvume yama-app akhona kakade."</string>
     <string name="review_notification_settings_remind_me_action" msgid="1081081018678480907">"Ngikhumbuze ngesinye isikhathi"</string>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 440219d..02f9f3c 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -7720,6 +7720,44 @@
         <attr name="animation" />
     </declare-styleable>
 
+    <!-- ================================== -->
+    <!-- NotificationProgressDrawable class -->
+    <!-- ================================== -->
+
+    <!-- Drawable used to render a segmented bar, with segments and points. -->
+    <!-- @hide internal use only -->
+    <declare-styleable name="NotificationProgressDrawable">
+        <!-- Default color for the parts. -->
+        <attr name="segSegGap" format="dimension" />
+        <attr name="segPointGap" format="dimension" />
+    </declare-styleable>
+
+    <!-- Used to config the segments of a NotificationProgressDrawable. -->
+    <!-- @hide internal use only -->
+    <declare-styleable name="NotificationProgressDrawableSegments">
+        <!-- Width of the stroke. -->
+        <attr name="width" />
+        <!-- Default color of the stroke. -->
+        <attr name="color" />
+        <!-- Length of a dash in the stroke for the dashed segments. -->
+        <attr name="dashWidth" />
+        <!-- Gap between dashes in the stroke for the dashed segments. -->
+        <attr name="dashGap" />
+    </declare-styleable>
+
+    <!-- Used to config the points of a NotificationProgressDrawable. -->
+    <!-- @hide internal use only -->
+    <declare-styleable name="NotificationProgressDrawablePoints">
+        <!-- Radius (1/2 size) of the point rect. -->
+        <attr name="radius" />
+        <!-- Inset of the point icon or rect. -->
+        <attr name="inset" />
+        <!-- Corner radius of the point rect. -->
+        <attr name="cornerRadius" format="dimension" />
+        <!-- Default color of the point rect. -->
+        <attr name="color" />
+    </declare-styleable>
+
     <!-- ========================== -->
     <!-- Animation class attributes -->
     <!-- ========================== -->
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index b90ee2b..8a2d767 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -6918,6 +6918,14 @@
          entering the corresponding modes -->
     <string name="config_rearDisplayPhysicalAddress" translatable="false"></string>
 
+    <!-- The maximum number of virtual displays that can exist at the same time.
+         It must be >= 1. -->
+    <integer name="config_virtualDisplayLimit">100</integer>
+
+    <!-- The maximum number of virtual displays per package that can exist at the same time.
+         It must be >= 1. -->
+    <integer name="config_virtualDisplayLimitPerPackage">50</integer>
+
     <!-- List of certificate to be used for font fs-verity integrity verification -->
     <string-array translatable="false" name="config_fontManagerServiceCerts">
     </string-array>
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 6683dc0..b92aa2f 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -304,6 +304,9 @@
     <!-- The top margin before the notification progress bar. -->
     <dimen name="notification_progress_margin_top">8dp</dimen>
 
+    <!-- The horizontal margin before and after the notification progress bar. -->
+    <dimen name="notification_progress_margin_horizontal">2dp</dimen>
+
     <!-- height of the notification header -->
     <dimen name="notification_header_height">56dp</dimen>
 
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index c50c336..4f63fac 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -224,6 +224,8 @@
   <java-symbol type="id" name="status_bar_latest_event_content" />
   <java-symbol type="id" name="notification_main_column" />
   <java-symbol type="id" name="notification_headerless_view_column" />
+  <java-symbol type="id" name="notification_progress_start_icon" />
+  <java-symbol type="id" name="notification_progress_end_icon" />
   <java-symbol type="id" name="sms_short_code_confirm_message" />
   <java-symbol type="id" name="sms_short_code_detail_layout" />
   <java-symbol type="id" name="sms_short_code_detail_message" />
@@ -1580,6 +1582,8 @@
   <java-symbol type="layout" name="input_method" />
   <java-symbol type="layout" name="input_method_extract_view" />
   <java-symbol type="layout" name="input_method_switch_item" />
+  <java-symbol type="layout" name="input_method_switch_item_divider" />
+  <java-symbol type="layout" name="input_method_switch_item_header" />
   <java-symbol type="layout" name="input_method_switch_item_new" />
   <java-symbol type="layout" name="input_method_switch_dialog_new" />
   <java-symbol type="layout" name="input_method_switch_dialog_title" />
@@ -2390,6 +2394,7 @@
   <java-symbol type="layout" name="notification_template_material_media" />
   <java-symbol type="layout" name="notification_template_material_big_media" />
   <java-symbol type="layout" name="notification_template_material_big_text" />
+  <java-symbol type="layout" name="notification_template_material_progress" />
   <java-symbol type="layout" name="notification_template_header" />
   <java-symbol type="layout" name="notification_material_media_action" />
   <java-symbol type="color" name="notification_progress_background_color" />
@@ -3205,6 +3210,7 @@
   <java-symbol type="dimen" name="notification_heading_margin_end" />
   <java-symbol type="dimen" name="notification_content_margin_top" />
   <java-symbol type="dimen" name="notification_content_margin" />
+  <java-symbol type="dimen" name="notification_progress_margin_horizontal" />
   <java-symbol type="dimen" name="notification_header_background_height" />
   <java-symbol type="dimen" name="notification_header_touchable_height" />
   <java-symbol type="dimen" name="notification_header_expand_icon_size" />
@@ -4076,6 +4082,7 @@
   <java-symbol type="dimen" name="text_size_body_2_material" />
   <java-symbol type="dimen" name="notification_icon_circle_size" />
   <java-symbol type="drawable" name="notification_icon_circle" />
+  <java-symbol type="drawable" name="notification_progress_icon_background" />
   <java-symbol type="dimen" name="messaging_avatar_size" />
   <java-symbol type="dimen" name="messaging_group_sending_progress_size" />
   <java-symbol type="dimen" name="messaging_image_rounding" />
@@ -5235,6 +5242,9 @@
   <java-symbol type="integer" name="config_deviceStateConcurrentRearDisplay" />
   <java-symbol type="string" name="config_rearDisplayPhysicalAddress" />
 
+  <java-symbol type="integer" name="config_virtualDisplayLimit" />
+  <java-symbol type="integer" name="config_virtualDisplayLimitPerPackage" />
+
   <!-- For app language picker -->
   <java-symbol type="string" name="system_locale_title" />
   <java-symbol type="layout" name="app_language_picker_system_default" />
diff --git a/core/tests/coretests/src/android/app/ActivityManagerTest.java b/core/tests/coretests/src/android/app/ActivityManagerTest.java
index d850f86..85ff846 100644
--- a/core/tests/coretests/src/android/app/ActivityManagerTest.java
+++ b/core/tests/coretests/src/android/app/ActivityManagerTest.java
@@ -60,7 +60,6 @@
     public void testProcState() throws Exception {
         // For the moment mostly want to confirm we don't crash
         assertNotNull(ActivityManager.procStateToString(PROCESS_STATE_SERVICE));
-        assertNotNull(ActivityManager.processStateAmToProto(PROCESS_STATE_SERVICE));
         assertTrue(ActivityManager.isProcStateBackground(PROCESS_STATE_SERVICE));
         assertFalse(ActivityManager.isProcStateCached(PROCESS_STATE_SERVICE));
         assertFalse(ActivityManager.isForegroundService(PROCESS_STATE_SERVICE));
diff --git a/core/tests/coretests/src/android/app/activity/ActivityManagerTest.java b/core/tests/coretests/src/android/app/activity/ActivityManagerTest.java
index b972882..cd52421 100644
--- a/core/tests/coretests/src/android/app/activity/ActivityManagerTest.java
+++ b/core/tests/coretests/src/android/app/activity/ActivityManagerTest.java
@@ -111,12 +111,6 @@
         assertEquals(config.reqKeyboardType, vconfig.keyboard);
         assertEquals(config.reqTouchScreen, vconfig.touchscreen);
         assertEquals(config.reqNavigation, vconfig.navigation);
-        if (vconfig.navigation == Configuration.NAVIGATION_NONAV) {
-            assertNotNull(config.reqInputFeatures & ConfigurationInfo.INPUT_FEATURE_FIVE_WAY_NAV);
-        }
-        if (vconfig.keyboard != Configuration.KEYBOARD_UNDEFINED) {
-            assertNotNull(config.reqInputFeatures & ConfigurationInfo.INPUT_FEATURE_HARD_KEYBOARD);
-        }    
     }
 
     @SmallTest
diff --git a/core/tests/coretests/src/android/app/assist/AssistStructureTest.java b/core/tests/coretests/src/android/app/assist/AssistStructureTest.java
index a28b2f6..51e79e7 100644
--- a/core/tests/coretests/src/android/app/assist/AssistStructureTest.java
+++ b/core/tests/coretests/src/android/app/assist/AssistStructureTest.java
@@ -24,6 +24,7 @@
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
 
 import android.app.assist.AssistStructure.ViewNode;
 import android.app.assist.AssistStructure.ViewNodeBuilder;
@@ -37,6 +38,7 @@
 import android.os.LocaleList;
 import android.os.OutcomeReceiver;
 import android.os.Parcel;
+import android.os.PooledStringWriter;
 import android.os.SystemClock;
 import android.text.InputFilter;
 import android.util.Log;
@@ -355,6 +357,18 @@
 
     }
 
+    @Test
+    public void testParcelTransferWriter_writeNull() {
+        AssistStructure structure = new AssistStructure(mActivity, FOR_AUTOFILL, NO_FLAGS);
+        Parcel parcel = Parcel.obtain();
+        AssistStructure.ParcelTransferWriter writer =
+                new AssistStructure.ParcelTransferWriter(structure, parcel);
+        writer.writeView(null, parcel, new PooledStringWriter(parcel), 0);
+
+        // No throw any exception.
+        assertTrue(true);
+    }
+
     private EditText newSmallView() {
         EditText view = new EditText(mContext);
         view.setText("I AM GROOT");
diff --git a/core/tests/coretests/src/android/content/res/ResourcesManagerTest.java b/core/tests/coretests/src/android/content/res/ResourcesManagerTest.java
index b16c237..be8ecbe 100644
--- a/core/tests/coretests/src/android/content/res/ResourcesManagerTest.java
+++ b/core/tests/coretests/src/android/content/res/ResourcesManagerTest.java
@@ -470,6 +470,7 @@
 
     @Test
     @SmallTest
+    @DisabledOnRavenwood(blockedBy = ResourcesManager.class)
     public void testResourceConfigurationAppliedWhenOverrideDoesNotExist() {
         final int width = 240;
         final int height = 360;
diff --git a/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java b/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java
index ba6f62c..d7f6a29 100644
--- a/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java
+++ b/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java
@@ -100,14 +100,14 @@
         topConsumer.setControl(
                 new InsetsSourceControl(ID_STATUS_BAR, WindowInsets.Type.statusBars(),
                         mStatusLeash, true, new Point(0, 0), Insets.of(0, 100, 0, 0)),
-                new int[1], new int[1]);
+                new int[1], new int[1], new int[1]);
 
         InsetsSourceConsumer navConsumer = new InsetsSourceConsumer(ID_NAVIGATION_BAR,
                 WindowInsets.Type.navigationBars(), mInsetsState, mMockController);
         navConsumer.setControl(
                 new InsetsSourceControl(ID_NAVIGATION_BAR, WindowInsets.Type.navigationBars(),
                         mNavLeash, true, new Point(400, 0), Insets.of(0, 0, 100, 0)),
-                new int[1], new int[1]);
+                new int[1], new int[1], new int[1]);
         mMockController.setRequestedVisibleTypes(0, WindowInsets.Type.navigationBars());
         navConsumer.applyLocalVisibilityOverride();
 
diff --git a/core/tests/coretests/src/android/view/InsetsSourceConsumerTest.java b/core/tests/coretests/src/android/view/InsetsSourceConsumerTest.java
index d6d45e8..3a8f7ee 100644
--- a/core/tests/coretests/src/android/view/InsetsSourceConsumerTest.java
+++ b/core/tests/coretests/src/android/view/InsetsSourceConsumerTest.java
@@ -117,7 +117,23 @@
         mConsumer.setControl(
                 new InsetsSourceControl(ID_STATUS_BAR, statusBars(), mLeash,
                         true /* initialVisible */, new Point(), Insets.NONE),
-                new int[1], new int[1]);
+                new int[1], new int[1], new int[1]);
+    }
+
+    @Test
+    public void testSetControl_cancelAnimation() {
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
+            final InsetsSourceControl newControl = new InsetsSourceControl(mConsumer.getControl());
+
+            // Change the side of the insets hint.
+            newControl.setInsetsHint(Insets.of(0, 0, 0, 100));
+
+            int[] cancelTypes = {0};
+            mConsumer.setControl(newControl, new int[1], new int[1], cancelTypes);
+
+            assertEquals(statusBars(), cancelTypes[0]);
+        });
+
     }
 
     @Test
@@ -180,7 +196,7 @@
     @Test
     public void testRestore() {
         InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
-            mConsumer.setControl(null, new int[1], new int[1]);
+            mConsumer.setControl(null, new int[1], new int[1], new int[1]);
             mSurfaceParamsApplied = false;
             mController.setRequestedVisibleTypes(0 /* visibleTypes */, statusBars());
             assertFalse(mSurfaceParamsApplied);
@@ -188,7 +204,7 @@
             mConsumer.setControl(
                     new InsetsSourceControl(ID_STATUS_BAR, statusBars(), mLeash,
                             true /* initialVisible */, new Point(), Insets.NONE),
-                    new int[1], hideTypes);
+                    new int[1], hideTypes, new int[1]);
             assertEquals(statusBars(), hideTypes[0]);
             assertFalse(mRemoveSurfaceCalled);
         });
@@ -198,7 +214,7 @@
     public void testRestore_noAnimation() {
         InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
             mController.setRequestedVisibleTypes(0 /* visibleTypes */, statusBars());
-            mConsumer.setControl(null, new int[1], new int[1]);
+            mConsumer.setControl(null, new int[1], new int[1], new int[1]);
             mLeash = new SurfaceControl.Builder(mSession)
                     .setName("testSurface")
                     .build();
@@ -207,7 +223,7 @@
             mConsumer.setControl(
                     new InsetsSourceControl(ID_STATUS_BAR, statusBars(), mLeash,
                             false /* initialVisible */, new Point(), Insets.NONE),
-                    new int[1], hideTypes);
+                    new int[1], hideTypes, new int[1]);
             assertTrue(mRemoveSurfaceCalled);
             assertEquals(0, hideTypes[0]);
         });
@@ -235,7 +251,8 @@
 
             // Initial IME insets source control with its leash.
             imeConsumer.setControl(new InsetsSourceControl(ID_IME, ime(), mLeash,
-                    false /* initialVisible */, new Point(), Insets.NONE), new int[1], new int[1]);
+                    false /* initialVisible */, new Point(), Insets.NONE), new int[1], new int[1],
+                    new int[1]);
             mSurfaceParamsApplied = false;
 
             // Verify when the app requests controlling show IME animation, the IME leash
@@ -244,7 +261,8 @@
                     null /* interpolator */, null /* cancellationSignal */, null /* listener */);
             assertEquals(ANIMATION_TYPE_USER, insetsController.getAnimationType(ime()));
             imeConsumer.setControl(new InsetsSourceControl(ID_IME, ime(), mLeash,
-                    true /* initialVisible */, new Point(), Insets.NONE), new int[1], new int[1]);
+                    true /* initialVisible */, new Point(), Insets.NONE), new int[1], new int[1],
+                    new int[1]);
             assertFalse(mSurfaceParamsApplied);
         });
     }
diff --git a/core/tests/coretests/src/android/view/accessibility/AccessibilityNodeInfoTest.java b/core/tests/coretests/src/android/view/accessibility/AccessibilityNodeInfoTest.java
index 6e563ff..da202b6 100644
--- a/core/tests/coretests/src/android/view/accessibility/AccessibilityNodeInfoTest.java
+++ b/core/tests/coretests/src/android/view/accessibility/AccessibilityNodeInfoTest.java
@@ -46,7 +46,7 @@
     // The number of fields tested in the corresponding CTS AccessibilityNodeInfoTest:
     // See fullyPopulateAccessibilityNodeInfo, assertEqualsAccessibilityNodeInfo,
     // and assertAccessibilityNodeInfoCleared in that class.
-    private static final int NUM_MARSHALLED_PROPERTIES = 44;
+    private static final int NUM_MARSHALLED_PROPERTIES = 45;
 
     /**
      * The number of properties that are purposely not marshalled
diff --git a/core/tests/coretests/src/android/window/BackTouchTrackerTest.kt b/core/tests/coretests/src/android/window/BackTouchTrackerTest.kt
index b7bccd4..381b566 100644
--- a/core/tests/coretests/src/android/window/BackTouchTrackerTest.kt
+++ b/core/tests/coretests/src/android/window/BackTouchTrackerTest.kt
@@ -46,45 +46,43 @@
         val linearTracker = linearTouchTracker()
         linearTracker.setGestureStartLocation(INITIAL_X_LEFT_EDGE, 0f, BackEvent.EDGE_LEFT)
         var touchX = 10f
-        val velocityX = 0f
-        val velocityY = 0f
 
         // Pre-commit
-        linearTracker.update(touchX, 0f, velocityX, velocityY)
+        linearTracker.update(touchX, 0f)
         linearTracker.assertProgress((touchX - INITIAL_X_LEFT_EDGE) / MAX_DISTANCE)
 
         // Post-commit
         touchX += 100f
         linearTracker.setTriggerBack(true)
-        linearTracker.update(touchX, 0f, velocityX, velocityY)
+        linearTracker.update(touchX, 0f)
         linearTracker.assertProgress((touchX - INITIAL_X_LEFT_EDGE) / MAX_DISTANCE)
 
         // Cancel
         touchX -= 10f
         linearTracker.setTriggerBack(false)
-        linearTracker.update(touchX, 0f, velocityX, velocityY)
+        linearTracker.update(touchX, 0f)
         linearTracker.assertProgress(0f)
 
         // Cancel more
         touchX -= 10f
-        linearTracker.update(touchX, 0f, velocityX, velocityY)
+        linearTracker.update(touchX, 0f)
         linearTracker.assertProgress(0f)
 
         // Restarted, but pre-commit
         val restartX = touchX
         touchX += 10f
-        linearTracker.update(touchX, 0f, velocityX, velocityY)
+        linearTracker.update(touchX, 0f)
         linearTracker.assertProgress((touchX - restartX) / MAX_DISTANCE)
 
         // continue restart within pre-commit
         touchX += 10f
-        linearTracker.update(touchX, 0f, velocityX, velocityY)
+        linearTracker.update(touchX, 0f)
         linearTracker.assertProgress((touchX - restartX) / MAX_DISTANCE)
 
         // Restarted, post-commit
         touchX += 10f
         linearTracker.setTriggerBack(true)
-        linearTracker.update(touchX, 0f, velocityX, velocityY)
+        linearTracker.update(touchX, 0f)
         linearTracker.assertProgress((touchX - INITIAL_X_LEFT_EDGE) / MAX_DISTANCE)
     }
 
@@ -93,46 +91,44 @@
         val linearTracker = linearTouchTracker()
         linearTracker.setGestureStartLocation(INITIAL_X_RIGHT_EDGE, 0f, BackEvent.EDGE_RIGHT)
         var touchX = INITIAL_X_RIGHT_EDGE - 10 // Fake right edge
-        val velocityX = 0f
-        val velocityY = 0f
         val target = MAX_DISTANCE
 
         // Pre-commit
-        linearTracker.update(touchX, 0f, velocityX, velocityY)
+        linearTracker.update(touchX, 0f)
         linearTracker.assertProgress((INITIAL_X_RIGHT_EDGE - touchX) / target)
 
         // Post-commit
         touchX -= 100f
         linearTracker.setTriggerBack(true)
-        linearTracker.update(touchX, 0f, velocityX, velocityY)
+        linearTracker.update(touchX, 0f)
         linearTracker.assertProgress((INITIAL_X_RIGHT_EDGE - touchX) / target)
 
         // Cancel
         touchX += 10f
         linearTracker.setTriggerBack(false)
-        linearTracker.update(touchX, 0f, velocityX, velocityY)
+        linearTracker.update(touchX, 0f)
         linearTracker.assertProgress(0f)
 
         // Cancel more
         touchX += 10f
-        linearTracker.update(touchX, 0f, velocityX, velocityY)
+        linearTracker.update(touchX, 0f)
         linearTracker.assertProgress(0f)
 
         // Restarted, but pre-commit
         val restartX = touchX
         touchX -= 10f
-        linearTracker.update(touchX, 0f, velocityX, velocityY)
+        linearTracker.update(touchX, 0f)
         linearTracker.assertProgress((restartX - touchX) / target)
 
         // continue restart within pre-commit
         touchX -= 10f
-        linearTracker.update(touchX, 0f, velocityX, velocityY)
+        linearTracker.update(touchX, 0f)
         linearTracker.assertProgress((restartX - touchX) / target)
 
         // Restarted, post-commit
         touchX -= 10f
         linearTracker.setTriggerBack(true)
-        linearTracker.update(touchX, 0f, velocityX, velocityY)
+        linearTracker.update(touchX, 0f)
         linearTracker.assertProgress((INITIAL_X_RIGHT_EDGE - touchX) / target)
     }
 
@@ -141,28 +137,26 @@
         val nonLinearTracker = nonLinearTouchTracker()
         nonLinearTracker.setGestureStartLocation(INITIAL_X_LEFT_EDGE, 0f, BackEvent.EDGE_LEFT)
         var touchX = 10f
-        val velocityX = 0f
-        val velocityY = 0f
         val linearTarget = LINEAR_DISTANCE + (MAX_DISTANCE - LINEAR_DISTANCE) * NON_LINEAR_FACTOR
 
         // Pre-commit: linear progress
-        nonLinearTracker.update(touchX, 0f, velocityX, velocityY)
+        nonLinearTracker.update(touchX, 0f)
         nonLinearTracker.assertProgress((touchX - INITIAL_X_LEFT_EDGE) / linearTarget)
 
         // Post-commit: still linear progress
         touchX += 100f
         nonLinearTracker.setTriggerBack(true)
-        nonLinearTracker.update(touchX, 0f, velocityX, velocityY)
+        nonLinearTracker.update(touchX, 0f)
         nonLinearTracker.assertProgress((touchX - INITIAL_X_LEFT_EDGE) / linearTarget)
 
         // still linear progress
         touchX = INITIAL_X_LEFT_EDGE + LINEAR_DISTANCE
-        nonLinearTracker.update(touchX, 0f, velocityX, velocityY)
+        nonLinearTracker.update(touchX, 0f)
         nonLinearTracker.assertProgress((touchX - INITIAL_X_LEFT_EDGE) / linearTarget)
 
         // non linear progress
         touchX += 10
-        nonLinearTracker.update(touchX, 0f, velocityX, velocityY)
+        nonLinearTracker.update(touchX, 0f)
         val nonLinearTouch = (touchX - INITIAL_X_LEFT_EDGE) - LINEAR_DISTANCE
         val nonLinearProgress = nonLinearTouch / NON_LINEAR_DISTANCE
         val nonLinearTarget = MathUtils.lerp(linearTarget, MAX_DISTANCE, nonLinearProgress)
@@ -178,7 +172,7 @@
         val velocityY = 0f
 
         // assert that progress is increased when increasing touchX
-        linearTracker.update(touchX, 0f, velocityX, velocityY)
+        linearTracker.update(touchX, 0f)
         linearTracker.assertProgress((touchX - INITIAL_X_LEFT_EDGE) / MAX_DISTANCE)
 
         // assert that progress is reset to 0 when start location is updated
@@ -187,13 +181,13 @@
 
         // assert that progress remains 0 when touchX is decreased
         touchX -= 50
-        linearTracker.update(touchX, 0f, velocityX, velocityY)
+        linearTracker.update(touchX, 0f)
         linearTracker.assertProgress(0f)
 
         // assert that progress uses new minimal touchX for progress calculation
         val newInitialTouchX = touchX
         touchX += 100
-        linearTracker.update(touchX, 0f, velocityX, velocityY)
+        linearTracker.update(touchX, 0f)
         linearTracker.assertProgress((touchX - newInitialTouchX) / MAX_DISTANCE)
 
         // assert the same for triggerBack==true
@@ -207,11 +201,8 @@
         linearTracker.setGestureStartLocation(INITIAL_X_RIGHT_EDGE, 0f, BackEvent.EDGE_RIGHT)
 
         var touchX = INITIAL_X_RIGHT_EDGE - 100f
-        val velocityX = 0f
-        val velocityY = 0f
-
         // assert that progress is increased when decreasing touchX
-        linearTracker.update(touchX, 0f, velocityX, velocityY)
+        linearTracker.update(touchX, 0f)
         linearTracker.assertProgress((INITIAL_X_RIGHT_EDGE - touchX) / MAX_DISTANCE)
 
         // assert that progress is reset to 0 when start location is updated
@@ -220,13 +211,13 @@
 
         // assert that progress remains 0 when touchX is increased
         touchX += 50
-        linearTracker.update(touchX, 0f, velocityX, velocityY)
+        linearTracker.update(touchX, 0f)
         linearTracker.assertProgress(0f)
 
         // assert that progress uses new maximal touchX for progress calculation
         val newInitialTouchX = touchX
         touchX -= 100
-        linearTracker.update(touchX, 0f, velocityX, velocityY)
+        linearTracker.update(touchX, 0f)
         linearTracker.assertProgress((newInitialTouchX - touchX) / MAX_DISTANCE)
 
         // assert the same for triggerBack==true
diff --git a/core/tests/coretests/src/android/window/flags/DesktopModeFlagsTest.java b/core/tests/coretests/src/android/window/DesktopModeFlagsTest.java
similarity index 88%
rename from core/tests/coretests/src/android/window/flags/DesktopModeFlagsTest.java
rename to core/tests/coretests/src/android/window/DesktopModeFlagsTest.java
index a311d0d..b28e2b0 100644
--- a/core/tests/coretests/src/android/window/flags/DesktopModeFlagsTest.java
+++ b/core/tests/coretests/src/android/window/DesktopModeFlagsTest.java
@@ -14,13 +14,14 @@
  * limitations under the License.
  */
 
-package android.window.flags;
+package android.window;
 
-import static android.window.flags.DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_MODE;
-import static android.window.flags.DesktopModeFlags.ToggleOverride.OVERRIDE_OFF;
-import static android.window.flags.DesktopModeFlags.ToggleOverride.OVERRIDE_ON;
-import static android.window.flags.DesktopModeFlags.ToggleOverride.OVERRIDE_UNSET;
-import static android.window.flags.DesktopModeFlags.ToggleOverride.fromSetting;
+import static android.window.DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_MODE;
+import static android.window.DesktopModeFlags.ToggleOverride.OVERRIDE_OFF;
+import static android.window.DesktopModeFlags.ToggleOverride.OVERRIDE_ON;
+import static android.window.DesktopModeFlags.ToggleOverride.OVERRIDE_UNSET;
+import static android.window.DesktopModeFlags.ToggleOverride.fromSetting;
+import static android.window.DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_TRANSITIONS;
 
 import static com.android.window.flags.Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE;
 import static com.android.window.flags.Flags.FLAG_ENABLE_DESKTOP_WINDOWING_TRANSITIONS;
@@ -40,6 +41,7 @@
 import androidx.test.filters.SmallTest;
 import androidx.test.platform.app.InstrumentationRegistry;
 
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
@@ -48,7 +50,7 @@
 import java.lang.reflect.Field;
 
 /**
- * Test class for {@link DesktopModeFlags}
+ * Test class for {@link android.window.DesktopModeFlags}
  *
  * Build/Install/Run:
  * atest FrameworksCoreTests:DesktopModeFlagsTest
@@ -68,8 +70,12 @@
     private static final int OVERRIDE_UNSET_SETTING = -1;
 
     @Before
-    public void setUp() throws Exception {
+    public void setUp() {
         mContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
+    }
+
+    @After
+    public void tearDown() throws Exception {
         resetCache();
     }
 
@@ -203,7 +209,7 @@
         setOverride(OVERRIDE_UNSET_SETTING);
 
         // For unset overrides, follow flag
-        assertThat(DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_TRANSITIONS.isTrue()).isTrue();
+        assertThat(ENABLE_DESKTOP_WINDOWING_TRANSITIONS.isTrue()).isTrue();
     }
 
     @Test
@@ -212,7 +218,7 @@
     public void isTrue_dwFlagOn_overrideUnset_featureFlagOff_returnsFalse() {
         setOverride(OVERRIDE_UNSET_SETTING);
         // For unset overrides, follow flag
-        assertThat(DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_TRANSITIONS.isTrue()).isFalse();
+        assertThat(ENABLE_DESKTOP_WINDOWING_TRANSITIONS.isTrue()).isFalse();
     }
 
     @Test
@@ -225,7 +231,7 @@
         setOverride(OVERRIDE_ON_SETTING);
 
         // When toggle override matches its default state (dw flag), don't override flags
-        assertThat(DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_TRANSITIONS.isTrue()).isTrue();
+        assertThat(ENABLE_DESKTOP_WINDOWING_TRANSITIONS.isTrue()).isTrue();
     }
 
     @Test
@@ -235,7 +241,7 @@
         setOverride(OVERRIDE_ON_SETTING);
 
         // When toggle override matches its default state (dw flag), don't override flags
-        assertThat(DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_TRANSITIONS.isTrue()).isFalse();
+        assertThat(ENABLE_DESKTOP_WINDOWING_TRANSITIONS.isTrue()).isFalse();
     }
 
     @Test
@@ -248,7 +254,7 @@
         setOverride(OVERRIDE_OFF_SETTING);
 
         // Follow override if they exist, and is not equal to default toggle state (dw flag)
-        assertThat(DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_TRANSITIONS.isTrue()).isTrue();
+        assertThat(ENABLE_DESKTOP_WINDOWING_TRANSITIONS.isTrue()).isTrue();
     }
 
     @Test
@@ -258,7 +264,7 @@
         setOverride(OVERRIDE_OFF_SETTING);
 
         // Follow override if they exist, and is not equal to default toggle state (dw flag)
-        assertThat(DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_TRANSITIONS.isTrue()).isFalse();
+        assertThat(ENABLE_DESKTOP_WINDOWING_TRANSITIONS.isTrue()).isFalse();
     }
 
     @Test
@@ -271,7 +277,7 @@
         setOverride(OVERRIDE_UNSET_SETTING);
 
         // For unset overrides, follow flag
-        assertThat(DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_TRANSITIONS.isTrue()).isTrue();
+        assertThat(ENABLE_DESKTOP_WINDOWING_TRANSITIONS.isTrue()).isTrue();
     }
 
     @Test
@@ -284,7 +290,7 @@
         setOverride(OVERRIDE_UNSET_SETTING);
 
         // For unset overrides, follow flag
-        assertThat(DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_TRANSITIONS.isTrue()).isFalse();
+        assertThat(ENABLE_DESKTOP_WINDOWING_TRANSITIONS.isTrue()).isFalse();
     }
 
     @Test
@@ -297,7 +303,7 @@
         setOverride(OVERRIDE_ON_SETTING);
 
         // Follow override if they exist, and is not equal to default toggle state (dw flag)
-        assertThat(DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_TRANSITIONS.isTrue()).isTrue();
+        assertThat(ENABLE_DESKTOP_WINDOWING_TRANSITIONS.isTrue()).isTrue();
     }
 
     @Test
@@ -310,7 +316,7 @@
         setOverride(OVERRIDE_ON_SETTING);
 
         // Follow override if they exist, and is not equal to default toggle state (dw flag)
-        assertThat(DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_TRANSITIONS.isTrue()).isFalse();
+        assertThat(ENABLE_DESKTOP_WINDOWING_TRANSITIONS.isTrue()).isFalse();
     }
 
     @Test
@@ -323,7 +329,7 @@
         setOverride(OVERRIDE_OFF_SETTING);
 
         // When toggle override matches its default state (dw flag), don't override flags
-        assertThat(DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_TRANSITIONS.isTrue()).isTrue();
+        assertThat(ENABLE_DESKTOP_WINDOWING_TRANSITIONS.isTrue()).isTrue();
     }
 
     @Test
@@ -336,7 +342,7 @@
         setOverride(OVERRIDE_OFF_SETTING);
 
         // When toggle override matches its default state (dw flag), don't override flags
-        assertThat(DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_TRANSITIONS.isTrue()).isFalse();
+        assertThat(ENABLE_DESKTOP_WINDOWING_TRANSITIONS.isTrue()).isFalse();
     }
 
     @Test
@@ -375,5 +381,6 @@
                 "sCachedToggleOverride");
         cachedToggleOverride.setAccessible(true);
         cachedToggleOverride.set(null, null);
+        setOverride(OVERRIDE_UNSET_SETTING);
     }
 }
diff --git a/core/tests/coretests/src/android/window/WindowOnBackInvokedDispatcherTest.java b/core/tests/coretests/src/android/window/WindowOnBackInvokedDispatcherTest.java
index 0a4c5e6..b001cc2 100644
--- a/core/tests/coretests/src/android/window/WindowOnBackInvokedDispatcherTest.java
+++ b/core/tests/coretests/src/android/window/WindowOnBackInvokedDispatcherTest.java
@@ -586,13 +586,13 @@
 
     @Test(expected = IllegalArgumentException.class)
     @RequiresFlagsDisabled(FLAG_PREDICTIVE_BACK_PRIORITY_SYSTEM_NAVIGATION_OBSERVER)
-    public void testNoUiCallback_registrationFailsWithoutFlaggedApiEnabled() {
+    public void testObserverCallback_registrationFailsWithoutFlaggedApiEnabled() {
         mDispatcher.registerOnBackInvokedCallback(PRIORITY_SYSTEM_NAVIGATION_OBSERVER, mCallback2);
     }
 
     @Test
     @RequiresFlagsEnabled(FLAG_PREDICTIVE_BACK_PRIORITY_SYSTEM_NAVIGATION_OBSERVER)
-    public void testNoUiCallback_invokedWithSystemCallback() throws RemoteException {
+    public void testObserverCallback_invokedWithSystemCallback() throws RemoteException {
         mDispatcher.registerSystemOnBackInvokedCallback(mCallback1);
         mDispatcher.registerOnBackInvokedCallback(PRIORITY_SYSTEM_NAVIGATION_OBSERVER, mCallback2);
 
@@ -607,7 +607,7 @@
 
         callbackInfo.getCallback().onBackProgressed(mBackEvent);
         waitForIdle();
-        verify(mCallback1).onBackProgressed(any());
+        verify(mCallback1, atLeast(1)).onBackProgressed(any());
         verify(mCallback2, never()).onBackProgressed(any());
 
         callbackInfo.getCallback().onBackCancelled();
@@ -625,7 +625,7 @@
 
     @Test
     @RequiresFlagsEnabled(FLAG_PREDICTIVE_BACK_PRIORITY_SYSTEM_NAVIGATION_OBSERVER)
-    public void testNoUiCallback_notInvokedWithNonSystemCallback() throws RemoteException {
+    public void testObserverCallback_notInvokedWithNonSystemCallback() throws RemoteException {
         mDispatcher.registerOnBackInvokedCallback(PRIORITY_DEFAULT, mCallback1);
         mDispatcher.registerOnBackInvokedCallback(PRIORITY_SYSTEM_NAVIGATION_OBSERVER, mCallback2);
 
@@ -640,7 +640,7 @@
 
         callbackInfo.getCallback().onBackProgressed(mBackEvent);
         waitForIdle();
-        verify(mCallback1).onBackProgressed(any());
+        verify(mCallback1, atLeast(1)).onBackProgressed(any());
         verify(mCallback2, never()).onBackProgressed(any());
 
         callbackInfo.getCallback().onBackCancelled();
@@ -658,7 +658,7 @@
 
     @Test
     @RequiresFlagsEnabled(FLAG_PREDICTIVE_BACK_PRIORITY_SYSTEM_NAVIGATION_OBSERVER)
-    public void testNoUiCallback_reregistrations() {
+    public void testObserverCallback_reregistrations() {
         mDispatcher.registerOnBackInvokedCallback(PRIORITY_SYSTEM_NAVIGATION_OBSERVER, mCallback1);
         assertCallbacksSize(/* default */ 0, /* overlay */ 0, /* observer */ 1);
         assertEquals(mCallback1, mDispatcher.mSystemNavigationObserverCallback);
@@ -685,8 +685,6 @@
                 /* touchX = */ 0,
                 /* touchY = */ 0,
                 /* progress = */ progress,
-                /* velocityX = */ 0,
-                /* velocityY = */ 0,
                 /* triggerBack = */ false,
                 /* swipeEdge = */ BackEvent.EDGE_LEFT,
                 /* departingAnimationTarget = */ null);
diff --git a/core/tests/coretests/src/com/android/internal/accessibility/dialog/AccessibilityServiceWarningTest.java b/core/tests/coretests/src/com/android/internal/accessibility/dialog/AccessibilityServiceWarningTest.java
index 362eeea..8e906fd 100644
--- a/core/tests/coretests/src/com/android/internal/accessibility/dialog/AccessibilityServiceWarningTest.java
+++ b/core/tests/coretests/src/com/android/internal/accessibility/dialog/AccessibilityServiceWarningTest.java
@@ -25,6 +25,8 @@
 import android.app.AlertDialog;
 import android.content.Context;
 import android.os.RemoteException;
+import android.platform.test.annotations.RequiresFlagsDisabled;
+import android.platform.test.annotations.RequiresFlagsEnabled;
 import android.platform.test.flag.junit.CheckFlagsRule;
 import android.platform.test.flag.junit.DeviceFlagsValueProvider;
 import android.testing.AndroidTestingRunner;
@@ -33,6 +35,7 @@
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.Window;
+import android.view.accessibility.Flags;
 import android.widget.TextView;
 
 import androidx.test.platform.app.InstrumentationRegistry;
@@ -89,7 +92,19 @@
     }
 
     @Test
-    public void createAccessibilityServiceWarningDialog_hasExpectedWindowParams() {
+    @RequiresFlagsDisabled(Flags.FLAG_WARNING_USE_DEFAULT_DIALOG_TYPE)
+    public void createAccessibilityServiceWarningDialog_hasExpectedWindowParams_isSystemDialog() {
+        createAccessibilityServiceWarningDialog_hasExpectedWindowParams(true);
+    }
+
+    @Test
+    @RequiresFlagsEnabled(Flags.FLAG_WARNING_USE_DEFAULT_DIALOG_TYPE)
+    public void createAccessibilityServiceWarningDialog_hasExpectedWindowParams_notSystemDialog() {
+        createAccessibilityServiceWarningDialog_hasExpectedWindowParams(false);
+    }
+
+    private void createAccessibilityServiceWarningDialog_hasExpectedWindowParams(
+            boolean expectSystemDialog) {
         final AlertDialog dialog =
                 AccessibilityServiceWarning.createAccessibilityServiceWarningDialog(
                         mContext,
@@ -101,7 +116,11 @@
         expect.that(dialogWindow.getAttributes().privateFlags
                 & SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS).isEqualTo(
                 SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);
-        expect.that(dialogWindow.getAttributes().type).isEqualTo(TYPE_SYSTEM_DIALOG);
+        if (expectSystemDialog) {
+            expect.that(dialogWindow.getAttributes().type).isEqualTo(TYPE_SYSTEM_DIALOG);
+        } else {
+            expect.that(dialogWindow.getAttributes().type).isNotEqualTo(TYPE_SYSTEM_DIALOG);
+        }
     }
 
     @Test
diff --git a/core/tests/coretests/src/com/android/internal/widget/NotificationProgressBarTest.java b/core/tests/coretests/src/com/android/internal/widget/NotificationProgressBarTest.java
new file mode 100644
index 0000000..6419c1e0
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/widget/NotificationProgressBarTest.java
@@ -0,0 +1,302 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.widget;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.app.Notification.ProgressStyle;
+import android.graphics.Color;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import com.android.internal.widget.NotificationProgressDrawable.Part;
+import com.android.internal.widget.NotificationProgressDrawable.Point;
+import com.android.internal.widget.NotificationProgressDrawable.Segment;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@RunWith(AndroidJUnit4.class)
+public class NotificationProgressBarTest {
+
+    @Test(expected = IllegalArgumentException.class)
+    public void processAndConvertToDrawableParts_segmentsIsEmpty() {
+        List<ProgressStyle.Segment> segments = new ArrayList<>();
+        List<ProgressStyle.Point> points = new ArrayList<>();
+        int progress = 50;
+        boolean isStyledByProgress = true;
+
+        NotificationProgressBar.processAndConvertToDrawableParts(segments, points, progress,
+                isStyledByProgress);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void processAndConvertToDrawableParts_segmentLengthIsNegative() {
+        List<ProgressStyle.Segment> segments = new ArrayList<>();
+        segments.add(new ProgressStyle.Segment(-50));
+        List<ProgressStyle.Point> points = new ArrayList<>();
+        int progress = 50;
+        boolean isStyledByProgress = true;
+
+        NotificationProgressBar.processAndConvertToDrawableParts(segments, points, progress,
+                isStyledByProgress);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void processAndConvertToDrawableParts_segmentLengthIsZero() {
+        List<ProgressStyle.Segment> segments = new ArrayList<>();
+        segments.add(new ProgressStyle.Segment(0));
+        List<ProgressStyle.Point> points = new ArrayList<>();
+        int progress = 50;
+        boolean isStyledByProgress = true;
+
+        NotificationProgressBar.processAndConvertToDrawableParts(segments, points, progress,
+                isStyledByProgress);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void processAndConvertToDrawableParts_progressIsNegative() {
+        List<ProgressStyle.Segment> segments = new ArrayList<>();
+        segments.add(new ProgressStyle.Segment(100));
+        List<ProgressStyle.Point> points = new ArrayList<>();
+        int progress = -50;
+        boolean isStyledByProgress = true;
+
+        NotificationProgressBar.processAndConvertToDrawableParts(segments, points, progress,
+                isStyledByProgress);
+    }
+
+    @Test
+    public void processAndConvertToDrawableParts_progressIsZero() {
+        List<ProgressStyle.Segment> segments = new ArrayList<>();
+        segments.add(new ProgressStyle.Segment(100).setColor(Color.RED));
+        List<ProgressStyle.Point> points = new ArrayList<>();
+        int progress = 0;
+        boolean isStyledByProgress = true;
+
+        List<Part> parts = NotificationProgressBar.processAndConvertToDrawableParts(
+                segments, points, progress, isStyledByProgress);
+
+        int fadedRed = 0x7FFF0000;
+        List<Part> expected = new ArrayList<>(List.of(new Segment(1f, fadedRed, true)));
+
+        assertThat(parts).isEqualTo(expected);
+    }
+
+    @Test
+    public void processAndConvertToDrawableParts_progressAtMax() {
+        List<ProgressStyle.Segment> segments = new ArrayList<>();
+        segments.add(new ProgressStyle.Segment(100).setColor(Color.RED));
+        List<ProgressStyle.Point> points = new ArrayList<>();
+        int progress = 100;
+        boolean isStyledByProgress = true;
+
+        List<Part> parts = NotificationProgressBar.processAndConvertToDrawableParts(
+                segments, points, progress, isStyledByProgress);
+
+        List<Part> expected = new ArrayList<>(List.of(new Segment(1f, Color.RED)));
+
+        assertThat(parts).isEqualTo(expected);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void processAndConvertToDrawableParts_progressAboveMax() {
+        List<ProgressStyle.Segment> segments = new ArrayList<>();
+        segments.add(new ProgressStyle.Segment(100));
+        List<ProgressStyle.Point> points = new ArrayList<>();
+        int progress = 150;
+        boolean isStyledByProgress = true;
+
+        NotificationProgressBar.processAndConvertToDrawableParts(segments, points, progress,
+                isStyledByProgress);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void processAndConvertToDrawableParts_pointPositionIsNegative() {
+        List<ProgressStyle.Segment> segments = new ArrayList<>();
+        segments.add(new ProgressStyle.Segment(100));
+        List<ProgressStyle.Point> points = new ArrayList<>();
+        points.add(new ProgressStyle.Point(-50).setColor(Color.RED));
+        int progress = 50;
+        boolean isStyledByProgress = true;
+
+        NotificationProgressBar.processAndConvertToDrawableParts(segments, points, progress,
+                isStyledByProgress);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void processAndConvertToDrawableParts_pointPositionIsZero() {
+        List<ProgressStyle.Segment> segments = new ArrayList<>();
+        segments.add(new ProgressStyle.Segment(100));
+        List<ProgressStyle.Point> points = new ArrayList<>();
+        points.add(new ProgressStyle.Point(0).setColor(Color.RED));
+        int progress = 50;
+        boolean isStyledByProgress = true;
+
+        NotificationProgressBar.processAndConvertToDrawableParts(segments, points, progress,
+                isStyledByProgress);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void processAndConvertToDrawableParts_pointPositionAtMax() {
+        List<ProgressStyle.Segment> segments = new ArrayList<>();
+        segments.add(new ProgressStyle.Segment(100));
+        List<ProgressStyle.Point> points = new ArrayList<>();
+        points.add(new ProgressStyle.Point(100).setColor(Color.RED));
+        int progress = 50;
+        boolean isStyledByProgress = true;
+
+        NotificationProgressBar.processAndConvertToDrawableParts(segments, points, progress,
+                isStyledByProgress);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void processAndConvertToDrawableParts_pointPositionAboveMax() {
+        List<ProgressStyle.Segment> segments = new ArrayList<>();
+        segments.add(new ProgressStyle.Segment(100));
+        List<ProgressStyle.Point> points = new ArrayList<>();
+        points.add(new ProgressStyle.Point(150).setColor(Color.RED));
+        int progress = 50;
+        boolean isStyledByProgress = true;
+
+        NotificationProgressBar.processAndConvertToDrawableParts(segments, points, progress,
+                isStyledByProgress);
+    }
+
+    @Test
+    public void processAndConvertToDrawableParts_multipleSegmentsWithoutPoints() {
+        List<ProgressStyle.Segment> segments = new ArrayList<>();
+        segments.add(new ProgressStyle.Segment(50).setColor(Color.RED));
+        segments.add(new ProgressStyle.Segment(50).setColor(Color.GREEN));
+        List<ProgressStyle.Point> points = new ArrayList<>();
+        int progress = 60;
+        boolean isStyledByProgress = true;
+
+        List<Part> parts = NotificationProgressBar.processAndConvertToDrawableParts(
+                segments, points, progress, isStyledByProgress);
+
+        // Colors with 50% opacity
+        int fadedGreen = 0x7F00FF00;
+
+        List<Part> expected = new ArrayList<>(List.of(
+                new Segment(0.50f, Color.RED),
+                new Segment(0.10f, Color.GREEN),
+                new Segment(0.40f, fadedGreen, true)));
+
+        assertThat(parts).isEqualTo(expected);
+    }
+
+    @Test
+    public void processAndConvertToDrawableParts_singleSegmentWithPoints() {
+        List<ProgressStyle.Segment> segments = new ArrayList<>();
+        segments.add(new ProgressStyle.Segment(100).setColor(Color.BLUE));
+        List<ProgressStyle.Point> points = new ArrayList<>();
+        points.add(new ProgressStyle.Point(15).setColor(Color.RED));
+        points.add(new ProgressStyle.Point(25).setColor(Color.BLUE));
+        points.add(new ProgressStyle.Point(60).setColor(Color.BLUE));
+        points.add(new ProgressStyle.Point(75).setColor(Color.YELLOW));
+        int progress = 60;
+        boolean isStyledByProgress = true;
+
+        // Colors with 50% opacity
+        int fadedBlue = 0x7F0000FF;
+        int fadedYellow = 0x7FFFFF00;
+
+        List<Part> expected = new ArrayList<>(List.of(
+                new Segment(0.15f, Color.BLUE),
+                new Point(null, Color.RED),
+                new Segment(0.10f, Color.BLUE),
+                new Point(null, Color.BLUE),
+                new Segment(0.35f, Color.BLUE),
+                new Point(null, Color.BLUE),
+                new Segment(0.15f, fadedBlue, true),
+                new Point(null, fadedYellow, true),
+                new Segment(0.25f, fadedBlue, true)));
+
+        List<Part> parts = NotificationProgressBar.processAndConvertToDrawableParts(
+                segments, points, progress, isStyledByProgress);
+
+        assertThat(parts).isEqualTo(expected);
+    }
+
+    @Test
+    public void processAndConvertToDrawableParts_multipleSegmentsWithPoints() {
+        List<ProgressStyle.Segment> segments = new ArrayList<>();
+        segments.add(new ProgressStyle.Segment(50).setColor(Color.RED));
+        segments.add(new ProgressStyle.Segment(50).setColor(Color.GREEN));
+        List<ProgressStyle.Point> points = new ArrayList<>();
+        points.add(new ProgressStyle.Point(15).setColor(Color.RED));
+        points.add(new ProgressStyle.Point(25).setColor(Color.BLUE));
+        points.add(new ProgressStyle.Point(60).setColor(Color.BLUE));
+        points.add(new ProgressStyle.Point(75).setColor(Color.YELLOW));
+        int progress = 60;
+        boolean isStyledByProgress = true;
+
+        List<Part> parts = NotificationProgressBar.processAndConvertToDrawableParts(
+                segments, points, progress, isStyledByProgress);
+
+        // Colors with 50% opacity
+        int fadedGreen = 0x7F00FF00;
+        int fadedBlue = 0x7F0000FF;
+        int fadedYellow = 0x7FFFFF00;
+
+        List<Part> expected = new ArrayList<>(List.of(
+                new Segment(0.15f, Color.RED),
+                new Point(null, Color.RED),
+                new Segment(0.10f, Color.RED),
+                new Point(null, Color.BLUE),
+                new Segment(0.25f, Color.RED),
+                new Segment(0.10f, Color.GREEN),
+                new Point(null, Color.BLUE),
+                new Segment(0.15f, fadedGreen, true),
+                new Point(null, fadedYellow, true),
+                new Segment(0.25f, fadedGreen, true)));
+
+        assertThat(parts).isEqualTo(expected);
+    }
+
+    @Test
+    public void processAndConvertToDrawableParts_multipleSegmentsWithPoints_notStyledByProgress() {
+        List<ProgressStyle.Segment> segments = new ArrayList<>();
+        segments.add(new ProgressStyle.Segment(50).setColor(Color.RED));
+        segments.add(new ProgressStyle.Segment(50).setColor(Color.GREEN));
+        List<ProgressStyle.Point> points = new ArrayList<>();
+        points.add(new ProgressStyle.Point(15).setColor(Color.RED));
+        points.add(new ProgressStyle.Point(25).setColor(Color.BLUE));
+        points.add(new ProgressStyle.Point(75).setColor(Color.YELLOW));
+        int progress = 60;
+        boolean isStyledByProgress = false;
+
+        List<Part> parts = NotificationProgressBar.processAndConvertToDrawableParts(
+                segments, points, progress, isStyledByProgress);
+
+        List<Part> expected = new ArrayList<>(List.of(
+                new Segment(0.15f, Color.RED),
+                new Point(null, Color.RED),
+                new Segment(0.10f, Color.RED),
+                new Point(null, Color.BLUE),
+                new Segment(0.25f, Color.RED),
+                new Segment(0.25f, Color.GREEN),
+                new Point(null, Color.YELLOW),
+                new Segment(0.25f, Color.GREEN)));
+
+        assertThat(parts).isEqualTo(expected);
+    }
+}
diff --git a/core/tests/coretests/src/com/android/internal/widget/NotificationProgressModelTest.java b/core/tests/coretests/src/com/android/internal/widget/NotificationProgressModelTest.java
new file mode 100644
index 0000000..962399e
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/widget/NotificationProgressModelTest.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.widget;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.app.Flags;
+import android.app.Notification;
+import android.graphics.Color;
+import android.os.Bundle;
+import android.platform.test.annotations.EnableFlags;
+import android.platform.test.flag.junit.SetFlagsRule;
+
+import androidx.test.filters.SmallTest;
+
+import org.junit.Rule;
+import org.junit.Test;
+
+import java.util.List;
+
+@SmallTest
+@EnableFlags(Flags.FLAG_API_RICH_ONGOING)
+public class NotificationProgressModelTest {
+
+    @Rule
+    public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+
+    @Test(expected = IllegalArgumentException.class)
+    public void throw_exception_on_transparent_indeterminate_color() {
+        new NotificationProgressModel(Color.TRANSPARENT);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void throw_exception_on_empty_segments() {
+        new NotificationProgressModel(List.of(),
+                List.of(),
+                10,
+                false);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void throw_exception_on_negative_progress() {
+        new NotificationProgressModel(
+                List.of(new Notification.ProgressStyle.Segment(50).setColor(Color.YELLOW)),
+                List.of(),
+                -1,
+                false);
+    }
+
+    @Test
+    public void save_and_restore_indeterminate_progress_model() {
+        // GIVEN
+        final NotificationProgressModel savedModel = new NotificationProgressModel(Color.RED);
+        final Bundle bundle = savedModel.toBundle();
+
+        // WHEN
+        final NotificationProgressModel restoredModel =
+                NotificationProgressModel.fromBundle(bundle);
+
+        // THEN
+        assertThat(restoredModel.getIndeterminateColor()).isEqualTo(Color.RED);
+        assertThat(restoredModel.isIndeterminate()).isTrue();
+        assertThat(restoredModel.getProgress()).isEqualTo(-1);
+        assertThat(restoredModel.getSegments()).isEmpty();
+        assertThat(restoredModel.getPoints()).isEmpty();
+        assertThat(restoredModel.isStyledByProgress()).isFalse();
+    }
+
+    @Test
+    public void save_and_restore_non_indeterminate_progress_model() {
+        // GIVEN
+        final List<Notification.ProgressStyle.Segment> segments = List.of(
+                new Notification.ProgressStyle.Segment(50).setColor(Color.YELLOW),
+                new Notification.ProgressStyle.Segment(50).setColor(Color.LTGRAY));
+        final List<Notification.ProgressStyle.Point> points = List.of(
+                new Notification.ProgressStyle.Point(0).setColor(Color.RED),
+                new Notification.ProgressStyle.Point(20).setColor(Color.BLUE));
+        final NotificationProgressModel savedModel = new NotificationProgressModel(segments,
+                points,
+                100,
+                true);
+
+        final Bundle bundle = savedModel.toBundle();
+
+        // WHEN
+        final NotificationProgressModel restoredModel =
+                NotificationProgressModel.fromBundle(bundle);
+
+        // THEN
+        assertThat(restoredModel.isIndeterminate()).isFalse();
+        assertThat(restoredModel.getSegments()).isEqualTo(segments);
+        assertThat(restoredModel.getPoints()).isEqualTo(points);
+        assertThat(restoredModel.getProgress()).isEqualTo(100);
+        assertThat(restoredModel.isStyledByProgress()).isTrue();
+        assertThat(restoredModel.getIndeterminateColor()).isEqualTo(-1);
+    }
+}
diff --git a/core/tests/devicestatetests/Android.bp b/core/tests/devicestatetests/Android.bp
index a3303c6..e573a51 100644
--- a/core/tests/devicestatetests/Android.bp
+++ b/core/tests/devicestatetests/Android.bp
@@ -26,11 +26,14 @@
     // Include all test java files
     srcs: ["src/**/*.java"],
     static_libs: [
+        "androidx.test.ext.junit",
         "androidx.test.rules",
+        "flag-junit",
         "frameworks-base-testutils",
         "mockito-target-minus-junit4",
+        "platform-parametric-runner-lib",
         "platform-test-annotations",
-        "testng",
+        "truth",
     ],
     libs: ["android.test.runner.stubs.system"],
     platform_apis: true,
diff --git a/core/tests/devicestatetests/src/android/hardware/devicestate/DeviceStateInfoTest.java b/core/tests/devicestatetests/src/android/hardware/devicestate/DeviceStateInfoTest.java
index cf7c549..1b78433 100644
--- a/core/tests/devicestatetests/src/android/hardware/devicestate/DeviceStateInfoTest.java
+++ b/core/tests/devicestatetests/src/android/hardware/devicestate/DeviceStateInfoTest.java
@@ -22,21 +22,15 @@
 import static android.hardware.devicestate.DeviceState.PROPERTY_FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_HALF_OPEN;
 import static android.hardware.devicestate.DeviceState.PROPERTY_POLICY_CANCEL_OVERRIDE_REQUESTS;
 
-import static junit.framework.Assert.assertEquals;
-import static junit.framework.Assert.assertNotNull;
-
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotEquals;
-import static org.junit.Assert.assertTrue;
+import static com.google.common.truth.Truth.assertThat;
 
 import android.os.Parcel;
 
+import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
-import org.junit.Assert;
 import org.junit.Test;
 import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -44,13 +38,13 @@
 
 /**
  * Unit tests for {@link DeviceStateInfo}.
- * <p/>
- * Run with <code>atest DeviceStateInfoTest</code>.
+ *
+ * <p> Build/Install/Run:
+ * atest FrameworksCoreDeviceStateManagerTests:DeviceStateInfoTest
  */
-@RunWith(JUnit4.class)
 @SmallTest
+@RunWith(AndroidJUnit4.class)
 public final class DeviceStateInfoTest {
-
     private static final DeviceState DEVICE_STATE_0 = new DeviceState(
             new DeviceState.Configuration.Builder(0, "STATE_0")
                     .setSystemProperties(
@@ -74,88 +68,113 @@
 
     @Test
     public void create() {
-        final ArrayList<DeviceState> supportedStates = new ArrayList<>(
-                List.of(DEVICE_STATE_0, DEVICE_STATE_1, DEVICE_STATE_2));
+        final ArrayList<DeviceState> supportedStates =
+                new ArrayList<>(List.of(DEVICE_STATE_0, DEVICE_STATE_1, DEVICE_STATE_2));
         final DeviceState baseState = DEVICE_STATE_0;
         final DeviceState currentState = DEVICE_STATE_2;
 
-        final DeviceStateInfo info = new DeviceStateInfo(supportedStates, baseState, currentState);
-        assertNotNull(info.supportedStates);
-        assertEquals(supportedStates, info.supportedStates);
-        assertEquals(baseState, info.baseState);
-        assertEquals(currentState, info.currentState);
+        final DeviceStateInfo info =
+                new DeviceStateInfo(supportedStates, baseState, currentState);
+
+        assertThat(info.supportedStates).containsExactlyElementsIn(supportedStates).inOrder();
+        assertThat(info.baseState).isEqualTo(baseState);
+        assertThat(info.currentState).isEqualTo(currentState);
     }
 
     @Test
     public void equals() {
-        final ArrayList<DeviceState> supportedStates = new ArrayList<>(
-                List.of(DEVICE_STATE_0, DEVICE_STATE_1, DEVICE_STATE_2));
+        final ArrayList<DeviceState> supportedStates =
+                new ArrayList<>(List.of(DEVICE_STATE_0, DEVICE_STATE_1, DEVICE_STATE_2));
         final DeviceState baseState = DEVICE_STATE_0;
         final DeviceState currentState = DEVICE_STATE_2;
 
         final DeviceStateInfo info = new DeviceStateInfo(supportedStates, baseState, currentState);
-        Assert.assertEquals(info, info);
+        final DeviceStateInfo sameInstance = info;
+        assertThat(info).isEqualTo(sameInstance);
 
-        final DeviceStateInfo sameInfo = new DeviceStateInfo(supportedStates, baseState,
-                currentState);
-        Assert.assertEquals(info, sameInfo);
+        final DeviceStateInfo sameInfo =
+                new DeviceStateInfo(supportedStates, baseState, currentState);
+        assertThat(info).isEqualTo(sameInfo);
+
+        final DeviceStateInfo copiedInfo = new DeviceStateInfo(info);
+        assertThat(info).isEqualTo(copiedInfo);
 
         final DeviceStateInfo differentInfo = new DeviceStateInfo(
                 new ArrayList<>(List.of(DEVICE_STATE_0, DEVICE_STATE_2)), baseState, currentState);
-        assertNotEquals(info, differentInfo);
+        assertThat(differentInfo).isNotEqualTo(info);
+    }
+
+    @Test
+    public void hashCode_sameObject() {
+        final ArrayList<DeviceState> supportedStates =
+                new ArrayList<>(List.of(DEVICE_STATE_0, DEVICE_STATE_1, DEVICE_STATE_2));
+        final DeviceState baseState = DEVICE_STATE_0;
+        final DeviceState currentState = DEVICE_STATE_2;
+        final DeviceStateInfo info =
+                new DeviceStateInfo(supportedStates, baseState, currentState);
+        final DeviceStateInfo copiedInfo = new DeviceStateInfo(info);
+
+        assertThat(info.hashCode()).isEqualTo(copiedInfo.hashCode());
     }
 
     @Test
     public void diff_sameObject() {
-        final ArrayList<DeviceState> supportedStates = new ArrayList<>(
-                List.of(DEVICE_STATE_0, DEVICE_STATE_1, DEVICE_STATE_2));
+        final ArrayList<DeviceState> supportedStates =
+                new ArrayList<>(List.of(DEVICE_STATE_0, DEVICE_STATE_1, DEVICE_STATE_2));
         final DeviceState baseState = DEVICE_STATE_0;
         final DeviceState currentState = DEVICE_STATE_2;
 
         final DeviceStateInfo info = new DeviceStateInfo(supportedStates, baseState, currentState);
-        assertEquals(0, info.diff(info));
+
+        assertThat(info.diff(info)).isEqualTo(0);
     }
 
     @Test
     public void diff_differentSupportedStates() {
-        final DeviceStateInfo info = new DeviceStateInfo(new ArrayList<>(List.of(DEVICE_STATE_1)),
-                DEVICE_STATE_0, DEVICE_STATE_0);
+        final DeviceStateInfo info = new DeviceStateInfo(
+                new ArrayList<>(List.of(DEVICE_STATE_1)), DEVICE_STATE_0, DEVICE_STATE_0);
         final DeviceStateInfo otherInfo = new DeviceStateInfo(
                 new ArrayList<>(List.of(DEVICE_STATE_2)), DEVICE_STATE_0, DEVICE_STATE_0);
+
         final int diff = info.diff(otherInfo);
-        assertTrue((diff & DeviceStateInfo.CHANGED_SUPPORTED_STATES) > 0);
-        assertFalse((diff & DeviceStateInfo.CHANGED_BASE_STATE) > 0);
-        assertFalse((diff & DeviceStateInfo.CHANGED_CURRENT_STATE) > 0);
+
+        assertThat(diff & DeviceStateInfo.CHANGED_SUPPORTED_STATES).isGreaterThan(0);
+        assertThat(diff & DeviceStateInfo.CHANGED_BASE_STATE).isEqualTo(0);
+        assertThat(diff & DeviceStateInfo.CHANGED_CURRENT_STATE).isEqualTo(0);
     }
 
     @Test
     public void diff_differentNonOverrideState() {
-        final DeviceStateInfo info = new DeviceStateInfo(new ArrayList<>(List.of(DEVICE_STATE_1)),
-                DEVICE_STATE_1, DEVICE_STATE_0);
+        final DeviceStateInfo info = new DeviceStateInfo(
+                new ArrayList<>(List.of(DEVICE_STATE_1)), DEVICE_STATE_1, DEVICE_STATE_0);
         final DeviceStateInfo otherInfo = new DeviceStateInfo(
                 new ArrayList<>(List.of(DEVICE_STATE_1)), DEVICE_STATE_2, DEVICE_STATE_0);
+
         final int diff = info.diff(otherInfo);
-        assertFalse((diff & DeviceStateInfo.CHANGED_SUPPORTED_STATES) > 0);
-        assertTrue((diff & DeviceStateInfo.CHANGED_BASE_STATE) > 0);
-        assertFalse((diff & DeviceStateInfo.CHANGED_CURRENT_STATE) > 0);
+
+        assertThat(diff & DeviceStateInfo.CHANGED_SUPPORTED_STATES).isEqualTo(0);
+        assertThat(diff & DeviceStateInfo.CHANGED_BASE_STATE).isGreaterThan(0);
+        assertThat(diff & DeviceStateInfo.CHANGED_CURRENT_STATE).isEqualTo(0);
     }
 
     @Test
     public void diff_differentState() {
-        final DeviceStateInfo info = new DeviceStateInfo(new ArrayList<>(List.of(DEVICE_STATE_1)),
-                DEVICE_STATE_0, DEVICE_STATE_1);
+        final DeviceStateInfo info = new DeviceStateInfo(
+                new ArrayList<>(List.of(DEVICE_STATE_1)), DEVICE_STATE_0, DEVICE_STATE_1);
         final DeviceStateInfo otherInfo = new DeviceStateInfo(
                 new ArrayList<>(List.of(DEVICE_STATE_1)), DEVICE_STATE_0, DEVICE_STATE_2);
+
         final int diff = info.diff(otherInfo);
-        assertFalse((diff & DeviceStateInfo.CHANGED_SUPPORTED_STATES) > 0);
-        assertFalse((diff & DeviceStateInfo.CHANGED_BASE_STATE) > 0);
-        assertTrue((diff & DeviceStateInfo.CHANGED_CURRENT_STATE) > 0);
+
+        assertThat(diff & DeviceStateInfo.CHANGED_SUPPORTED_STATES).isEqualTo(0);
+        assertThat(diff & DeviceStateInfo.CHANGED_BASE_STATE).isEqualTo(0);
+        assertThat(diff & DeviceStateInfo.CHANGED_CURRENT_STATE).isGreaterThan(0);
     }
 
     @Test
     public void writeToParcel() {
-        final ArrayList<DeviceState> supportedStates = new ArrayList<>(
-                List.of(DEVICE_STATE_0, DEVICE_STATE_1, DEVICE_STATE_2));
+        final ArrayList<DeviceState> supportedStates =
+                new ArrayList<>(List.of(DEVICE_STATE_0, DEVICE_STATE_1, DEVICE_STATE_2));
         final DeviceState nonOverrideState = DEVICE_STATE_0;
         final DeviceState state = DEVICE_STATE_2;
         final DeviceStateInfo originalInfo =
@@ -166,6 +185,6 @@
         parcel.setDataPosition(0);
 
         final DeviceStateInfo info = DeviceStateInfo.CREATOR.createFromParcel(parcel);
-        assertEquals(originalInfo, info);
+        assertThat(info).isEqualTo(originalInfo);
     }
 }
diff --git a/core/tests/devicestatetests/src/android/hardware/devicestate/DeviceStateManagerGlobalTest.java b/core/tests/devicestatetests/src/android/hardware/devicestate/DeviceStateManagerGlobalTest.java
index f4d3631..e640ce5 100644
--- a/core/tests/devicestatetests/src/android/hardware/devicestate/DeviceStateManagerGlobalTest.java
+++ b/core/tests/devicestatetests/src/android/hardware/devicestate/DeviceStateManagerGlobalTest.java
@@ -16,11 +16,12 @@
 
 package android.hardware.devicestate;
 
-import static junit.framework.Assert.assertEquals;
-import static junit.framework.Assert.assertFalse;
+import static com.google.common.truth.Truth.assertThat;
 
+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.reset;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyZeroInteractions;
@@ -30,49 +31,104 @@
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.os.test.FakePermissionEnforcer;
+import android.platform.test.annotations.DisableFlags;
+import android.platform.test.annotations.EnableFlags;
+import android.platform.test.flag.junit.FlagsParameterization;
+import android.platform.test.flag.junit.SetFlagsRule;
 
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
 import androidx.test.filters.SmallTest;
 
 import com.android.internal.util.ConcurrentUtils;
+import com.android.window.flags.Flags;
 
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
 
 import java.util.ArrayList;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
 
+import platform.test.runner.parameterized.ParameterizedAndroidJunit4;
+import platform.test.runner.parameterized.Parameters;
+
 /**
  * Unit tests for {@link DeviceStateManagerGlobal}.
- * <p/>
- * Run with <code>atest DeviceStateManagerGlobalTest</code>.
+ *
+ * <p> Build/Install/Run:
+ * atest FrameworksCoreDeviceStateManagerTests:DeviceStateManagerGlobalTest
  */
-@RunWith(JUnit4.class)
 @SmallTest
+@RunWith(ParameterizedAndroidJunit4.class)
 public final class DeviceStateManagerGlobalTest {
     private static final DeviceState DEFAULT_DEVICE_STATE = new DeviceState(
             new DeviceState.Configuration.Builder(0 /* identifier */, "" /* name */).build());
     private static final DeviceState OTHER_DEVICE_STATE = new DeviceState(
             new DeviceState.Configuration.Builder(1 /* identifier */, "" /* name */).build());
 
+    @Rule
+    public final SetFlagsRule mSetFlagsRule;
+
+    @Parameters(name = "{0}")
+    public static List<FlagsParameterization> getParams() {
+        return FlagsParameterization.allCombinationsOf(Flags.FLAG_WLINFO_ONCREATE);
+    }
+
+    @NonNull
     private TestDeviceStateManagerService mService;
+    @NonNull
     private DeviceStateManagerGlobal mDeviceStateManagerGlobal;
 
+    public DeviceStateManagerGlobalTest(FlagsParameterization flags) {
+        mSetFlagsRule = new SetFlagsRule(flags);
+    }
+
     @Before
     public void setUp() {
-        FakePermissionEnforcer permissionEnforcer = new FakePermissionEnforcer();
+        final FakePermissionEnforcer permissionEnforcer = new FakePermissionEnforcer();
         mService = new TestDeviceStateManagerService(permissionEnforcer);
         mDeviceStateManagerGlobal = new DeviceStateManagerGlobal(mService);
-        assertFalse(mService.mCallbacks.isEmpty());
+        assertThat(mService.mCallbacks).isNotEmpty();
+    }
+
+    @Test
+    @DisableFlags(Flags.FLAG_WLINFO_ONCREATE)
+    public void create_whenWlinfoOncreateIsDisabled_receivesDeviceStateInfoFromCallback() {
+        final FakePermissionEnforcer permissionEnforcer = new FakePermissionEnforcer();
+        final TestDeviceStateManagerService service = new TestDeviceStateManagerService(
+                permissionEnforcer, true /* simulatePostCallback */);
+        final DeviceStateManagerGlobal dsmGlobal = new DeviceStateManagerGlobal(service);
+        final DeviceStateCallback callback = mock(DeviceStateCallback.class);
+        dsmGlobal.registerDeviceStateCallback(callback, ConcurrentUtils.DIRECT_EXECUTOR);
+
+        verify(callback, never()).onDeviceStateChanged(any());
+
+        // Simulate DeviceStateManagerService#registerProcess by notifying clients of current device
+        // state via callback.
+        service.notifyDeviceStateInfoChanged();
+        verify(callback).onDeviceStateChanged(eq(DEFAULT_DEVICE_STATE));
+    }
+
+    @Test
+    @EnableFlags(Flags.FLAG_WLINFO_ONCREATE)
+    public void create_whenWlinfoOncreateIsEnabled_returnsDeviceStateInfoFromRegistration() {
+        final FakePermissionEnforcer permissionEnforcer = new FakePermissionEnforcer();
+        final IDeviceStateManager service = new TestDeviceStateManagerService(permissionEnforcer);
+        final DeviceStateManagerGlobal dsmGlobal = new DeviceStateManagerGlobal(service);
+        final DeviceStateCallback callback = mock(DeviceStateCallback.class);
+        dsmGlobal.registerDeviceStateCallback(callback, ConcurrentUtils.DIRECT_EXECUTOR);
+
+        verify(callback).onDeviceStateChanged(eq(DEFAULT_DEVICE_STATE));
     }
 
     @Test
     public void registerCallback() {
-        DeviceStateCallback callback1 = mock(DeviceStateCallback.class);
-        DeviceStateCallback callback2 = mock(DeviceStateCallback.class);
+        final DeviceStateCallback callback1 = mock(DeviceStateCallback.class);
+        final DeviceStateCallback callback2 = mock(DeviceStateCallback.class);
 
         mDeviceStateManagerGlobal.registerDeviceStateCallback(callback1,
                 ConcurrentUtils.DIRECT_EXECUTOR);
@@ -105,8 +161,8 @@
         reset(callback2);
 
         // Change the requested state and verify callback
-        DeviceStateRequest request = DeviceStateRequest.newBuilder(
-                DEFAULT_DEVICE_STATE.getIdentifier()).build();
+        final DeviceStateRequest request =
+                DeviceStateRequest.newBuilder(DEFAULT_DEVICE_STATE.getIdentifier()).build();
         mDeviceStateManagerGlobal.requestState(request, null /* executor */, null /* callback */);
 
         verify(callback1).onDeviceStateChanged(eq(mService.getMergedState()));
@@ -115,10 +171,10 @@
 
     @Test
     public void unregisterCallback() {
-        DeviceStateCallback callback = mock(DeviceStateCallback.class);
+        final DeviceStateCallback callback = mock(DeviceStateCallback.class);
 
-        mDeviceStateManagerGlobal.registerDeviceStateCallback(callback,
-                ConcurrentUtils.DIRECT_EXECUTOR);
+        mDeviceStateManagerGlobal
+                .registerDeviceStateCallback(callback, ConcurrentUtils.DIRECT_EXECUTOR);
 
         // Verify initial callbacks
         verify(callback).onSupportedStatesChanged(eq(mService.getSupportedDeviceStates()));
@@ -134,15 +190,15 @@
 
     @Test
     public void submitRequest() {
-        DeviceStateCallback callback = mock(DeviceStateCallback.class);
-        mDeviceStateManagerGlobal.registerDeviceStateCallback(callback,
-                ConcurrentUtils.DIRECT_EXECUTOR);
+        final DeviceStateCallback callback = mock(DeviceStateCallback.class);
+        mDeviceStateManagerGlobal
+                .registerDeviceStateCallback(callback, ConcurrentUtils.DIRECT_EXECUTOR);
 
         verify(callback).onDeviceStateChanged(eq(mService.getBaseState()));
         reset(callback);
 
-        DeviceStateRequest request = DeviceStateRequest.newBuilder(
-                OTHER_DEVICE_STATE.getIdentifier()).build();
+        final DeviceStateRequest request =
+                DeviceStateRequest.newBuilder(OTHER_DEVICE_STATE.getIdentifier()).build();
         mDeviceStateManagerGlobal.requestState(request, null /* executor */, null /* callback */);
 
         verify(callback).onDeviceStateChanged(eq(OTHER_DEVICE_STATE));
@@ -155,15 +211,15 @@
 
     @Test
     public void submitBaseStateOverrideRequest() {
-        DeviceStateCallback callback = mock(DeviceStateCallback.class);
-        mDeviceStateManagerGlobal.registerDeviceStateCallback(callback,
-                ConcurrentUtils.DIRECT_EXECUTOR);
+        final DeviceStateCallback callback = mock(DeviceStateCallback.class);
+        mDeviceStateManagerGlobal
+                .registerDeviceStateCallback(callback, ConcurrentUtils.DIRECT_EXECUTOR);
 
         verify(callback).onDeviceStateChanged(eq(mService.getBaseState()));
         reset(callback);
 
-        DeviceStateRequest request = DeviceStateRequest.newBuilder(
-                OTHER_DEVICE_STATE.getIdentifier()).build();
+        final DeviceStateRequest request =
+                DeviceStateRequest.newBuilder(OTHER_DEVICE_STATE.getIdentifier()).build();
         mDeviceStateManagerGlobal.requestBaseStateOverride(request, null /* executor */,
                 null /* callback */);
 
@@ -177,28 +233,28 @@
 
     @Test
     public void submitBaseAndEmulatedStateOverride() {
-        DeviceStateCallback callback = mock(DeviceStateCallback.class);
-        mDeviceStateManagerGlobal.registerDeviceStateCallback(callback,
-                ConcurrentUtils.DIRECT_EXECUTOR);
+        final DeviceStateCallback callback = mock(DeviceStateCallback.class);
+        mDeviceStateManagerGlobal
+                .registerDeviceStateCallback(callback, ConcurrentUtils.DIRECT_EXECUTOR);
 
         verify(callback).onDeviceStateChanged(eq(mService.getBaseState()));
         reset(callback);
 
-        DeviceStateRequest request = DeviceStateRequest.newBuilder(
-                OTHER_DEVICE_STATE.getIdentifier()).build();
+        final DeviceStateRequest request =
+                DeviceStateRequest.newBuilder(OTHER_DEVICE_STATE.getIdentifier()).build();
         mDeviceStateManagerGlobal.requestBaseStateOverride(request, null /* executor */,
                 null /* callback */);
 
         verify(callback).onDeviceStateChanged(eq(OTHER_DEVICE_STATE));
-        assertEquals(OTHER_DEVICE_STATE, mService.getBaseState());
+        assertThat(mService.getBaseState()).isEqualTo(OTHER_DEVICE_STATE);
         reset(callback);
 
-        DeviceStateRequest secondRequest = DeviceStateRequest.newBuilder(
-                DEFAULT_DEVICE_STATE.getIdentifier()).build();
+        final DeviceStateRequest secondRequest =
+                DeviceStateRequest.newBuilder(DEFAULT_DEVICE_STATE.getIdentifier()).build();
 
         mDeviceStateManagerGlobal.requestState(secondRequest, null, null);
 
-        assertEquals(OTHER_DEVICE_STATE, mService.getBaseState());
+        assertThat(mService.getBaseState()).isEqualTo(OTHER_DEVICE_STATE);
         verify(callback).onDeviceStateChanged(eq(DEFAULT_DEVICE_STATE));
         reset(callback);
 
@@ -214,10 +270,10 @@
 
     @Test
     public void verifyDeviceStateRequestCallbacksCalled() {
-        DeviceStateRequest.Callback callback = mock(TestDeviceStateRequestCallback.class);
+        final DeviceStateRequest.Callback callback = mock(TestDeviceStateRequestCallback.class);
 
-        DeviceStateRequest request = DeviceStateRequest.newBuilder(
-                OTHER_DEVICE_STATE.getIdentifier()).build();
+        final DeviceStateRequest request =
+                DeviceStateRequest.newBuilder(OTHER_DEVICE_STATE.getIdentifier()).build();
         mDeviceStateManagerGlobal.requestState(request,
                 ConcurrentUtils.DIRECT_EXECUTOR /* executor */,
                 callback /* callback */);
@@ -232,52 +288,62 @@
 
     public static class TestDeviceStateRequestCallback implements DeviceStateRequest.Callback {
         @Override
-        public void onRequestActivated(DeviceStateRequest request) { }
+        public void onRequestActivated(@NonNull DeviceStateRequest request) { }
 
         @Override
-        public void onRequestCanceled(DeviceStateRequest request) { }
+        public void onRequestCanceled(@NonNull DeviceStateRequest request) { }
 
         @Override
-        public void onRequestSuspended(DeviceStateRequest request) { }
+        public void onRequestSuspended(@NonNull DeviceStateRequest request) { }
     }
 
     private static final class TestDeviceStateManagerService extends IDeviceStateManager.Stub {
-        public static final class Request {
-            public final IBinder token;
-            public final int state;
-            public final int flags;
+        static final class Request {
+            @NonNull
+            final IBinder mToken;
+            final int mState;
 
-            private Request(IBinder token, int state, int flags) {
-                this.token = token;
-                this.state = state;
-                this.flags = flags;
+            private Request(@NonNull IBinder token, int state) {
+                this.mToken = token;
+                this.mState = state;
             }
         }
 
-        private List<DeviceState> mSupportedDeviceStates = List.of(DEFAULT_DEVICE_STATE,
-                OTHER_DEVICE_STATE);
-
+        @NonNull
+        private List<DeviceState> mSupportedDeviceStates =
+                List.of(DEFAULT_DEVICE_STATE, OTHER_DEVICE_STATE);
+        @NonNull
         private DeviceState mBaseState = DEFAULT_DEVICE_STATE;
+        @Nullable
         private Request mRequest;
+        @Nullable
         private Request mBaseStateRequest;
 
+        private final boolean mSimulatePostCallback;
         private final Set<IDeviceStateManagerCallback> mCallbacks = new HashSet<>();
 
-        TestDeviceStateManagerService(FakePermissionEnforcer enforcer) {
-            super(enforcer);
+        TestDeviceStateManagerService(@NonNull FakePermissionEnforcer enforcer) {
+            this(enforcer, false /* simulatePostCallback */);
         }
 
+        TestDeviceStateManagerService(@NonNull FakePermissionEnforcer enforcer,
+                boolean simulatePostCallback) {
+            super(enforcer);
+            mSimulatePostCallback = simulatePostCallback;
+        }
+
+        @NonNull
         private DeviceStateInfo getInfo() {
             final int mergedBaseState = mBaseStateRequest == null
-                    ? mBaseState.getIdentifier() : mBaseStateRequest.state;
-            final int mergedState = mRequest == null
-                    ? mergedBaseState : mRequest.state;
+                    ? mBaseState.getIdentifier() : mBaseStateRequest.mState;
+            final int mergedState = mRequest == null ? mergedBaseState : mRequest.mState;
 
+            final ArrayList<DeviceState> supportedStates = new ArrayList<>(mSupportedDeviceStates);
             final DeviceState baseState = new DeviceState(
                     new DeviceState.Configuration.Builder(mergedBaseState, "" /* name */).build());
             final DeviceState state = new DeviceState(
                     new DeviceState.Configuration.Builder(mergedState, "" /* name */).build());
-            return new DeviceStateInfo(new ArrayList<>(mSupportedDeviceStates), baseState, state);
+            return new DeviceStateInfo(supportedStates, baseState, state);
         }
 
         private void notifyDeviceStateInfoChanged() {
@@ -291,38 +357,47 @@
             }
         }
 
+        @NonNull
         @Override
         public DeviceStateInfo getDeviceStateInfo() {
             return getInfo();
         }
 
+        @Nullable
         @Override
-        public void registerCallback(IDeviceStateManagerCallback callback) {
+        public DeviceStateInfo registerCallback(IDeviceStateManagerCallback callback) {
             if (mCallbacks.contains(callback)) {
                 throw new SecurityException("Callback is already registered.");
             }
 
             mCallbacks.add(callback);
-            try {
-                callback.onDeviceStateInfoChanged(getInfo());
-            } catch (RemoteException e) {
-                e.rethrowFromSystemServer();
+            if (Flags.wlinfoOncreate()) {
+                return getInfo();
             }
+
+            if (!mSimulatePostCallback) {
+                try {
+                    callback.onDeviceStateInfoChanged(getInfo());
+                } catch (RemoteException e) {
+                    e.rethrowFromSystemServer();
+                }
+            }
+            return null;
         }
 
         @Override
-        public void requestState(IBinder token, int state, int flags) {
+        public void requestState(@NonNull IBinder token, int state, int unusedFlags) {
             if (mRequest != null) {
                 for (IDeviceStateManagerCallback callback : mCallbacks) {
                     try {
-                        callback.onRequestCanceled(mRequest.token);
+                        callback.onRequestCanceled(mRequest.mToken);
                     } catch (RemoteException e) {
                         e.rethrowFromSystemServer();
                     }
                 }
             }
 
-            final Request request = new Request(token, state, flags);
+            final Request request = new Request(token, state);
             mRequest = request;
             notifyDeviceStateInfoChanged();
 
@@ -337,7 +412,7 @@
 
         @Override
         public void cancelStateRequest() {
-            IBinder token = mRequest.token;
+            final IBinder token = mRequest.mToken;
             mRequest = null;
             for (IDeviceStateManagerCallback callback : mCallbacks) {
                 try {
@@ -350,19 +425,18 @@
         }
 
         @Override
-        public void requestBaseStateOverride(IBinder token, int state, int flags) {
+        public void requestBaseStateOverride(@NonNull IBinder token, int state, int unusedFlags) {
             if (mBaseStateRequest != null) {
                 for (IDeviceStateManagerCallback callback : mCallbacks) {
                     try {
-                        callback.onRequestCanceled(mBaseStateRequest.token);
+                        callback.onRequestCanceled(mBaseStateRequest.mToken);
                     } catch (RemoteException e) {
                         e.rethrowFromSystemServer();
                     }
                 }
             }
 
-            final Request request = new Request(token, state, flags);
-            mBaseStateRequest = request;
+            mBaseStateRequest = new Request(token, state);
             notifyDeviceStateInfoChanged();
 
             for (IDeviceStateManagerCallback callback : mCallbacks) {
@@ -376,7 +450,7 @@
 
         @Override
         public void cancelBaseStateOverride() throws RemoteException {
-            IBinder token = mBaseStateRequest.token;
+            final IBinder token = mBaseStateRequest.mToken;
             mBaseStateRequest = null;
             for (IDeviceStateManagerCallback callback : mCallbacks) {
                 try {
@@ -396,24 +470,27 @@
             onStateRequestOverlayDismissed_enforcePermission();
         }
 
-        public void setSupportedStates(List<DeviceState> states) {
+        public void setSupportedStates(@NonNull List<DeviceState> states) {
             mSupportedDeviceStates = states;
             notifyDeviceStateInfoChanged();
         }
 
+        @NonNull
         public List<DeviceState> getSupportedDeviceStates() {
             return mSupportedDeviceStates;
         }
 
-        public void setBaseState(DeviceState state) {
+        public void setBaseState(@NonNull DeviceState state) {
             mBaseState = state;
             notifyDeviceStateInfoChanged();
         }
 
+        @NonNull
         public DeviceState getBaseState() {
             return getInfo().baseState;
         }
 
+        @NonNull
         public DeviceState getMergedState() {
             return getInfo().currentState;
         }
diff --git a/core/tests/devicestatetests/src/android/hardware/devicestate/DeviceStateTest.java b/core/tests/devicestatetests/src/android/hardware/devicestate/DeviceStateTest.java
index 78d4324..83b5ff3 100644
--- a/core/tests/devicestatetests/src/android/hardware/devicestate/DeviceStateTest.java
+++ b/core/tests/devicestatetests/src/android/hardware/devicestate/DeviceStateTest.java
@@ -21,17 +21,16 @@
 import static android.hardware.devicestate.DeviceState.PROPERTY_POLICY_CANCEL_OVERRIDE_REQUESTS;
 import static android.hardware.devicestate.DeviceStateManager.MINIMUM_DEVICE_STATE_IDENTIFIER;
 
-import static org.testng.Assert.assertEquals;
-import static org.testng.Assert.assertTrue;
+import static com.google.common.truth.Truth.assertThat;
 
 import android.os.Parcel;
 import android.platform.test.annotations.Presubmit;
 
-import junit.framework.Assert;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
 
 import java.util.HashSet;
 import java.util.List;
@@ -39,28 +38,32 @@
 
 /**
  * Unit tests for {@link android.hardware.devicestate.DeviceState}.
- * <p/>
- * Run with <code>atest DeviceStateTest</code>.
+ *
+ * <p> Build/Install/Run:
+ * atest FrameworksCoreDeviceStateManagerTests:DeviceStateTest
  */
 @Presubmit
-@RunWith(JUnit4.class)
+@SmallTest
+@RunWith(AndroidJUnit4.class)
 public final class DeviceStateTest {
     @Test
     public void testConstruct() {
-        DeviceState.Configuration config = new DeviceState.Configuration.Builder(
+        final DeviceState.Configuration config = new DeviceState.Configuration.Builder(
                 MINIMUM_DEVICE_STATE_IDENTIFIER, "TEST_CLOSED")
                 .setSystemProperties(
                         new HashSet<>(List.of(PROPERTY_POLICY_CANCEL_OVERRIDE_REQUESTS)))
                 .build();
+
         final DeviceState state = new DeviceState(config);
-        assertEquals(state.getIdentifier(), MINIMUM_DEVICE_STATE_IDENTIFIER);
-        assertEquals(state.getName(), "TEST_CLOSED");
-        assertTrue(state.hasProperty(PROPERTY_POLICY_CANCEL_OVERRIDE_REQUESTS));
+
+        assertThat(state.getIdentifier()).isEqualTo(MINIMUM_DEVICE_STATE_IDENTIFIER);
+        assertThat(state.getName()).isEqualTo("TEST_CLOSED");
+        assertThat(state.hasProperty(PROPERTY_POLICY_CANCEL_OVERRIDE_REQUESTS)).isTrue();
     }
 
     @Test
     public void testHasProperties() {
-        DeviceState.Configuration config = new DeviceState.Configuration.Builder(
+        final DeviceState.Configuration config = new DeviceState.Configuration.Builder(
                 MINIMUM_DEVICE_STATE_IDENTIFIER, "TEST")
                 .setSystemProperties(new HashSet<>(List.of(PROPERTY_POLICY_CANCEL_OVERRIDE_REQUESTS,
                         PROPERTY_POLICY_AVAILABLE_FOR_APP_REQUEST)))
@@ -68,10 +71,10 @@
 
         final DeviceState state = new DeviceState(config);
 
-        assertTrue(state.hasProperty(PROPERTY_POLICY_CANCEL_OVERRIDE_REQUESTS));
-        assertTrue(state.hasProperty(PROPERTY_POLICY_AVAILABLE_FOR_APP_REQUEST));
-        assertTrue(state.hasProperties(PROPERTY_POLICY_CANCEL_OVERRIDE_REQUESTS,
-                PROPERTY_POLICY_AVAILABLE_FOR_APP_REQUEST));
+        assertThat(state.hasProperty(PROPERTY_POLICY_CANCEL_OVERRIDE_REQUESTS)).isTrue();
+        assertThat(state.hasProperty(PROPERTY_POLICY_AVAILABLE_FOR_APP_REQUEST)).isTrue();
+        assertThat(state.hasProperties(PROPERTY_POLICY_CANCEL_OVERRIDE_REQUESTS,
+                PROPERTY_POLICY_AVAILABLE_FOR_APP_REQUEST)).isTrue();
     }
 
     @Test
@@ -91,7 +94,7 @@
         final DeviceState.Configuration stateConfiguration =
                 DeviceState.Configuration.CREATOR.createFromParcel(parcel);
 
-        Assert.assertEquals(originalState, new DeviceState(stateConfiguration));
+        assertThat(originalState).isEqualTo(new DeviceState(stateConfiguration));
     }
 
     @Test
@@ -109,6 +112,6 @@
         final DeviceState.Configuration stateConfiguration =
                 DeviceState.Configuration.CREATOR.createFromParcel(parcel);
 
-        Assert.assertEquals(originalState, new DeviceState(stateConfiguration));
+        assertThat(originalState).isEqualTo(new DeviceState(stateConfiguration));
     }
 }
diff --git a/core/tests/vibrator/src/android/os/VibratorInfoTest.java b/core/tests/vibrator/src/android/os/VibratorInfoTest.java
index c810810..04945f3 100644
--- a/core/tests/vibrator/src/android/os/VibratorInfoTest.java
+++ b/core/tests/vibrator/src/android/os/VibratorInfoTest.java
@@ -16,6 +16,8 @@
 
 package android.os;
 
+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.assertNotEquals;
@@ -24,6 +26,7 @@
 
 import android.hardware.vibrator.Braking;
 import android.hardware.vibrator.IVibrator;
+import android.util.Range;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -39,12 +42,19 @@
     private static final float TEST_FREQUENCY_RESOLUTION = 25;
     private static final float[] TEST_AMPLITUDE_MAP = new float[]{
             /* 50Hz= */ 0.1f, 0.2f, 0.4f, 0.8f, /* 150Hz= */ 1f, 0.9f, /* 200Hz= */ 0.8f};
+    private static final float[] TEST_FREQUENCIES =
+            new float[]{90f, 120f, 150f, 60f, 30f, 210f, 270f, 300f, 240f, 180f};
+    private static final float[] TEST_OUTPUT_ACCELERATIONS =
+            new float[]{1.2f, 1.8f, 2.4f, 0.6f, 0.1f, 2.2f, 1.0f, 0.5f, 1.9f, 3.0f};
 
-    private static final VibratorInfo.FrequencyProfile EMPTY_FREQUENCY_PROFILE =
-            new VibratorInfo.FrequencyProfile(Float.NaN, Float.NaN, Float.NaN, null);
-    private static final VibratorInfo.FrequencyProfile TEST_FREQUENCY_PROFILE =
-            new VibratorInfo.FrequencyProfile(TEST_RESONANT_FREQUENCY, TEST_MIN_FREQUENCY,
+    private static final VibratorInfo.FrequencyProfileLegacy EMPTY_FREQUENCY_PROFILE =
+            new VibratorInfo.FrequencyProfileLegacy(Float.NaN, Float.NaN, Float.NaN, null);
+    private static final VibratorInfo.FrequencyProfileLegacy TEST_FREQUENCY_PROFILE_LEGACY =
+            new VibratorInfo.FrequencyProfileLegacy(TEST_RESONANT_FREQUENCY, TEST_MIN_FREQUENCY,
                     TEST_FREQUENCY_RESOLUTION, TEST_AMPLITUDE_MAP);
+    private static final VibratorInfo.FrequencyProfile TEST_FREQUENCY_PROFILE =
+            new VibratorInfo.FrequencyProfile(TEST_RESONANT_FREQUENCY, TEST_FREQUENCIES,
+                    TEST_OUTPUT_ACCELERATIONS);
 
     @Test
     public void testHasAmplitudeControl() {
@@ -180,52 +190,166 @@
 
     @Test
     public void testGetFrequencyProfile_unsetProfileIsEmpty() {
-        assertTrue(
-                new VibratorInfo.Builder(TEST_VIBRATOR_ID).build().getFrequencyProfile().isEmpty());
+        assertTrue(new VibratorInfo.Builder(
+                TEST_VIBRATOR_ID).build().getFrequencyProfile().isEmpty());
     }
 
     @Test
     public void testFrequencyProfile_invalidValuesCreatesEmptyProfile() {
-        // Invalid, contains NaN values or empty array.
-        assertTrue(new VibratorInfo.FrequencyProfile(
-                Float.NaN, 50, 25, TEST_AMPLITUDE_MAP).isEmpty());
-        assertTrue(new VibratorInfo.FrequencyProfile(
-                150, Float.NaN, 25, TEST_AMPLITUDE_MAP).isEmpty());
-        assertTrue(new VibratorInfo.FrequencyProfile(
-                150, 50, Float.NaN, TEST_AMPLITUDE_MAP).isEmpty());
-        assertTrue(new VibratorInfo.FrequencyProfile(150, 50, 25, null).isEmpty());
-        // Invalid, contains zero or negative frequency values.
-        assertTrue(new VibratorInfo.FrequencyProfile(-1, 50, 25, TEST_AMPLITUDE_MAP).isEmpty());
-        assertTrue(new VibratorInfo.FrequencyProfile(150, 0, 25, TEST_AMPLITUDE_MAP).isEmpty());
-        assertTrue(new VibratorInfo.FrequencyProfile(150, 50, -2, TEST_AMPLITUDE_MAP).isEmpty());
-        // Invalid max amplitude entries.
-        assertTrue(new VibratorInfo.FrequencyProfile(
-                150, 50, 50, new float[] { -1, 0, 1, 1, 0 }).isEmpty());
-        assertTrue(new VibratorInfo.FrequencyProfile(
-                150, 50, 50, new float[] { 0, 1, 2, 1, 0 }).isEmpty());
-        // Invalid, minFrequency > resonantFrequency
-        assertTrue(new VibratorInfo.FrequencyProfile(
-                /* resonantFrequencyHz= */ 150, /* minFrequencyHz= */ 250, 25, TEST_AMPLITUDE_MAP)
-                .isEmpty());
-        // Invalid, maxFrequency < resonantFrequency by changing resolution.
-        assertTrue(new VibratorInfo.FrequencyProfile(
-                150, 50, /* frequencyResolutionHz= */ 10, TEST_AMPLITUDE_MAP).isEmpty());
+        // Invalid resonant frequency.
+        assertThat(new VibratorInfo.FrequencyProfile(Float.NaN,
+                TEST_FREQUENCIES, TEST_OUTPUT_ACCELERATIONS).isEmpty()).isTrue();
+        assertThat(new VibratorInfo.FrequencyProfile(/*resonantFrequencyHz=*/-1f,
+                TEST_FREQUENCIES, TEST_OUTPUT_ACCELERATIONS).isEmpty()).isTrue();
+        // No frequency-acceleration data
+        assertThat(new VibratorInfo.FrequencyProfile(/*resonantFrequencyHz=*/150f,
+                /*frequenciesHz=*/ null, /*outputAccelerationsGs=*/ null).isEmpty()).isTrue();
+        // Mismatching frequency and output acceleration lists
+        assertThat(new VibratorInfo.FrequencyProfile(/*resonantFrequencyHz=*/150f,
+                /*frequenciesHz=*/ new float[]{30f, 40f, 50f, 100f},
+                /*outputAccelerationsGs=*/ new float[]{0.8f, 1.0f, 2.0f}).isEmpty()).isTrue();
+    }
+
+    @Test
+    public void testGetFrequenciesAndOutputAccelerations_noFrequencyAccelerationData_returnNull() {
+        VibratorInfo.FrequencyProfile emptyFrequencyProfile =
+                new VibratorInfo.FrequencyProfile(/*resonantFrequencyHz=*/150f,
+                        /*frequenciesHz=*/ null, /*outputAccelerationsGs=*/ null);
+        assertThat(emptyFrequencyProfile.getFrequenciesHz()).isNull();
+        assertThat(emptyFrequencyProfile.getOutputAccelerationsGs()).isNull();
+    }
+
+    @Test
+    public void testGetFrequenciesAndOutputAccelerations_mismatchingDataLength_returnNull() {
+        VibratorInfo.FrequencyProfile emptyFrequencyProfile =
+                new VibratorInfo.FrequencyProfile(/*resonantFrequencyHz=*/150f,
+                        /*frequenciesHz=*/ new float[]{150f, 200f},
+                        /*outputAccelerationsGs=*/ new float[]{1.2f, 2.2f, 3.0f});
+        assertThat(emptyFrequencyProfile.getFrequenciesHz()).isNull();
+        assertThat(emptyFrequencyProfile.getOutputAccelerationsGs()).isNull();
+    }
+
+    @Test
+    public void testGetFrequenciesAndOutputAccelerations_dataIsDedupedAndSorted() {
+        VibratorInfo.FrequencyProfile frequencyProfile =
+                new VibratorInfo.FrequencyProfile(/*resonantFrequencyHz=*/150f,
+                        /*frequenciesHz=*/ new float[]{150f, 150f, 150f, 130f, 200f, 160f},
+                        /*outputAccelerationsGs=*/ new float[]{1.2f, 1.5f, 1.9f, 1.0f, 2.2f, 3.0f});
+        float[] frequencies = frequencyProfile.getFrequenciesHz();
+        assertThat(frequencies).isEqualTo(
+                new float[]{130f, 150f, 160f, 200f});
+        assertThat(frequencyProfile.getOutputAccelerationsGs()).isEqualTo(
+                new float[]{1.0f, 1.2f, 3.0f, 2.2f});
     }
 
     @Test
     public void testGetFrequencyRangeHz_emptyProfileReturnsNull() {
-        assertNull(new VibratorInfo.FrequencyProfile(
-                Float.NaN, 50, 25, TEST_AMPLITUDE_MAP).getFrequencyRangeHz());
-        assertNull(new VibratorInfo.FrequencyProfile(
-                150, Float.NaN, 25, TEST_AMPLITUDE_MAP).getFrequencyRangeHz());
-        assertNull(new VibratorInfo.FrequencyProfile(
-                150, 50, Float.NaN, TEST_AMPLITUDE_MAP).getFrequencyRangeHz());
-        assertNull(new VibratorInfo.FrequencyProfile(150, 50, 25, null).getFrequencyRangeHz());
+        VibratorInfo.FrequencyProfile emptyFrequencyProfile =
+                new VibratorInfo.FrequencyProfile(/*resonantFrequencyHz=*/150f,
+                        /*frequenciesHz=*/ null, /*outputAccelerationsGs=*/ null);
+        assertThat(
+                emptyFrequencyProfile.getFrequencyRangeHz(/*minOutputAcceleration=*/0.2f)).isNull();
     }
 
     @Test
     public void testGetFrequencyRangeHz_validProfileReturnsMappedValues() {
-        VibratorInfo.FrequencyProfile profile = new VibratorInfo.FrequencyProfile(
+        VibratorInfo.FrequencyProfile frequencyProfile =
+                new VibratorInfo.FrequencyProfile(/*resonantFrequencyHz=*/150f,
+                /*frequenciesHz=*/new float[]{90f, 120f, 150f, 60f, 30f, 210f, 180f},
+                /*outputAccelerationsGs=*/ new float[]{1.2f, 1.8f, 2.4f, 0.6f, 0.4f, 2.2f, 3.0f});
+
+        // lower and upper bounds are min and max frequencies
+        assertThat(frequencyProfile.getFrequencyRangeHz(/*minOutputAcceleration=*/0.33f)).isEqualTo(
+                new Range<>(frequencyProfile.getMinFrequencyHz(),
+                        frequencyProfile.getMaxFrequencyHz()));
+
+        // lower and upper bounds are within frequency range and use interpolation
+        assertThat(frequencyProfile.getFrequencyRangeHz(/*minOutputAcceleration=*/2.6f))
+                .isEqualTo(new Range<>(160f, 195f));
+
+        // upper bound is max frequency
+        assertThat(frequencyProfile.getFrequencyRangeHz(/*minOutputAcceleration=*/2.0f))
+                .isEqualTo(new Range<>(130f, frequencyProfile.getMaxFrequencyHz()));
+    }
+
+    @Test
+    public void testFrequencyProfile_emptyProfileReturnsNanValues() {
+        VibratorInfo.FrequencyProfile frequencyProfile = new VibratorInfo.FrequencyProfile(
+                /*resonantFrequencyHz=*/150f, /*frequenciesHz=*/ null,
+                /*outputAccelerationsGs=*/ null);
+
+        assertThat(frequencyProfile.getMaxOutputAccelerationGs()).isNaN();
+        assertThat(frequencyProfile.getMinFrequencyHz()).isNaN();
+        assertThat(frequencyProfile.getMaxFrequencyHz()).isNaN();
+        assertThat(frequencyProfile.getOutputAccelerationGs(/*frequencyHz=*/150f)).isNaN();
+    }
+
+    @Test
+    public void testFrequencyProfile_validProfileReturnsAppropriateValues() {
+        VibratorInfo.FrequencyProfile frequencyProfile = new VibratorInfo.FrequencyProfile(
+                /*resonantFrequencyHz=*/150f, TEST_FREQUENCIES, TEST_OUTPUT_ACCELERATIONS);
+
+        assertThat(frequencyProfile.getMaxOutputAccelerationGs()).isEqualTo(3f);
+        assertThat(frequencyProfile.getMinFrequencyHz()).isEqualTo(30f);
+        assertThat(frequencyProfile.getMaxFrequencyHz()).isEqualTo(300f);
+        assertThat(frequencyProfile.getOutputAccelerationGs(/*frequencyHz=*/150f)).isEqualTo(2.4f);
+        // Test getting output acceleration using linear interpolation
+        assertThat(frequencyProfile.getOutputAccelerationGs(/*frequencyHz=*/166f)).isEqualTo(
+                2.72f);
+    }
+
+    @Test
+    public void testGetFrequencyProfileLegacy_unsetProfileIsEmpty() {
+        assertTrue(new VibratorInfo.Builder(
+                TEST_VIBRATOR_ID).build().getFrequencyProfileLegacy().isEmpty());
+    }
+
+    @Test
+    public void testFrequencyProfileLegacy_invalidValuesCreatesEmptyProfile() {
+        // Invalid, contains NaN values or empty array.
+        assertTrue(new VibratorInfo.FrequencyProfileLegacy(
+                Float.NaN, 50, 25, TEST_AMPLITUDE_MAP).isEmpty());
+        assertTrue(new VibratorInfo.FrequencyProfileLegacy(
+                150, Float.NaN, 25, TEST_AMPLITUDE_MAP).isEmpty());
+        assertTrue(new VibratorInfo.FrequencyProfileLegacy(
+                150, 50, Float.NaN, TEST_AMPLITUDE_MAP).isEmpty());
+        assertTrue(new VibratorInfo.FrequencyProfileLegacy(150, 50, 25, null).isEmpty());
+        // Invalid, contains zero or negative frequency values.
+        assertTrue(
+                new VibratorInfo.FrequencyProfileLegacy(-1, 50, 25, TEST_AMPLITUDE_MAP).isEmpty());
+        assertTrue(
+                new VibratorInfo.FrequencyProfileLegacy(150, 0, 25, TEST_AMPLITUDE_MAP).isEmpty());
+        assertTrue(
+                new VibratorInfo.FrequencyProfileLegacy(150, 50, -2, TEST_AMPLITUDE_MAP).isEmpty());
+        // Invalid max amplitude entries.
+        assertTrue(new VibratorInfo.FrequencyProfileLegacy(
+                150, 50, 50, new float[] { -1, 0, 1, 1, 0 }).isEmpty());
+        assertTrue(new VibratorInfo.FrequencyProfileLegacy(
+                150, 50, 50, new float[] { 0, 1, 2, 1, 0 }).isEmpty());
+        // Invalid, minFrequency > resonantFrequency
+        assertTrue(new VibratorInfo.FrequencyProfileLegacy(
+                /* resonantFrequencyHz= */ 150, /* minFrequencyHz= */ 250, 25, TEST_AMPLITUDE_MAP)
+                .isEmpty());
+        // Invalid, maxFrequency < resonantFrequency by changing resolution.
+        assertTrue(new VibratorInfo.FrequencyProfileLegacy(
+                150, 50, /* frequencyResolutionHz= */ 10, TEST_AMPLITUDE_MAP).isEmpty());
+    }
+
+    @Test
+    public void testLegacyGetFrequencyRangeHz_emptyProfileReturnsNull() {
+        assertNull(new VibratorInfo.FrequencyProfileLegacy(
+                Float.NaN, 50, 25, TEST_AMPLITUDE_MAP).getFrequencyRangeHz());
+        assertNull(new VibratorInfo.FrequencyProfileLegacy(
+                150, Float.NaN, 25, TEST_AMPLITUDE_MAP).getFrequencyRangeHz());
+        assertNull(new VibratorInfo.FrequencyProfileLegacy(
+                150, 50, Float.NaN, TEST_AMPLITUDE_MAP).getFrequencyRangeHz());
+        assertNull(
+                new VibratorInfo.FrequencyProfileLegacy(150, 50, 25, null).getFrequencyRangeHz());
+    }
+
+    @Test
+    public void testLegacyGetFrequencyRangeHz_validProfileReturnsMappedValues() {
+        VibratorInfo.FrequencyProfileLegacy profile = new VibratorInfo.FrequencyProfileLegacy(
                 /* resonantFrequencyHz= */ 150,
                 /* minFrequencyHz= */ 50,
                 /* frequencyResolutionHz= */ 25,
@@ -239,12 +363,12 @@
 
     @Test
     public void testGetMaxAmplitude_emptyProfileReturnsAlwaysZero() {
-        VibratorInfo.FrequencyProfile profile = EMPTY_FREQUENCY_PROFILE;
+        VibratorInfo.FrequencyProfileLegacy profile = EMPTY_FREQUENCY_PROFILE;
         assertEquals(0f, profile.getMaxAmplitude(Float.NaN), TEST_TOLERANCE);
         assertEquals(0f, profile.getMaxAmplitude(100f), TEST_TOLERANCE);
         assertEquals(0f, profile.getMaxAmplitude(200f), TEST_TOLERANCE);
 
-        profile = new VibratorInfo.FrequencyProfile(
+        profile = new VibratorInfo.FrequencyProfileLegacy(
                         /* resonantFrequencyHz= */ 150,
                         /* minFrequencyHz= */ Float.NaN,
                         /* frequencyResolutionHz= */ Float.NaN,
@@ -257,7 +381,7 @@
 
     @Test
     public void testGetMaxAmplitude_validProfileReturnsMappedValues() {
-        VibratorInfo.FrequencyProfile profile = new VibratorInfo.FrequencyProfile(
+        VibratorInfo.FrequencyProfileLegacy profile = new VibratorInfo.FrequencyProfileLegacy(
                         /* resonantFrequencyHz= */ 150,
                         /* minFrequencyHz= */ 50,
                         /* frequencyResolutionHz= */ 25,
@@ -301,6 +425,7 @@
                     .setPwlePrimitiveDurationMax(50)
                     .setPwleSizeMax(20)
                     .setQFactor(2f)
+                    .setFrequencyProfileLegacy(TEST_FREQUENCY_PROFILE_LEGACY)
                     .setFrequencyProfile(TEST_FREQUENCY_PROFILE)
                     .setMaxEnvelopeEffectSize(16)
                     .setMinEnvelopeEffectControlPointDurationMillis(20)
@@ -343,18 +468,33 @@
         assertNotEquals(complete, completeWithDifferentPrimitiveDuration);
         assertFalse(complete.equalContent(completeWithDifferentPrimitiveDuration));
 
-        VibratorInfo completeWithDifferentFrequencyProfile = completeBuilder
-                .setFrequencyProfile(new VibratorInfo.FrequencyProfile(
+        VibratorInfo completeWithDifferentFrequencyProfileLegacy = completeBuilder
+                .setFrequencyProfileLegacy(new VibratorInfo.FrequencyProfileLegacy(
                         TEST_RESONANT_FREQUENCY + 20,
                         TEST_MIN_FREQUENCY + 10,
                         TEST_FREQUENCY_RESOLUTION + 5,
                         TEST_AMPLITUDE_MAP))
                 .build();
+        assertNotEquals(complete, completeWithDifferentFrequencyProfileLegacy);
+        assertFalse(complete.equalContent(completeWithDifferentFrequencyProfileLegacy));
+
+        VibratorInfo completeWithEmptyFrequencyProfileLegacy = completeBuilder
+                .setFrequencyProfileLegacy(EMPTY_FREQUENCY_PROFILE)
+                .build();
+        assertNotEquals(complete, completeWithEmptyFrequencyProfileLegacy);
+        assertFalse(complete.equalContent(completeWithEmptyFrequencyProfileLegacy));
+
+        VibratorInfo completeWithDifferentFrequencyProfile = completeBuilder
+                .setFrequencyProfile(
+                        new VibratorInfo.FrequencyProfile(TEST_RESONANT_FREQUENCY + 20,
+                                new float[]{90f, 150f}, new float[]{1.2f, 2.2f}))
+                .build();
         assertNotEquals(complete, completeWithDifferentFrequencyProfile);
         assertFalse(complete.equalContent(completeWithDifferentFrequencyProfile));
 
         VibratorInfo completeWithEmptyFrequencyProfile = completeBuilder
-                .setFrequencyProfile(EMPTY_FREQUENCY_PROFILE)
+                .setFrequencyProfile(
+                        new VibratorInfo.FrequencyProfile(Float.NaN, null, null))
                 .build();
         assertNotEquals(complete, completeWithEmptyFrequencyProfile);
         assertFalse(complete.equalContent(completeWithEmptyFrequencyProfile));
@@ -391,6 +531,7 @@
                 .setSupportedEffects(VibrationEffect.EFFECT_CLICK)
                 .setSupportedPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 20)
                 .setQFactor(Float.NaN)
+                .setFrequencyProfileLegacy(TEST_FREQUENCY_PROFILE_LEGACY)
                 .setFrequencyProfile(TEST_FREQUENCY_PROFILE)
                 .build();
 
diff --git a/core/tests/vibrator/src/android/os/vibrator/MultiVibratorInfoTest.java b/core/tests/vibrator/src/android/os/vibrator/MultiVibratorInfoTest.java
index fc31ac4..c9ab297 100644
--- a/core/tests/vibrator/src/android/os/vibrator/MultiVibratorInfoTest.java
+++ b/core/tests/vibrator/src/android/os/vibrator/MultiVibratorInfoTest.java
@@ -16,6 +16,8 @@
 
 package android.os.vibrator;
 
+import static com.google.common.truth.Truth.assertThat;
+
 import static junit.framework.Assert.assertFalse;
 import static junit.framework.Assert.assertTrue;
 import static junit.framework.TestCase.assertEquals;
@@ -24,7 +26,11 @@
 import android.os.VibrationEffect;
 import android.os.Vibrator;
 import android.os.VibratorInfo;
+import android.platform.test.annotations.DisableFlags;
+import android.platform.test.annotations.EnableFlags;
+import android.platform.test.flag.junit.SetFlagsRule;
 
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
@@ -33,6 +39,9 @@
 public class MultiVibratorInfoTest {
     private static final float TEST_TOLERANCE = 1e-5f;
 
+    @Rule
+    public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+
     @Test
     public void testGetId() {
         VibratorInfo firstInfo = new VibratorInfo.Builder(/* id= */ 1)
@@ -157,16 +166,17 @@
     }
 
     @Test
+    @DisableFlags(android.os.vibrator.Flags.FLAG_NORMALIZED_PWLE_EFFECTS)
     public void testGetQFactorAndResonantFrequency_differentValues_returnsNaN() {
         VibratorInfo firstInfo = new VibratorInfo.Builder(/* id= */ 1)
                 .setCapabilities(IVibrator.CAP_FREQUENCY_CONTROL)
                 .setQFactor(1f)
-                .setFrequencyProfile(new VibratorInfo.FrequencyProfile(1, 1, 1, null))
+                .setFrequencyProfileLegacy(new VibratorInfo.FrequencyProfileLegacy(1, 1, 1, null))
                 .build();
         VibratorInfo secondInfo = new VibratorInfo.Builder(/* id= */ 2)
                 .setCapabilities(IVibrator.CAP_FREQUENCY_CONTROL)
                 .setQFactor(2f)
-                .setFrequencyProfile(new VibratorInfo.FrequencyProfile(2, 2, 2, null))
+                .setFrequencyProfileLegacy(new VibratorInfo.FrequencyProfileLegacy(2, 2, 2, null))
                 .build();
 
         VibratorInfo info = new MultiVibratorInfo(/* id= */ 1,
@@ -187,17 +197,18 @@
     }
 
     @Test
+    @DisableFlags(android.os.vibrator.Flags.FLAG_NORMALIZED_PWLE_EFFECTS)
     public void testGetQFactorAndResonantFrequency_sameValues_returnsValue() {
         VibratorInfo firstInfo = new VibratorInfo.Builder(/* id= */ 1)
                 .setCapabilities(IVibrator.CAP_FREQUENCY_CONTROL)
                 .setQFactor(10f)
-                .setFrequencyProfile(new VibratorInfo.FrequencyProfile(
+                .setFrequencyProfileLegacy(new VibratorInfo.FrequencyProfileLegacy(
                         /* resonantFrequencyHz= */ 11, 10, 0.5f, null))
                 .build();
         VibratorInfo secondInfo = new VibratorInfo.Builder(/* id= */ 2)
                 .setCapabilities(IVibrator.CAP_FREQUENCY_CONTROL)
                 .setQFactor(10f)
-                .setFrequencyProfile(new VibratorInfo.FrequencyProfile(
+                .setFrequencyProfileLegacy(new VibratorInfo.FrequencyProfileLegacy(
                         /* resonantFrequencyHz= */ 11, 5, 1, null))
                 .build();
 
@@ -207,20 +218,21 @@
         assertEquals(10f, info.getQFactor(), TEST_TOLERANCE);
         assertEquals(11f, info.getResonantFrequencyHz(), TEST_TOLERANCE);
         // No frequency range defined.
-        assertTrue(info.getFrequencyProfile().isEmpty());
+        assertTrue(info.getFrequencyProfileLegacy().isEmpty());
         assertEquals(false, info.hasCapability(IVibrator.CAP_FREQUENCY_CONTROL));
     }
 
     @Test
-    public void testGetFrequencyProfile_differentResonantFrequencyOrResolutions_returnsEmpty() {
+    @DisableFlags(android.os.vibrator.Flags.FLAG_NORMALIZED_PWLE_EFFECTS)
+    public void testGetFrequencyProfileLegacy_differentResonantFreqOrResolutions_returnsEmpty() {
         VibratorInfo firstInfo = new VibratorInfo.Builder(/* id= */ 1)
                 .setCapabilities(IVibrator.CAP_FREQUENCY_CONTROL)
-                .setFrequencyProfile(new VibratorInfo.FrequencyProfile(1, 1, 1,
+                .setFrequencyProfileLegacy(new VibratorInfo.FrequencyProfileLegacy(1, 1, 1,
                         new float[] { 0, 1 }))
                 .build();
         VibratorInfo differentResonantFrequency = new VibratorInfo.Builder(/* id= */ 2)
                 .setCapabilities(IVibrator.CAP_FREQUENCY_CONTROL)
-                .setFrequencyProfile(new VibratorInfo.FrequencyProfile(2, 1, 1,
+                .setFrequencyProfileLegacy(new VibratorInfo.FrequencyProfileLegacy(2, 1, 1,
                         new float[] { 0, 1 }))
                 .build();
         VibratorInfo info = new MultiVibratorInfo(/* id= */ 1,
@@ -230,7 +242,7 @@
 
         VibratorInfo differentFrequencyResolution = new VibratorInfo.Builder(/* id= */ 2)
                 .setCapabilities(IVibrator.CAP_FREQUENCY_CONTROL)
-                .setFrequencyProfile(new VibratorInfo.FrequencyProfile(1, 1, 2,
+                .setFrequencyProfileLegacy(new VibratorInfo.FrequencyProfileLegacy(1, 1, 2,
                         new float[] { 0, 1 }))
                 .build();
         info = new MultiVibratorInfo(/* id= */ 1,
@@ -240,15 +252,16 @@
     }
 
     @Test
-    public void testGetFrequencyProfile_missingValues_returnsEmpty() {
+    @DisableFlags(android.os.vibrator.Flags.FLAG_NORMALIZED_PWLE_EFFECTS)
+    public void testGetFrequencyProfileLegacy_missingValues_returnsEmpty() {
         VibratorInfo firstInfo = new VibratorInfo.Builder(/* id= */ 1)
                 .setCapabilities(IVibrator.CAP_FREQUENCY_CONTROL)
-                .setFrequencyProfile(new VibratorInfo.FrequencyProfile(1, 1, 1,
+                .setFrequencyProfileLegacy(new VibratorInfo.FrequencyProfileLegacy(1, 1, 1,
                         new float[] { 0, 1 }))
                 .build();
         VibratorInfo missingResonantFrequency = new VibratorInfo.Builder(/* id= */ 2)
                 .setCapabilities(IVibrator.CAP_FREQUENCY_CONTROL)
-                .setFrequencyProfile(new VibratorInfo.FrequencyProfile(Float.NaN, 1, 1,
+                .setFrequencyProfileLegacy(new VibratorInfo.FrequencyProfileLegacy(Float.NaN, 1, 1,
                         new float[] { 0, 1 }))
                 .build();
 
@@ -259,7 +272,7 @@
 
         VibratorInfo missingMinFrequency = new VibratorInfo.Builder(/* id= */ 2)
                 .setCapabilities(IVibrator.CAP_FREQUENCY_CONTROL)
-                .setFrequencyProfile(new VibratorInfo.FrequencyProfile(1, Float.NaN, 1,
+                .setFrequencyProfileLegacy(new VibratorInfo.FrequencyProfileLegacy(1, Float.NaN, 1,
                         new float[] { 0, 1 }))
                 .build();
         info = new MultiVibratorInfo(/* id= */ 1,
@@ -269,7 +282,7 @@
 
         VibratorInfo missingFrequencyResolution = new VibratorInfo.Builder(/* id= */ 2)
                 .setCapabilities(IVibrator.CAP_FREQUENCY_CONTROL)
-                .setFrequencyProfile(new VibratorInfo.FrequencyProfile(1, 1, Float.NaN,
+                .setFrequencyProfileLegacy(new VibratorInfo.FrequencyProfileLegacy(1, 1, Float.NaN,
                         new float[] { 0, 1 }))
                 .build();
         info = new MultiVibratorInfo(/* id= */ 1,
@@ -279,7 +292,7 @@
 
         VibratorInfo missingMaxAmplitudes = new VibratorInfo.Builder(/* id= */ 2)
                 .setCapabilities(IVibrator.CAP_FREQUENCY_CONTROL)
-                .setFrequencyProfile(new VibratorInfo.FrequencyProfile(1, 1, 1, null))
+                .setFrequencyProfileLegacy(new VibratorInfo.FrequencyProfileLegacy(1, 1, 1, null))
                 .build();
         info = new MultiVibratorInfo(/* id= */ 1,
                 new VibratorInfo[]{firstInfo, missingMaxAmplitudes});
@@ -288,20 +301,21 @@
     }
 
     @Test
-    public void testGetFrequencyProfile_unalignedMaxAmplitudes_returnsEmpty() {
+    @DisableFlags(android.os.vibrator.Flags.FLAG_NORMALIZED_PWLE_EFFECTS)
+    public void testGetFrequencyProfileLegacy_unalignedMaxAmplitudes_returnsEmpty() {
         VibratorInfo firstInfo = new VibratorInfo.Builder(/* id= */ 1)
                 .setCapabilities(IVibrator.CAP_FREQUENCY_CONTROL)
-                .setFrequencyProfile(new VibratorInfo.FrequencyProfile(11, 10, 0.5f,
+                .setFrequencyProfileLegacy(new VibratorInfo.FrequencyProfileLegacy(11, 10, 0.5f,
                         new float[] { 0, 1, 1, 0 }))
                 .build();
         VibratorInfo unalignedMinFrequency = new VibratorInfo.Builder(/* id= */ 2)
                 .setCapabilities(IVibrator.CAP_FREQUENCY_CONTROL)
-                .setFrequencyProfile(new VibratorInfo.FrequencyProfile(11, 10.1f, 0.5f,
+                .setFrequencyProfileLegacy(new VibratorInfo.FrequencyProfileLegacy(11, 10.1f, 0.5f,
                         new float[] { 0, 1, 1, 0 }))
                 .build();
         VibratorInfo thirdVibrator = new VibratorInfo.Builder(/* id= */ 2)
                 .setCapabilities(IVibrator.CAP_FREQUENCY_CONTROL)
-                .setFrequencyProfile(new VibratorInfo.FrequencyProfile(11, 10.5f, 0.5f,
+                .setFrequencyProfileLegacy(new VibratorInfo.FrequencyProfileLegacy(11, 10.5f, 0.5f,
                         new float[] { 0, 1, 1, 0 }))
                 .build();
 
@@ -312,20 +326,21 @@
     }
 
     @Test
-    public void testGetFrequencyProfile_alignedProfiles_returnsIntersection() {
+    @DisableFlags(android.os.vibrator.Flags.FLAG_NORMALIZED_PWLE_EFFECTS)
+    public void testGetFrequencyProfileLegacy_alignedProfiles_returnsIntersection() {
         VibratorInfo firstInfo = new VibratorInfo.Builder(/* id= */ 1)
                 .setCapabilities(IVibrator.CAP_FREQUENCY_CONTROL)
-                .setFrequencyProfile(new VibratorInfo.FrequencyProfile(11, 10, 0.5f,
+                .setFrequencyProfileLegacy(new VibratorInfo.FrequencyProfileLegacy(11, 10, 0.5f,
                         new float[] { 0.5f, 1, 1, 0.5f }))
                 .build();
         VibratorInfo secondInfo = new VibratorInfo.Builder(/* id= */ 2)
                 .setCapabilities(IVibrator.CAP_FREQUENCY_CONTROL)
-                .setFrequencyProfile(new VibratorInfo.FrequencyProfile(11, 10.5f, 0.5f,
+                .setFrequencyProfileLegacy(new VibratorInfo.FrequencyProfileLegacy(11, 10.5f, 0.5f,
                         new float[] { 1, 1, 1 }))
                 .build();
         VibratorInfo thirdVibrator = new VibratorInfo.Builder(/* id= */ 3)
                 .setCapabilities(IVibrator.CAP_FREQUENCY_CONTROL)
-                .setFrequencyProfile(new VibratorInfo.FrequencyProfile(11, 10.5f, 0.5f,
+                .setFrequencyProfileLegacy(new VibratorInfo.FrequencyProfileLegacy(11, 10.5f, 0.5f,
                         new float[] { 0.8f, 1, 0.8f, 0.5f }))
                 .build();
 
@@ -333,29 +348,157 @@
                 new VibratorInfo[]{firstInfo, secondInfo, thirdVibrator});
 
         assertEquals(
-                new VibratorInfo.FrequencyProfile(11, 10.5f, 0.5f, new float[] { 0.8f, 1, 0.5f }),
-                info.getFrequencyProfile());
+                new VibratorInfo.FrequencyProfileLegacy(11, 10.5f, 0.5f,
+                        new float[]{0.8f, 1, 0.5f}),
+                info.getFrequencyProfileLegacy());
         assertEquals(true, info.hasCapability(IVibrator.CAP_FREQUENCY_CONTROL));
 
         // Third vibrator without frequency control capability.
         thirdVibrator = new VibratorInfo.Builder(/* id= */ 3)
-                .setFrequencyProfile(new VibratorInfo.FrequencyProfile(11, 10.5f, 0.5f,
+                .setFrequencyProfileLegacy(new VibratorInfo.FrequencyProfileLegacy(11, 10.5f, 0.5f,
                         new float[] { 0.8f, 1, 0.8f, 0.5f }))
                 .build();
         info = new MultiVibratorInfo(/* id= */ 1,
                 new VibratorInfo[]{firstInfo, secondInfo, thirdVibrator});
 
         assertEquals(
-                new VibratorInfo.FrequencyProfile(11, 10.5f, 0.5f, new float[] { 0.8f, 1, 0.5f }),
-                info.getFrequencyProfile());
+                new VibratorInfo.FrequencyProfileLegacy(11, 10.5f, 0.5f,
+                        new float[]{0.8f, 1, 0.5f}),
+                info.getFrequencyProfileLegacy());
         assertEquals(false, info.hasCapability(IVibrator.CAP_FREQUENCY_CONTROL));
     }
 
+    @Test
+    @EnableFlags(android.os.vibrator.Flags.FLAG_NORMALIZED_PWLE_EFFECTS)
+    public void testGetFrequencyProfile_alignedProfiles_returnsIntersection() {
+        VibratorInfo firstInfo = createVibratorInfoWithFrequencyProfile(/*id=*/ 1,
+                IVibrator.CAP_FREQUENCY_CONTROL, /*resonantFrequencyHz=*/ 180f,
+                /*frequencies=*/new float[]{30f, 60f, 120f, 150f, 180f, 210f, 270f, 300f},
+                /*accelerations=*/new float[]{0.1f, 0.6f, 1.8f, 2.4f, 3.0f, 2.2f, 1.0f, 0.5f});
+
+        VibratorInfo secondInfo = createVibratorInfoWithFrequencyProfile(/*id=*/ 2,
+                IVibrator.CAP_FREQUENCY_CONTROL, /*resonantFrequencyHz=*/ 180f,
+                /*frequencies=*/new float[]{120f, 150f, 180f, 210f},
+                /*accelerations=*/new float[]{1.5f, 2.6f, 2.7f, 2.1f});
+
+        VibratorInfo.FrequencyProfile expectedFrequencyProfile =
+                new VibratorInfo.FrequencyProfile(/*resonantFrequencyHz=*/
+                        180f, /*frequenciesHz=*/new float[]{120.0f, 150.0f, 180.0f, 210.0f},
+                        /*outputAccelerationsGs=*/new float[]{1.5f, 2.4f, 2.7f, 2.1f});
+
+        VibratorInfo info = new MultiVibratorInfo(/* id= */ 1,
+                new VibratorInfo[]{firstInfo, secondInfo});
+
+        assertThat(info.getFrequencyProfile()).isEqualTo(expectedFrequencyProfile);
+    }
+
+    @Test
+    @EnableFlags(android.os.vibrator.Flags.FLAG_NORMALIZED_PWLE_EFFECTS)
+    public void testGetFrequencyProfile_alignedProfilesUsingInterpolation_returnsIntersection() {
+        VibratorInfo firstInfo = createVibratorInfoWithFrequencyProfile(/*id=*/ 1,
+                IVibrator.CAP_FREQUENCY_CONTROL, /*resonantFrequencyHz=*/ 180f,
+                /*frequencies=*/new float[]{30f, 60f, 120f},
+                /*accelerations=*/new float[]{0.25f, 1.0f, 4.0f});
+
+        VibratorInfo secondInfo = createVibratorInfoWithFrequencyProfile(/*id=*/ 2,
+                IVibrator.CAP_FREQUENCY_CONTROL, /*resonantFrequencyHz=*/ 180f,
+                /*frequencies=*/new float[]{40f, 70f, 110f},
+                /*accelerations=*/new float[]{1.0f, 2.5f, 4.0f});
+
+        VibratorInfo.FrequencyProfile expectedFrequencyProfile =
+                new VibratorInfo.FrequencyProfile(/*resonantFrequencyHz=*/
+                        180f, /*frequenciesHz=*/new float[]{40f, 60f, 70f, 110f},
+                        /*outputAccelerationsGs=*/new float[]{0.5f, 1.0f, 1.5f, 3.5f});
+
+        VibratorInfo info = new MultiVibratorInfo(/* id= */ 1,
+                new VibratorInfo[]{firstInfo, secondInfo});
+
+        assertThat(info.getFrequencyProfile()).isEqualTo(expectedFrequencyProfile);
+    }
+
+    @Test
+    @EnableFlags(android.os.vibrator.Flags.FLAG_NORMALIZED_PWLE_EFFECTS)
+    public void testGetFrequencyProfile_disjointFrequencyRange_returnsEmpty() {
+
+        VibratorInfo firstInfo = createVibratorInfoWithFrequencyProfile(/*id=*/ 1,
+                IVibrator.CAP_FREQUENCY_CONTROL, /*resonantFrequencyHz=*/ 180f,
+                /*frequencies=*/new float[]{30f, 60f, 120f, 150f, 180f, 210f, 270f, 300f},
+                /*accelerations=*/new float[]{0.1f, 0.6f, 1.8f, 2.4f, 3.0f, 2.2f, 1.0f, 0.5f});
+
+        VibratorInfo secondInfo = createVibratorInfoWithFrequencyProfile(/*id=*/ 2,
+                IVibrator.CAP_FREQUENCY_CONTROL, /*resonantFrequencyHz=*/ 180f,
+                /*frequencies=*/new float[]{310f, 320f, 350f, 380f, 410f, 440f},
+                /*accelerations=*/new float[]{0.3f, 0.75f, 1.82f, 2.11f, 2.8f, 2.12f, 1.4f, 0.42f});
+
+        VibratorInfo info = new MultiVibratorInfo(/* id= */ 1,
+                new VibratorInfo[]{firstInfo, secondInfo});
+
+        assertThat(info.getFrequencyProfile()).isEqualTo(
+                new VibratorInfo.FrequencyProfile(/*resonantFrequencyHz=*/ Float.NaN,
+                        /*frequenciesHz=*/null, /*outputAccelerationsGs=*/null));
+        assertThat(info.hasCapability(IVibrator.CAP_FREQUENCY_CONTROL)).isFalse();
+    }
+
+    @Test
+    @EnableFlags(android.os.vibrator.Flags.FLAG_NORMALIZED_PWLE_EFFECTS)
+    public void testGetFrequencyProfile_emptyFrequencyRange_returnsEmpty() {
+        VibratorInfo firstInfo = createVibratorInfoWithFrequencyProfile(/*id=*/ 1,
+                IVibrator.CAP_FREQUENCY_CONTROL, /*resonantFrequencyHz=*/180f,
+                /*frequencies=*/null, /*accelerations=*/null);
+
+        VibratorInfo secondInfo = createVibratorInfoWithFrequencyProfile(/*id=*/ 2,
+                IVibrator.CAP_FREQUENCY_CONTROL, /*resonantFrequencyHz=*/180f,
+                /*frequencies=*/new float[]{30f, 60f, 150f, 180f, 210f, 240f, 300f},
+                /*accelerations=*/new float[]{0.1f, 0.6f, 2.4f, 3.0f, 2.2f, 1.9f, 0.5f});
+
+        VibratorInfo info = new MultiVibratorInfo(/* id= */ 1,
+                new VibratorInfo[]{firstInfo, secondInfo});
+
+        assertThat(info.getFrequencyProfile()).isEqualTo(
+                new VibratorInfo.FrequencyProfile(/*resonantFrequencyHz=*/ Float.NaN,
+                        /*frequenciesHz=*/null,
+                        /*outputAccelerationsGs=*/null));
+        assertThat(info.hasCapability(IVibrator.CAP_FREQUENCY_CONTROL)).isFalse();
+    }
+
+    @Test
+    @EnableFlags(android.os.vibrator.Flags.FLAG_NORMALIZED_PWLE_EFFECTS)
+    public void testGetFrequencyProfile_differentResonantFrequency_returnsEmpty() {
+        VibratorInfo firstInfo = createVibratorInfoWithFrequencyProfile(/*id=*/ 1,
+                IVibrator.CAP_FREQUENCY_CONTROL, /*resonantFrequencyHz=*/ 160f,
+                /*frequencies=*/new float[]{30f, 60f, 120f, 150f, 180f, 210f, 270f, 300f},
+                /*accelerations=*/new float[]{0.1f, 0.6f, 1.8f, 2.4f, 3.0f, 2.2f, 1.0f, 0.5f});
+
+        VibratorInfo secondInfo = createVibratorInfoWithFrequencyProfile(/*id=*/ 2,
+                IVibrator.CAP_FREQUENCY_CONTROL, /*resonantFrequencyHz=*/ 180f,
+                /*frequencies=*/new float[]{30f, 60f, 120f, 150f, 180f, 210f, 270f, 300f},
+                /*accelerations=*/new float[]{0.1f, 0.6f, 1.8f, 2.4f, 3.0f, 2.2f, 1.0f, 0.5f});
+
+        VibratorInfo info = new MultiVibratorInfo(/* id= */ 1,
+                new VibratorInfo[]{firstInfo, secondInfo});
+
+        assertThat(info.getFrequencyProfile()).isEqualTo(
+                new VibratorInfo.FrequencyProfile(/*resonantFrequencyHz=*/ Float.NaN,
+                        /*frequenciesHz=*/null,
+                        /*outputAccelerationsGs=*/null));
+        assertThat(info.hasCapability(IVibrator.CAP_FREQUENCY_CONTROL)).isFalse();
+    }
+
+    private VibratorInfo createVibratorInfoWithFrequencyProfile(int id, long capabilities,
+            float resonantFrequencyHz, float[] frequencies, float[] accelerations) {
+        return new VibratorInfo.Builder(id)
+                .setCapabilities(capabilities)
+                .setFrequencyProfile(
+                        new VibratorInfo.FrequencyProfile(resonantFrequencyHz, frequencies,
+                                accelerations))
+                .build();
+    }
+
     /**
      * Asserts that the frequency profile is empty, and therefore frequency control isn't supported.
      */
     private void assertEmptyFrequencyProfileAndControl(VibratorInfo info) {
-        assertTrue(info.getFrequencyProfile().isEmpty());
+        assertTrue(info.getFrequencyProfileLegacy().isEmpty());
         assertEquals(false, info.hasCapability(IVibrator.CAP_FREQUENCY_CONTROL));
     }
 }
diff --git a/keystore/OWNERS b/keystore/OWNERS
index 6891777..ea783e7 100644
--- a/keystore/OWNERS
+++ b/keystore/OWNERS
@@ -1,5 +1,6 @@
 # Bug component: 189335
+ascull@google.com
 drysdale@google.com
-eranm@google.com
 jbires@google.com
+sethmo@google.com
 swillden@google.com
diff --git a/libs/WindowManager/Shell/Android.bp b/libs/WindowManager/Shell/Android.bp
index e493ed1..4642fe5 100644
--- a/libs/WindowManager/Shell/Android.bp
+++ b/libs/WindowManager/Shell/Android.bp
@@ -234,10 +234,6 @@
         // *.kt sources are inside a filegroup.
         "kotlin-annotations",
     ],
-    required: [
-        "wmshell.protolog.json.gz",
-        "wmshell.protolog.pb",
-    ],
     flags_packages: [
         "com_android_wm_shell_flags",
     ],
@@ -246,3 +242,11 @@
     plugins: ["dagger2-compiler"],
     use_resource_processor: true,
 }
+
+java_defaults {
+    name: "wmshell_defaults",
+    required: [
+        "wmshell.protolog.json.gz",
+        "wmshell.protolog.pb",
+    ],
+}
diff --git a/libs/WindowManager/Shell/AndroidManifest.xml b/libs/WindowManager/Shell/AndroidManifest.xml
index 3b739c3..1260796 100644
--- a/libs/WindowManager/Shell/AndroidManifest.xml
+++ b/libs/WindowManager/Shell/AndroidManifest.xml
@@ -24,6 +24,7 @@
     <uses-permission android:name="android.permission.WAKEUP_SURFACE_FLINGER" />
     <uses-permission android:name="android.permission.READ_FRAME_BUFFER" />
     <uses-permission android:name="android.permission.SUBSCRIBE_TO_KEYGUARD_LOCKED_STATE" />
+    <uses-permission android:name="android.permission.UPDATE_DOMAIN_VERIFICATION_USER_SELECTION" />
 
     <application>
         <activity
diff --git a/libs/WindowManager/Shell/res/drawable/app_handle_education_tooltip_icon.xml b/libs/WindowManager/Shell/res/drawable/app_handle_education_tooltip_icon.xml
index b74d922..2d5597e 100644
--- a/libs/WindowManager/Shell/res/drawable/app_handle_education_tooltip_icon.xml
+++ b/libs/WindowManager/Shell/res/drawable/app_handle_education_tooltip_icon.xml
@@ -19,9 +19,15 @@
     android:width="24dp"
     android:height="24dp"
     android:tint="?android:attr/textColorTertiary"
-    android:viewportHeight="960"
-    android:viewportWidth="960">
+    android:viewportHeight="24"
+    android:viewportWidth="24">
     <path
         android:fillColor="@android:color/system_on_tertiary_container_light"
-        android:pathData="M419,880Q391,880 366.5,868Q342,856 325,834L107,557L126,537Q146,516 174,512Q202,508 226,523L300,568L300,240Q300,223 311.5,211.5Q323,200 340,200Q357,200 369,211.5Q381,223 381,240L381,712L284,652L388,785Q394,792 402,796Q410,800 419,800L640,800Q673,800 696.5,776.5Q720,753 720,720L720,560Q720,543 708.5,531.5Q697,520 680,520L461,520L461,440L680,440Q730,440 765,475Q800,510 800,560L800,720Q800,786 753,833Q706,880 640,880L419,880ZM167,340Q154,318 147,292.5Q140,267 140,240Q140,157 198.5,98.5Q257,40 340,40Q423,40 481.5,98.5Q540,157 540,240Q540,267 533,292.5Q526,318 513,340L444,300Q452,286 456,271.5Q460,257 460,240Q460,190 425,155Q390,120 340,120Q290,120 255,155Q220,190 220,240Q220,257 224,271.5Q228,286 236,300L167,340ZM502,620L502,620L502,620L502,620Q502,620 502,620Q502,620 502,620L502,620Q502,620 502,620Q502,620 502,620L502,620Q502,620 502,620Q502,620 502,620L502,620L502,620Z" />
-</vector>
+        android:pathData="M12,22c1.1,0 2,-0.9 2,-2h-4C10,21.1 10.9,22 12,22z"/>
+    <path
+        android:fillColor="@android:color/system_on_tertiary_container_light"
+        android:pathData="M8,17h8v2h-8z"/>
+    <path
+        android:fillColor="@android:color/system_on_tertiary_container_light"
+        android:pathData="M12,2C7.86,2 4.5,5.36 4.5,9.5c0,3.82 2.66,5.86 3.77,6.5h7.46c1.11,-0.64 3.77,-2.68 3.77,-6.5C19.5,5.36 16.14,2 12,2z"/>
+  </vector>
diff --git a/libs/WindowManager/Shell/res/drawable/desktop_windowing_education_tooltip_background.xml b/libs/WindowManager/Shell/res/drawable/desktop_windowing_education_tooltip_background.xml
index a12a746..473236c 100644
--- a/libs/WindowManager/Shell/res/drawable/desktop_windowing_education_tooltip_background.xml
+++ b/libs/WindowManager/Shell/res/drawable/desktop_windowing_education_tooltip_background.xml
@@ -18,7 +18,7 @@
 <layer-list xmlns:android="http://schemas.android.com/apk/res/android">
     <item>
         <shape android:shape="rectangle">
-            <corners android:radius="30dp" />
+            <corners android:radius="28dp" />
             <solid android:color="@android:color/system_tertiary_fixed" />
         </shape>
     </item>
diff --git a/libs/WindowManager/Shell/res/drawable/open_by_default_settings_dialog_dismiss_button_background.xml b/libs/WindowManager/Shell/res/drawable/open_by_default_settings_dialog_confirm_button_background.xml
similarity index 100%
rename from libs/WindowManager/Shell/res/drawable/open_by_default_settings_dialog_dismiss_button_background.xml
rename to libs/WindowManager/Shell/res/drawable/open_by_default_settings_dialog_confirm_button_background.xml
diff --git a/libs/WindowManager/Shell/res/layout/desktop_windowing_education_left_arrow_tooltip.xml b/libs/WindowManager/Shell/res/layout/desktop_windowing_education_left_arrow_tooltip.xml
index a269b9e..fd75827 100644
--- a/libs/WindowManager/Shell/res/layout/desktop_windowing_education_left_arrow_tooltip.xml
+++ b/libs/WindowManager/Shell/res/layout/desktop_windowing_education_left_arrow_tooltip.xml
@@ -26,6 +26,7 @@
         android:id="@+id/arrow_icon"
         android:layout_width="10dp"
         android:layout_height="12dp"
+        android:elevation="2dp"
         android:layout_gravity="center_vertical"
         android:src="@drawable/desktop_windowing_education_tooltip_left_arrow" />
 
diff --git a/libs/WindowManager/Shell/res/layout/desktop_windowing_education_tooltip_container.xml b/libs/WindowManager/Shell/res/layout/desktop_windowing_education_tooltip_container.xml
index 09a049c..42f955d 100644
--- a/libs/WindowManager/Shell/res/layout/desktop_windowing_education_tooltip_container.xml
+++ b/libs/WindowManager/Shell/res/layout/desktop_windowing_education_tooltip_container.xml
@@ -16,16 +16,18 @@
 
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:id="@+id/tooltip_container"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
     android:background="@drawable/desktop_windowing_education_tooltip_background"
     android:orientation="horizontal"
+    android:elevation="2dp"
     android:padding="@dimen/desktop_windowing_education_tooltip_padding">
 
     <ImageView
         android:id="@+id/tooltip_icon"
         android:layout_width="32dp"
         android:layout_height="32dp"
+        android:layout_margin="8dp"
         android:layout_gravity="center_vertical"
         android:src="@drawable/app_handle_education_tooltip_icon" />
 
@@ -34,9 +36,9 @@
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:layout_gravity="center_vertical"
-        android:layout_marginStart="2dp"
+        android:layout_marginHorizontal="8dp"
         android:lineHeight="20dp"
-        android:maxWidth="150dp"
+        android:maxWidth="220dp"
         android:textColor="@android:color/system_on_tertiary_container_light"
         android:textFontWeight="500"
         android:textSize="14sp" />
diff --git a/libs/WindowManager/Shell/res/layout/desktop_windowing_education_top_arrow_tooltip.xml b/libs/WindowManager/Shell/res/layout/desktop_windowing_education_top_arrow_tooltip.xml
index c73c1da..83d7ef7 100644
--- a/libs/WindowManager/Shell/res/layout/desktop_windowing_education_top_arrow_tooltip.xml
+++ b/libs/WindowManager/Shell/res/layout/desktop_windowing_education_top_arrow_tooltip.xml
@@ -25,6 +25,7 @@
         android:id="@+id/arrow_icon"
         android:layout_width="12dp"
         android:layout_height="9dp"
+        android:elevation="2dp"
         android:layout_gravity="center_horizontal"
         android:src="@drawable/desktop_windowing_education_tooltip_top_arrow" />
 
diff --git a/libs/WindowManager/Shell/res/layout/open_by_default_settings_dialog.xml b/libs/WindowManager/Shell/res/layout/open_by_default_settings_dialog.xml
index 8ff382b..b5bceda 100644
--- a/libs/WindowManager/Shell/res/layout/open_by_default_settings_dialog.xml
+++ b/libs/WindowManager/Shell/res/layout/open_by_default_settings_dialog.xml
@@ -111,7 +111,7 @@
                 </RadioGroup>
 
                 <Button
-                    android:id="@+id/open_by_default_settings_dialog_dismiss_button"
+                    android:id="@+id/open_by_default_settings_dialog_confirm_button"
                     android:layout_width="wrap_content"
                     android:layout_height="36dp"
                     android:text="@string/open_by_default_dialog_dismiss_button_text"
@@ -122,7 +122,7 @@
                     android:textSize="14sp"
                     android:textFontWeight="500"
                     android:textColor="?androidprv:attr/materialColorOnPrimary"
-                    android:background="@drawable/open_by_default_settings_dialog_dismiss_button_background"/>
+                    android:background="@drawable/open_by_default_settings_dialog_confirm_button_background"/>
             </LinearLayout>
         </ScrollView>
     </FrameLayout>
diff --git a/libs/WindowManager/Shell/res/layout/pip2_menu_action.xml b/libs/WindowManager/Shell/res/layout/pip2_menu_action.xml
new file mode 100644
index 0000000..04ece31
--- /dev/null
+++ b/libs/WindowManager/Shell/res/layout/pip2_menu_action.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+    Copyright (C) 2024 The Android Open Source Project
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<com.android.wm.shell.pip2.phone.PipMenuActionView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="@dimen/pip_action_size"
+    android:layout_height="@dimen/pip_action_size"
+    android:background="?android:selectableItemBackgroundBorderless"
+    android:forceHasOverlappingRendering="false">
+
+    <ImageView
+        android:id="@+id/custom_close_bg"
+        android:layout_width="@dimen/pip_custom_close_bg_size"
+        android:layout_height="@dimen/pip_custom_close_bg_size"
+        android:layout_gravity="center"
+        android:src="@drawable/pip_custom_close_bg"
+        android:visibility="gone"/>
+
+    <ImageView
+        android:id="@+id/image"
+        android:layout_width="@dimen/pip_action_inner_size"
+        android:layout_height="@dimen/pip_action_inner_size"
+        android:layout_gravity="center"
+        android:scaleType="fitXY"/>
+
+</com.android.wm.shell.pip2.phone.PipMenuActionView>
diff --git a/libs/WindowManager/Shell/res/values-af/strings.xml b/libs/WindowManager/Shell/res/values-af/strings.xml
index 50aa4ca..be5a74b 100644
--- a/libs/WindowManager/Shell/res/values-af/strings.xml
+++ b/libs/WindowManager/Shell/res/values-af/strings.xml
@@ -97,6 +97,9 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Kamerakwessies?\nTik om aan te pas"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Nie opgelos nie?\nTik om terug te stel"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Geen kamerakwessies nie? Tik om toe te maak."</string>
+    <string name="windowing_app_handle_education_tooltip" msgid="6398482412956375783">"Tik om die appkieslys oop te maak"</string>
+    <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="6285279585554484957">"Tik om verskeie apps saam te wys"</string>
+    <string name="windowing_desktop_mode_exit_education_tooltip" msgid="6685429075790085337">"Keer terug na volskerm van die appkieslys af"</string>
     <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Sien en doen meer"</string>
     <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Sleep ’n ander app in vir verdeelde skerm"</string>
     <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Dubbeltik buite ’n program om dit te herposisioneer"</string>
@@ -126,15 +129,16 @@
     <string name="manage_windows_text" msgid="5567366688493093920">"Bestuur vensters"</string>
     <string name="close_text" msgid="4986518933445178928">"Maak toe"</string>
     <string name="collapse_menu_text" msgid="7515008122450342029">"Maak kieslys toe"</string>
-    <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) -->
-    <skip />
+    <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Maak kieslys oop"</string>
     <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maksimeer skerm"</string>
     <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Gryp skerm vas"</string>
-    <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"Hierdie app se grootte kan nie verander word nie"</string>
-    <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) -->
-    <skip />
-    <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) -->
-    <skip />
-    <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) -->
-    <skip />
+    <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"App kan nie hierheen geskuif word nie"</string>
+    <string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"Maksimeer"</string>
+    <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Spring na links"</string>
+    <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"Spring na regs"</string>
+    <string name="open_by_default_settings_text" msgid="2526548548598185500">"Maak By Verstek Oop-instellings"</string>
+    <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Kies hoe om webskakels vir hierdie app oop te maak"</string>
+    <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"In die app"</string>
+    <string name="open_by_default_dialog_in_browser_text" msgid="8042769465958497081">"In jou blaaier"</string>
+    <string name="open_by_default_dialog_dismiss_button_text" msgid="3487238795534582291">"OK"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-am/strings.xml b/libs/WindowManager/Shell/res/values-am/strings.xml
index 281e313..8c3e3fa 100644
--- a/libs/WindowManager/Shell/res/values-am/strings.xml
+++ b/libs/WindowManager/Shell/res/values-am/strings.xml
@@ -97,6 +97,9 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"የካሜራ ችግሮች አሉ?\nዳግም ለማበጀት መታ ያድርጉ"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"አልተስተካከለም?\nለማህደር መታ ያድርጉ"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"ምንም የካሜራ ችግሮች የሉም? ለማሰናበት መታ ያድርጉ።"</string>
+    <string name="windowing_app_handle_education_tooltip" msgid="6398482412956375783">"የመተግበሪያ ምናሌውን ለመክፈት መታ ያድርጉ"</string>
+    <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="6285279585554484957">"በርካታ መተግበሪያዎችን በአንድ ላይ ለማየት መታ ያድርጉ"</string>
+    <string name="windowing_desktop_mode_exit_education_tooltip" msgid="6685429075790085337">"ከመተግበሪያ ምናሌው ወደ ሙሉ ማያ ገፅ ይመለሱ"</string>
     <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"ተጨማሪ ይመልከቱ እና ያድርጉ"</string>
     <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"ለተከፈለ ማያ ገፅ ሌላ መተግበሪያ ይጎትቱ"</string>
     <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"ቦታውን ለመቀየር ከመተግበሪያው ውጭ ሁለቴ መታ ያድርጉ"</string>
@@ -126,15 +129,16 @@
     <string name="manage_windows_text" msgid="5567366688493093920">"መስኮቶችን አስተዳድር"</string>
     <string name="close_text" msgid="4986518933445178928">"ዝጋ"</string>
     <string name="collapse_menu_text" msgid="7515008122450342029">"ምናሌ ዝጋ"</string>
-    <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) -->
-    <skip />
+    <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"ምናሌን ክፈት"</string>
     <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"የማያ ገጹ መጠን አሳድግ"</string>
     <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"ማያ ገጹን አሳድግ"</string>
-    <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"ይህ መተግበሪያ መጠኑ ሊቀየር አይችልም"</string>
-    <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) -->
-    <skip />
-    <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) -->
-    <skip />
-    <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) -->
-    <skip />
+    <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"መተግበሪያ ወደዚህ መንቀሳቀስ አይችልም"</string>
+    <string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"አሳድግ"</string>
+    <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"ወደ ግራ አሳድግ"</string>
+    <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"ወደ ቀኝ አሳድግ"</string>
+    <string name="open_by_default_settings_text" msgid="2526548548598185500">"በነባሪ ቅንብሮች ክፈት"</string>
+    <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"ለዚህ የድር መተግበሪያ አገናኙን እንዴት እንደሚከፍቱ ይምረጡ"</string>
+    <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"በመተግበሪያው ውስጥ"</string>
+    <string name="open_by_default_dialog_in_browser_text" msgid="8042769465958497081">"በአሳሽዎ ውስጥ"</string>
+    <string name="open_by_default_dialog_dismiss_button_text" msgid="3487238795534582291">"እሺ"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-ar/strings.xml b/libs/WindowManager/Shell/res/values-ar/strings.xml
index 2c0b34a..4a34ce6 100644
--- a/libs/WindowManager/Shell/res/values-ar/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ar/strings.xml
@@ -97,6 +97,9 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"هل هناك مشاكل في الكاميرا؟\nانقر لإعادة الضبط."</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"ألم يتم حل المشكلة؟\nانقر للعودة"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"أليس هناك مشاكل في الكاميرا؟ انقر للإغلاق."</string>
+    <string name="windowing_app_handle_education_tooltip" msgid="6398482412956375783">"انقر لفتح قائمة التطبيق"</string>
+    <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="6285279585554484957">"انقر لعرض عدة تطبيقات معًا"</string>
+    <string name="windowing_desktop_mode_exit_education_tooltip" msgid="6685429075790085337">"الرجوع إلى وضع ملء الشاشة من قائمة التطبيق"</string>
     <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"استخدام تطبيقات متعدّدة في وقت واحد"</string>
     <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"اسحب تطبيقًا آخر لاستخدام وضع تقسيم الشاشة."</string>
     <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"انقر مرّتين خارج تطبيق لتغيير موضعه."</string>
@@ -126,15 +129,16 @@
     <string name="manage_windows_text" msgid="5567366688493093920">"إدارة النوافذ"</string>
     <string name="close_text" msgid="4986518933445178928">"إغلاق"</string>
     <string name="collapse_menu_text" msgid="7515008122450342029">"إغلاق القائمة"</string>
-    <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) -->
-    <skip />
+    <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"فتح القائمة"</string>
     <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"تكبير الشاشة إلى أقصى حدّ"</string>
     <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"التقاط صورة للشاشة"</string>
-    <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"لا يمكن تغيير حجم نافذة هذا التطبيق"</string>
-    <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) -->
-    <skip />
-    <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) -->
-    <skip />
-    <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) -->
-    <skip />
+    <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"لا يمكن نقل التطبيق إلى هنا"</string>
+    <string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"تكبير"</string>
+    <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"المحاذاة إلى اليسار"</string>
+    <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"المحاذاة إلى اليمين"</string>
+    <string name="open_by_default_settings_text" msgid="2526548548598185500">"إعدادات الفتح تلقائيًا"</string>
+    <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"اختيار طريقة فتح روابط الويب لهذا التطبيق"</string>
+    <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"في التطبيق"</string>
+    <string name="open_by_default_dialog_in_browser_text" msgid="8042769465958497081">"في المتصفِّح"</string>
+    <string name="open_by_default_dialog_dismiss_button_text" msgid="3487238795534582291">"حسنًا"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-as/strings.xml b/libs/WindowManager/Shell/res/values-as/strings.xml
index c5e3716..94c9ba3 100644
--- a/libs/WindowManager/Shell/res/values-as/strings.xml
+++ b/libs/WindowManager/Shell/res/values-as/strings.xml
@@ -97,6 +97,9 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"কেমেৰাৰ কোনো সমস্যা হৈছে নেকি?\nপুনৰ খাপ খোৱাবলৈ টিপক"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"এইটো সমাধান কৰা নাই নেকি?\nপূৰ্বাৱস্থালৈ নিবলৈ টিপক"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"কেমেৰাৰ কোনো সমস্যা নাই নেকি? অগ্ৰাহ্য কৰিবলৈ টিপক।"</string>
+    <string name="windowing_app_handle_education_tooltip" msgid="6398482412956375783">"এপৰ মেনুখন খুলিবলৈ টিপক"</string>
+    <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="6285279585554484957">"একাধিক এপ্ একেলগে দেখুৱাবলৈ টিপক"</string>
+    <string name="windowing_desktop_mode_exit_education_tooltip" msgid="6685429075790085337">"এপৰ মেনুখনৰ পৰা পূৰ্ণ স্ক্ৰীনলৈ উভতি যাওক"</string>
     <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"চাওক আৰু অধিক কৰক"</string>
     <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"বিভাজিত স্ক্ৰীনৰ বাবে অন্য এটা এপ্‌ টানি আনি এৰক"</string>
     <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"এপ্‌টোৰ স্থান সলনি কৰিবলৈ ইয়াৰ বাহিৰত দুবাৰ টিপক"</string>
@@ -126,15 +129,16 @@
     <string name="manage_windows_text" msgid="5567366688493093920">"ৱিণ্ড’ পৰিচালনা কৰক"</string>
     <string name="close_text" msgid="4986518933445178928">"বন্ধ কৰক"</string>
     <string name="collapse_menu_text" msgid="7515008122450342029">"মেনু বন্ধ কৰক"</string>
-    <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) -->
-    <skip />
+    <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"মেনু খোলক"</string>
     <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"স্ক্ৰীন মেক্সিমাইজ কৰক"</string>
     <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"স্ক্ৰীন স্নেপ কৰক"</string>
-    <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"এই এপ্‌টোৰ আকাৰ সলনি কৰিব নোৱাৰি"</string>
-    <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) -->
-    <skip />
-    <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) -->
-    <skip />
-    <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) -->
-    <skip />
+    <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"ইয়ালৈ এপ্‌টো আনিব নোৱাৰি"</string>
+    <string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"মেক্সিমাইজ কৰক"</string>
+    <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"বাওঁফাললৈ স্নেপ কৰক"</string>
+    <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"সোঁফাললৈ স্নেপ কৰক"</string>
+    <string name="open_by_default_settings_text" msgid="2526548548598185500">"ডিফ’ল্ট ছেটিং খোলক"</string>
+    <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"এই এপ্‌টোৰ বাবে কিদৰে ৱেব লিংক খুলিব পাৰি সেয়া বাছনি কৰক"</string>
+    <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"এপ্‌টোত"</string>
+    <string name="open_by_default_dialog_in_browser_text" msgid="8042769465958497081">"আপোনাৰ ব্ৰাউজাৰত"</string>
+    <string name="open_by_default_dialog_dismiss_button_text" msgid="3487238795534582291">"ঠিক আছে"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-az/strings.xml b/libs/WindowManager/Shell/res/values-az/strings.xml
index e23e8d0..191d074 100644
--- a/libs/WindowManager/Shell/res/values-az/strings.xml
+++ b/libs/WindowManager/Shell/res/values-az/strings.xml
@@ -97,6 +97,9 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Kamera problemi var?\nBərpa etmək üçün toxunun"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Düzəltməmisiniz?\nGeri qaytarmaq üçün toxunun"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Kamera problemi yoxdur? Qapatmaq üçün toxunun."</string>
+    <string name="windowing_app_handle_education_tooltip" msgid="6398482412956375783">"Tətbiq menyusunu açmaq üçün toxunun"</string>
+    <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="6285279585554484957">"Bir neçə tətbiqi birlikdə göstərmək üçün toxunun"</string>
+    <string name="windowing_desktop_mode_exit_education_tooltip" msgid="6685429075790085337">"Tətbiq menyusundan tam ekrana qayıdın"</string>
     <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Ardını görün və edin"</string>
     <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Bölünmüş ekran üçün başqa tətbiq sürüşdürün"</string>
     <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Tətbiqin yerini dəyişmək üçün kənarına iki dəfə toxunun"</string>
@@ -126,15 +129,16 @@
     <string name="manage_windows_text" msgid="5567366688493093920">"Pəncərələri idarə edin"</string>
     <string name="close_text" msgid="4986518933445178928">"Bağlayın"</string>
     <string name="collapse_menu_text" msgid="7515008122450342029">"Menyunu bağlayın"</string>
-    <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) -->
-    <skip />
+    <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Menyunu açın"</string>
     <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Ekranı maksimum böyüdün"</string>
     <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Ekranı çəkin"</string>
-    <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"Bu tətbiqin ölçüsünü dəyişmək olmur"</string>
-    <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) -->
-    <skip />
-    <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) -->
-    <skip />
-    <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) -->
-    <skip />
+    <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Tətbiqi bura köçürmək mümkün deyil"</string>
+    <string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"Böyüdün"</string>
+    <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Sola tərəf çəkin"</string>
+    <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"Sağa tərəf çəkin"</string>
+    <string name="open_by_default_settings_text" msgid="2526548548598185500">"Defolt ayarlarla açın"</string>
+    <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Bu tətbiq üçün veb-linklərin necə açılacağını seçin"</string>
+    <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"Tətbiqdə"</string>
+    <string name="open_by_default_dialog_in_browser_text" msgid="8042769465958497081">"Brauzerinizdə"</string>
+    <string name="open_by_default_dialog_dismiss_button_text" msgid="3487238795534582291">"OK"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-b+sr+Latn/strings.xml b/libs/WindowManager/Shell/res/values-b+sr+Latn/strings.xml
index 283d1f5..852c90e 100644
--- a/libs/WindowManager/Shell/res/values-b+sr+Latn/strings.xml
+++ b/libs/WindowManager/Shell/res/values-b+sr+Latn/strings.xml
@@ -97,6 +97,9 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Imate problema sa kamerom?\nDodirnite da biste ponovo uklopili"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Problem nije rešen?\nDodirnite da biste vratili"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Nemate problema sa kamerom? Dodirnite da biste odbacili."</string>
+    <string name="windowing_app_handle_education_tooltip" msgid="6398482412956375783">"Dodirnite da biste otvorili meni aplikacije"</string>
+    <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="6285279585554484957">"Dodirnite da biste prikazali više aplikacija zajedno"</string>
+    <string name="windowing_desktop_mode_exit_education_tooltip" msgid="6685429075790085337">"Vratite se iz menija aplikacije na prikaz preko celog ekrana"</string>
     <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Vidite i uradite više"</string>
     <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Prevucite drugu aplikaciju da biste koristili podeljeni ekran"</string>
     <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Dvaput dodirnite izvan aplikacije da biste promenili njenu poziciju"</string>
@@ -126,15 +129,16 @@
     <string name="manage_windows_text" msgid="5567366688493093920">"Upravljajte prozorima"</string>
     <string name="close_text" msgid="4986518933445178928">"Zatvorite"</string>
     <string name="collapse_menu_text" msgid="7515008122450342029">"Zatvorite meni"</string>
-    <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) -->
-    <skip />
+    <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Otvorite meni"</string>
     <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Povećaj ekran"</string>
     <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Uklopi ekran"</string>
-    <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"Veličina ove aplikacije ne može da se promeni"</string>
-    <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) -->
-    <skip />
-    <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) -->
-    <skip />
-    <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) -->
-    <skip />
+    <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Aplikacija ne može da se premesti ovde"</string>
+    <string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"Uvećajte"</string>
+    <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Prikačite levo"</string>
+    <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"Prikačite desno"</string>
+    <string name="open_by_default_settings_text" msgid="2526548548598185500">"Podešavanje Podrazumevano otvaraj"</string>
+    <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Odaberite način otvaranja veb-linkova za ovu aplikaciju"</string>
+    <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"U aplikaciji"</string>
+    <string name="open_by_default_dialog_in_browser_text" msgid="8042769465958497081">"U pregledaču"</string>
+    <string name="open_by_default_dialog_dismiss_button_text" msgid="3487238795534582291">"Potvrdi"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-be/strings.xml b/libs/WindowManager/Shell/res/values-be/strings.xml
index 48914f1..661b6c7 100644
--- a/libs/WindowManager/Shell/res/values-be/strings.xml
+++ b/libs/WindowManager/Shell/res/values-be/strings.xml
@@ -97,6 +97,9 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Праблемы з камерай?\nНацісніце, каб пераабсталяваць"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Не ўдалося выправіць?\nНацісніце, каб аднавіць"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Ніякіх праблем з камерай? Націсніце, каб адхіліць."</string>
+    <string name="windowing_app_handle_education_tooltip" msgid="6398482412956375783">"Адкрыць меню праграмы"</string>
+    <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="6285279585554484957">"Паказаць некалькі праграм разам"</string>
+    <string name="windowing_desktop_mode_exit_education_tooltip" msgid="6685429075790085337">"Вярнуцца ў поўнаэкранны рэжым з меню праграмы"</string>
     <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Адначасова выконвайце розныя задачы"</string>
     <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Перацягніце іншую праграму, каб выкарыстоўваць падзелены экран"</string>
     <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Двойчы націсніце экран па-за праграмай, каб перамясціць яе"</string>
@@ -126,15 +129,16 @@
     <string name="manage_windows_text" msgid="5567366688493093920">"Кіраваць вокнамі"</string>
     <string name="close_text" msgid="4986518933445178928">"Закрыць"</string>
     <string name="collapse_menu_text" msgid="7515008122450342029">"Закрыць меню"</string>
-    <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) -->
-    <skip />
+    <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Адкрыць меню"</string>
     <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Разгарнуць на ўвесь экран"</string>
     <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Размясціць на палавіне экрана"</string>
-    <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"Немагчыма змяніць памер праграмы"</string>
-    <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) -->
-    <skip />
-    <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) -->
-    <skip />
-    <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) -->
-    <skip />
+    <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Нельга перамясціць сюды праграму"</string>
+    <string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"Разгарнуць"</string>
+    <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Размясціць злева"</string>
+    <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"Размясціць справа"</string>
+    <string name="open_by_default_settings_text" msgid="2526548548598185500">"Налады параметра \"Адкрываць стандартна\""</string>
+    <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Выберыце, як гэта праграма будзе адкрываць вэб-спасылкі"</string>
+    <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"У праграме"</string>
+    <string name="open_by_default_dialog_in_browser_text" msgid="8042769465958497081">"У браўзеры"</string>
+    <string name="open_by_default_dialog_dismiss_button_text" msgid="3487238795534582291">"ОК"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-bg/strings.xml b/libs/WindowManager/Shell/res/values-bg/strings.xml
index f5e94da..d6da2a8 100644
--- a/libs/WindowManager/Shell/res/values-bg/strings.xml
+++ b/libs/WindowManager/Shell/res/values-bg/strings.xml
@@ -97,6 +97,9 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Имате проблеми с камерата?\nДокоснете за ремонтиране"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Проблемът не се отстрани?\nДокоснете за връщане в предишното състояние"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Нямате проблеми с камерата? Докоснете, за да отхвърлите."</string>
+    <string name="windowing_app_handle_education_tooltip" msgid="6398482412956375783">"Докоснете, за да отворите менюто на приложението"</string>
+    <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="6285279585554484957">"Докоснете, за да видите няколко приложения заедно"</string>
+    <string name="windowing_desktop_mode_exit_education_tooltip" msgid="6685429075790085337">"Връщане към цял екран от менюто на приложението"</string>
     <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Преглеждайте и правете повече неща"</string>
     <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Преместете друго приложение с плъзгане, за да преминете в режим за разделен екран"</string>
     <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Докоснете два пъти извън дадено приложение, за да промените позицията му"</string>
@@ -129,8 +132,13 @@
     <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Отваряне на менюто"</string>
     <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Увеличаване на екрана"</string>
     <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Прилепване на екрана"</string>
-    <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"Това приложение не може да бъде преоразмерено"</string>
+    <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Приложението не може да бъде преместено тук"</string>
     <string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"Увеличаване"</string>
     <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Прилепване наляво"</string>
     <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"Прилепване надясно"</string>
+    <string name="open_by_default_settings_text" msgid="2526548548598185500">"Отваряне на настройките по подразбиране"</string>
+    <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Изберете как да се отварят уеб връзките за това приложение"</string>
+    <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"В приложението"</string>
+    <string name="open_by_default_dialog_in_browser_text" msgid="8042769465958497081">"В браузъра ви"</string>
+    <string name="open_by_default_dialog_dismiss_button_text" msgid="3487238795534582291">"OK"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-bn/strings.xml b/libs/WindowManager/Shell/res/values-bn/strings.xml
index 5d63744..62e26b1 100644
--- a/libs/WindowManager/Shell/res/values-bn/strings.xml
+++ b/libs/WindowManager/Shell/res/values-bn/strings.xml
@@ -97,6 +97,9 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"ক্যামেরা সংক্রান্ত সমস্যা?\nরিফিট করতে ট্যাপ করুন"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"এখনও সমাধান হয়নি?\nরিভার্ট করার জন্য ট্যাপ করুন"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"ক্যামেরা সংক্রান্ত সমস্যা নেই? বাতিল করতে ট্যাপ করুন।"</string>
+    <string name="windowing_app_handle_education_tooltip" msgid="6398482412956375783">"অ্যাপ মেনু খুলতে ট্যাপ করুন"</string>
+    <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="6285279585554484957">"একাধিক অ্যাপ একসাথে দেখতে ট্যাপ করুন"</string>
+    <string name="windowing_desktop_mode_exit_education_tooltip" msgid="6685429075790085337">"অ্যাপ মেনু থেকে ফুল-স্ক্রিন মোডে ফিরে যান"</string>
     <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"দেখুন ও আরও অনেক কিছু করুন"</string>
     <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"স্প্লিট স্ক্রিনের ক্ষেত্রে অন্য কোনও অ্যাপ টেনে আনুন"</string>
     <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"কোনও অ্যাপের স্থান পরিবর্তন করতে তার বাইরে ডবল ট্যাপ করুন"</string>
@@ -129,8 +132,13 @@
     <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"মেনু খুলুন"</string>
     <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"স্ক্রিন বড় করুন"</string>
     <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"স্ক্রিনে অ্যাপ মানানসই হিসেবে ছোট বড় করুন"</string>
-    <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"এই অ্যাপ ছোট বড় করা যাবে না"</string>
+    <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"অ্যাপটি এখানে সরানো যাবে না"</string>
     <string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"বড় করুন"</string>
     <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"বাঁদিকে স্ন্যাপ করুন"</string>
     <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"ডানদিকে স্ন্যাপ করুন"</string>
+    <string name="open_by_default_settings_text" msgid="2526548548598185500">"ডিফল্ট হিসেবে থাকা সেটিংস খুলুন"</string>
+    <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"এই অ্যাপের জন্য কীভাবে ওয়েব লিঙ্ক খুলবেন তা বেছে নিন"</string>
+    <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"অ্যাপের মধ্যে"</string>
+    <string name="open_by_default_dialog_in_browser_text" msgid="8042769465958497081">"আপনার ব্রাউজারে"</string>
+    <string name="open_by_default_dialog_dismiss_button_text" msgid="3487238795534582291">"ঠিক আছে"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-bs/strings.xml b/libs/WindowManager/Shell/res/values-bs/strings.xml
index 95362bb..15b6058 100644
--- a/libs/WindowManager/Shell/res/values-bs/strings.xml
+++ b/libs/WindowManager/Shell/res/values-bs/strings.xml
@@ -97,6 +97,9 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Problemi s kamerom?\nDodirnite da ponovo namjestite"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Nije popravljeno?\nDodirnite da vratite"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Nema problema s kamerom? Dodirnite da odbacite."</string>
+    <string name="windowing_app_handle_education_tooltip" msgid="6398482412956375783">"Otvaranje menija aplikacije dodirom"</string>
+    <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="6285279585554484957">"Istovremeni prikaz više aplikacija dodirom"</string>
+    <string name="windowing_desktop_mode_exit_education_tooltip" msgid="6685429075790085337">"Povratak na prikaz preko cijelog ekrana putem menija aplikacije"</string>
     <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Pogledajte i učinite više"</string>
     <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Prevucite još jednu aplikaciju za podijeljeni ekran"</string>
     <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Dvaput dodirnite izvan aplikacije da promijenite njen položaj"</string>
@@ -126,15 +129,16 @@
     <string name="manage_windows_text" msgid="5567366688493093920">"Upravljanje prozorima"</string>
     <string name="close_text" msgid="4986518933445178928">"Zatvaranje"</string>
     <string name="collapse_menu_text" msgid="7515008122450342029">"Zatvaranje menija"</string>
-    <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) -->
-    <skip />
+    <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Otvaranje menija"</string>
     <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maksimiziraj ekran"</string>
     <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Snimi ekran"</string>
-    <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"Nije moguće promijeniti veličinu aplikacije"</string>
-    <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) -->
-    <skip />
-    <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) -->
-    <skip />
-    <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) -->
-    <skip />
+    <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Ne možete premjestiti aplikaciju ovdje"</string>
+    <string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"Maksimiziranje"</string>
+    <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Pomicanje ulijevo"</string>
+    <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"Pomicanje udesno"</string>
+    <string name="open_by_default_settings_text" msgid="2526548548598185500">"Otvaranje prema zadanim postavkama"</string>
+    <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Odaberite način otvaranja web linkova za ovu aplikaciju"</string>
+    <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"U aplikaciji"</string>
+    <string name="open_by_default_dialog_in_browser_text" msgid="8042769465958497081">"U pregledniku"</string>
+    <string name="open_by_default_dialog_dismiss_button_text" msgid="3487238795534582291">"Uredu"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-ca/strings.xml b/libs/WindowManager/Shell/res/values-ca/strings.xml
index e0b2538..7cc65a7 100644
--- a/libs/WindowManager/Shell/res/values-ca/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ca/strings.xml
@@ -97,6 +97,9 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Tens problemes amb la càmera?\nToca per resoldre\'ls"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"El problema no s\'ha resolt?\nToca per desfer els canvis"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"No tens cap problema amb la càmera? Toca per ignorar."</string>
+    <string name="windowing_app_handle_education_tooltip" msgid="6398482412956375783">"Toca per obrir el menú de l\'aplicació"</string>
+    <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="6285279585554484957">"Toca per mostrar diverses aplicacions alhora"</string>
+    <string name="windowing_desktop_mode_exit_education_tooltip" msgid="6685429075790085337">"Torna a la pantalla completa des del menú de l\'aplicació"</string>
     <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Consulta i fes més coses"</string>
     <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Arrossega una altra aplicació per utilitzar la pantalla dividida"</string>
     <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Fes doble toc fora d\'una aplicació per canviar-ne la posició"</string>
@@ -126,15 +129,16 @@
     <string name="manage_windows_text" msgid="5567366688493093920">"Gestiona les finestres"</string>
     <string name="close_text" msgid="4986518933445178928">"Tanca"</string>
     <string name="collapse_menu_text" msgid="7515008122450342029">"Tanca el menú"</string>
-    <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) -->
-    <skip />
+    <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Obre el menú"</string>
     <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maximitza la pantalla"</string>
     <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Ajusta la pantalla"</string>
-    <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"No es pot canviar la mida d\'aquesta aplicació"</string>
-    <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) -->
-    <skip />
-    <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) -->
-    <skip />
-    <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) -->
-    <skip />
+    <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"L\'aplicació no es pot moure aquí"</string>
+    <string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"Maximitza"</string>
+    <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Ajusta a l\'esquerra"</string>
+    <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"Ajusta a la dreta"</string>
+    <string name="open_by_default_settings_text" msgid="2526548548598185500">"Configuració d\'obertura predeterminada"</string>
+    <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Tria com vols obrir els enllaços web per a aquesta aplicació"</string>
+    <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"A l\'aplicació"</string>
+    <string name="open_by_default_dialog_in_browser_text" msgid="8042769465958497081">"Al navegador"</string>
+    <string name="open_by_default_dialog_dismiss_button_text" msgid="3487238795534582291">"D\'acord"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-cs/strings.xml b/libs/WindowManager/Shell/res/values-cs/strings.xml
index 7164910..f8bdcaf 100644
--- a/libs/WindowManager/Shell/res/values-cs/strings.xml
+++ b/libs/WindowManager/Shell/res/values-cs/strings.xml
@@ -97,6 +97,9 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Problémy s fotoaparátem?\nKlepnutím vyřešíte"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Nepomohlo to?\nKlepnutím se vrátíte"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Žádné problémy s fotoaparátem? Klepnutím zavřete."</string>
+    <string name="windowing_app_handle_education_tooltip" msgid="6398482412956375783">"Klepnutím otevřete nabídku aplikace"</string>
+    <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="6285279585554484957">"Klepnutím zobrazíte několik aplikací najednou"</string>
+    <string name="windowing_desktop_mode_exit_education_tooltip" msgid="6685429075790085337">"Návrat na celou obrazovku z nabídky aplikace"</string>
     <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Lepší zobrazení a více možností"</string>
     <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Přetáhnutím druhé aplikace použijete rozdělenou obrazovku"</string>
     <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Dvojitým klepnutím mimo aplikaci změníte její umístění"</string>
@@ -129,8 +132,13 @@
     <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Otevřít nabídku"</string>
     <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maximalizovat obrazovku"</string>
     <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Rozpůlit obrazovku"</string>
-    <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"Velikost aplikace nelze změnit"</string>
+    <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Aplikaci sem nelze přesunout"</string>
     <string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"Maximalizovat"</string>
     <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Přichytit vlevo"</string>
     <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"Přichytit vpravo"</string>
+    <string name="open_by_default_settings_text" msgid="2526548548598185500">"Otevírat podle výchozího nastavení"</string>
+    <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Určete, jak se v této aplikaci mají otevírat webové odkazy"</string>
+    <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"V aplikaci"</string>
+    <string name="open_by_default_dialog_in_browser_text" msgid="8042769465958497081">"V prohlížeči"</string>
+    <string name="open_by_default_dialog_dismiss_button_text" msgid="3487238795534582291">"OK"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-da/strings.xml b/libs/WindowManager/Shell/res/values-da/strings.xml
index fdc5913..1e05069 100644
--- a/libs/WindowManager/Shell/res/values-da/strings.xml
+++ b/libs/WindowManager/Shell/res/values-da/strings.xml
@@ -97,6 +97,9 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Har du problemer med dit kamera?\nTryk for at gendanne det oprindelige format"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Løste det ikke problemet?\nTryk for at fortryde"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Har du ingen problemer med dit kamera? Tryk for at afvise."</string>
+    <string name="windowing_app_handle_education_tooltip" msgid="6398482412956375783">"Tryk for at åbne appmenuen"</string>
+    <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="6285279585554484957">"Tryk for at se flere apps på én gang"</string>
+    <string name="windowing_desktop_mode_exit_education_tooltip" msgid="6685429075790085337">"Gå tilbage til fuld skærm via appmenuen"</string>
     <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Se og gør mere"</string>
     <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Træk en anden app hertil for at bruge opdelt skærm"</string>
     <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Tryk to gange uden for en app for at justere dens placering"</string>
@@ -126,15 +129,16 @@
     <string name="manage_windows_text" msgid="5567366688493093920">"Administrer vinduer"</string>
     <string name="close_text" msgid="4986518933445178928">"Luk"</string>
     <string name="collapse_menu_text" msgid="7515008122450342029">"Luk menu"</string>
-    <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) -->
-    <skip />
+    <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Åbn menu"</string>
     <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maksimér skærm"</string>
     <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Tilpas skærm"</string>
-    <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"Størrelsen på denne app kan ikke justeres"</string>
-    <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) -->
-    <skip />
-    <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) -->
-    <skip />
-    <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) -->
-    <skip />
+    <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Apps kan ikke flyttes hertil"</string>
+    <string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"Maksimér"</string>
+    <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Fastgør til venstre"</string>
+    <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"Fastgør til højre"</string>
+    <string name="open_by_default_settings_text" msgid="2526548548598185500">"Indstillinger for automatisk åbning"</string>
+    <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Vælg, hvordan denne app skal åben weblinks"</string>
+    <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"I appen"</string>
+    <string name="open_by_default_dialog_in_browser_text" msgid="8042769465958497081">"I din browser"</string>
+    <string name="open_by_default_dialog_dismiss_button_text" msgid="3487238795534582291">"OK"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-de/strings.xml b/libs/WindowManager/Shell/res/values-de/strings.xml
index 913e3d0..bccd4ae 100644
--- a/libs/WindowManager/Shell/res/values-de/strings.xml
+++ b/libs/WindowManager/Shell/res/values-de/strings.xml
@@ -97,6 +97,9 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Probleme mit der Kamera?\nZum Anpassen tippen."</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Das Problem ist nicht behoben?\nZum Rückgängigmachen tippen."</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Keine Probleme mit der Kamera? Zum Schließen tippen."</string>
+    <string name="windowing_app_handle_education_tooltip" msgid="6398482412956375783">"Zum Öffnen des App-Menüs tippen"</string>
+    <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="6285279585554484957">"Tippen, um mehrere Apps gleichzeitig anzuzeigen"</string>
+    <string name="windowing_desktop_mode_exit_education_tooltip" msgid="6685429075790085337">"Über das App-Menü zum Vollbildmodus zurückkehren"</string>
     <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Mehr sehen und erledigen"</string>
     <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Für Splitscreen-Modus weitere App hineinziehen"</string>
     <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Außerhalb einer App doppeltippen, um die Position zu ändern"</string>
@@ -126,15 +129,21 @@
     <string name="manage_windows_text" msgid="5567366688493093920">"Fenster verwalten"</string>
     <string name="close_text" msgid="4986518933445178928">"Schließen"</string>
     <string name="collapse_menu_text" msgid="7515008122450342029">"Menü schließen"</string>
-    <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) -->
-    <skip />
+    <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Menü öffnen"</string>
     <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Bildschirm maximieren"</string>
     <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Bildschirm teilen"</string>
-    <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"Die Größe dieser App kann nicht geändert werden"</string>
-    <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) -->
+    <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Die App kann nicht hierher verschoben werden"</string>
+    <string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"Maximieren"</string>
+    <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Links andocken"</string>
+    <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"Rechts andocken"</string>
+    <!-- no translation found for open_by_default_settings_text (2526548548598185500) -->
     <skip />
-    <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) -->
+    <!-- no translation found for open_by_default_dialog_subheader_text (1729599730664063881) -->
     <skip />
-    <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) -->
+    <!-- no translation found for open_by_default_dialog_in_app_text (6978022419634199806) -->
+    <skip />
+    <!-- no translation found for open_by_default_dialog_in_browser_text (8042769465958497081) -->
+    <skip />
+    <!-- no translation found for open_by_default_dialog_dismiss_button_text (3487238795534582291) -->
     <skip />
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-el/strings.xml b/libs/WindowManager/Shell/res/values-el/strings.xml
index 564fa91..6466215 100644
--- a/libs/WindowManager/Shell/res/values-el/strings.xml
+++ b/libs/WindowManager/Shell/res/values-el/strings.xml
@@ -97,6 +97,9 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Προβλήματα με την κάμερα;\nΠατήστε για επιδιόρθωση."</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Δεν διορθώθηκε;\nΠατήστε για επαναφορά."</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Δεν αντιμετωπίζετε προβλήματα με την κάμερα; Πατήστε για παράβλεψη."</string>
+    <string name="windowing_app_handle_education_tooltip" msgid="6398482412956375783">"Πατήστε για άνοιγμα του μενού της εφαρμογής"</string>
+    <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="6285279585554484957">"Πατήστε για εμφάνιση πολλών εφαρμογών μαζί"</string>
+    <string name="windowing_desktop_mode_exit_education_tooltip" msgid="6685429075790085337">"Επιστρέψτε στην πλήρη οθόνη από το μενού της εφαρμογής"</string>
     <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Δείτε και κάντε περισσότερα"</string>
     <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Σύρετε σε μια άλλη εφαρμογή για διαχωρισμό οθόνης."</string>
     <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Πατήστε δύο φορές έξω από μια εφαρμογή για να αλλάξετε τη θέση της"</string>
@@ -126,15 +129,16 @@
     <string name="manage_windows_text" msgid="5567366688493093920">"Διαχείριση παραθύρων"</string>
     <string name="close_text" msgid="4986518933445178928">"Κλείσιμο"</string>
     <string name="collapse_menu_text" msgid="7515008122450342029">"Κλείσιμο μενού"</string>
-    <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) -->
-    <skip />
+    <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Άνοιγμα μενού"</string>
     <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Μεγιστοποίηση οθόνης"</string>
     <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Προβολή στο μισό της οθόνης"</string>
-    <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"Δεν είναι δυνατή η αλλαγή μεγέθους αυτής της εφαρμογής"</string>
-    <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) -->
-    <skip />
-    <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) -->
-    <skip />
-    <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) -->
-    <skip />
+    <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Δεν είναι δυνατή η μετακίνηση της εφαρμογής εδώ"</string>
+    <string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"Μεγιστοποίηση"</string>
+    <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Κούμπωμα αριστερά"</string>
+    <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"Κούμπωμα δεξιά"</string>
+    <string name="open_by_default_settings_text" msgid="2526548548598185500">"Άνοιγμα ρυθμίσεων από προεπιλογή"</string>
+    <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Επιλογή τρόπου ανοίγματος συνδέσμων ιστού για την εφαρμογή"</string>
+    <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"Στην εφαρμογή"</string>
+    <string name="open_by_default_dialog_in_browser_text" msgid="8042769465958497081">"Στο πρόγραμμα περιήγησής σας"</string>
+    <string name="open_by_default_dialog_dismiss_button_text" msgid="3487238795534582291">"ΟΚ"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-en-rAU/strings.xml b/libs/WindowManager/Shell/res/values-en-rAU/strings.xml
index 766852d..0182915 100644
--- a/libs/WindowManager/Shell/res/values-en-rAU/strings.xml
+++ b/libs/WindowManager/Shell/res/values-en-rAU/strings.xml
@@ -97,6 +97,9 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Camera issues?\nTap to refit"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Didn’t fix it?\nTap to revert"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"No camera issues? Tap to dismiss."</string>
+    <string name="windowing_app_handle_education_tooltip" msgid="6398482412956375783">"Tap to open the app menu"</string>
+    <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="6285279585554484957">"Tap to show multiple apps together"</string>
+    <string name="windowing_desktop_mode_exit_education_tooltip" msgid="6685429075790085337">"Return to fullscreen from the app menu"</string>
     <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"See and do more"</string>
     <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Drag in another app for split screen"</string>
     <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Double-tap outside an app to reposition it"</string>
@@ -129,8 +132,13 @@
     <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Open menu"</string>
     <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maximise screen"</string>
     <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Snap screen"</string>
-    <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"This app can\'t be resized"</string>
+    <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"App can\'t be moved here"</string>
     <string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"Maximise"</string>
     <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Snap left"</string>
     <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"Snap right"</string>
+    <string name="open_by_default_settings_text" msgid="2526548548598185500">"Open by default settings"</string>
+    <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Choose how to open web links for this app"</string>
+    <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"In the app"</string>
+    <string name="open_by_default_dialog_in_browser_text" msgid="8042769465958497081">"In your browser"</string>
+    <string name="open_by_default_dialog_dismiss_button_text" msgid="3487238795534582291">"OK"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-en-rCA/strings.xml b/libs/WindowManager/Shell/res/values-en-rCA/strings.xml
index aa3a484..9d58109 100644
--- a/libs/WindowManager/Shell/res/values-en-rCA/strings.xml
+++ b/libs/WindowManager/Shell/res/values-en-rCA/strings.xml
@@ -97,6 +97,9 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Camera issues?\nTap to refit"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Didn’t fix it?\nTap to revert"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"No camera issues? Tap to dismiss."</string>
+    <string name="windowing_app_handle_education_tooltip" msgid="6398482412956375783">"Tap to open the app menu"</string>
+    <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="6285279585554484957">"Tap to show multiple apps together"</string>
+    <string name="windowing_desktop_mode_exit_education_tooltip" msgid="6685429075790085337">"Return to fullscreen from the app menu"</string>
     <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"See and do more"</string>
     <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Drag in another app for split screen"</string>
     <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Double-tap outside an app to reposition it"</string>
@@ -129,8 +132,13 @@
     <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Open Menu"</string>
     <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maximize Screen"</string>
     <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Snap Screen"</string>
-    <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"This app can\'t be resized"</string>
+    <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"App can\'t be moved here"</string>
     <string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"Maximize"</string>
     <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Snap left"</string>
     <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"Snap right"</string>
+    <string name="open_by_default_settings_text" msgid="2526548548598185500">"Open by default settings"</string>
+    <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Choose how to open web links for this app"</string>
+    <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"In the app"</string>
+    <string name="open_by_default_dialog_in_browser_text" msgid="8042769465958497081">"In your browser"</string>
+    <string name="open_by_default_dialog_dismiss_button_text" msgid="3487238795534582291">"OK"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-en-rGB/strings.xml b/libs/WindowManager/Shell/res/values-en-rGB/strings.xml
index d5b9703..0182915 100644
--- a/libs/WindowManager/Shell/res/values-en-rGB/strings.xml
+++ b/libs/WindowManager/Shell/res/values-en-rGB/strings.xml
@@ -97,12 +97,9 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Camera issues?\nTap to refit"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Didn’t fix it?\nTap to revert"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"No camera issues? Tap to dismiss."</string>
-    <!-- no translation found for windowing_app_handle_education_tooltip (6398482412956375783) -->
-    <skip />
-    <!-- no translation found for windowing_desktop_mode_image_button_education_tooltip (6285279585554484957) -->
-    <skip />
-    <!-- no translation found for windowing_desktop_mode_exit_education_tooltip (6685429075790085337) -->
-    <skip />
+    <string name="windowing_app_handle_education_tooltip" msgid="6398482412956375783">"Tap to open the app menu"</string>
+    <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="6285279585554484957">"Tap to show multiple apps together"</string>
+    <string name="windowing_desktop_mode_exit_education_tooltip" msgid="6685429075790085337">"Return to fullscreen from the app menu"</string>
     <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"See and do more"</string>
     <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Drag in another app for split screen"</string>
     <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Double-tap outside an app to reposition it"</string>
@@ -135,9 +132,13 @@
     <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Open menu"</string>
     <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maximise screen"</string>
     <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Snap screen"</string>
-    <!-- no translation found for desktop_mode_non_resizable_snap_text (3771776422751387878) -->
-    <skip />
+    <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"App can\'t be moved here"</string>
     <string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"Maximise"</string>
     <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Snap left"</string>
     <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"Snap right"</string>
+    <string name="open_by_default_settings_text" msgid="2526548548598185500">"Open by default settings"</string>
+    <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Choose how to open web links for this app"</string>
+    <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"In the app"</string>
+    <string name="open_by_default_dialog_in_browser_text" msgid="8042769465958497081">"In your browser"</string>
+    <string name="open_by_default_dialog_dismiss_button_text" msgid="3487238795534582291">"OK"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-en-rIN/strings.xml b/libs/WindowManager/Shell/res/values-en-rIN/strings.xml
index 766852d..0182915 100644
--- a/libs/WindowManager/Shell/res/values-en-rIN/strings.xml
+++ b/libs/WindowManager/Shell/res/values-en-rIN/strings.xml
@@ -97,6 +97,9 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Camera issues?\nTap to refit"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Didn’t fix it?\nTap to revert"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"No camera issues? Tap to dismiss."</string>
+    <string name="windowing_app_handle_education_tooltip" msgid="6398482412956375783">"Tap to open the app menu"</string>
+    <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="6285279585554484957">"Tap to show multiple apps together"</string>
+    <string name="windowing_desktop_mode_exit_education_tooltip" msgid="6685429075790085337">"Return to fullscreen from the app menu"</string>
     <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"See and do more"</string>
     <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Drag in another app for split screen"</string>
     <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Double-tap outside an app to reposition it"</string>
@@ -129,8 +132,13 @@
     <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Open menu"</string>
     <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maximise screen"</string>
     <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Snap screen"</string>
-    <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"This app can\'t be resized"</string>
+    <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"App can\'t be moved here"</string>
     <string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"Maximise"</string>
     <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Snap left"</string>
     <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"Snap right"</string>
+    <string name="open_by_default_settings_text" msgid="2526548548598185500">"Open by default settings"</string>
+    <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Choose how to open web links for this app"</string>
+    <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"In the app"</string>
+    <string name="open_by_default_dialog_in_browser_text" msgid="8042769465958497081">"In your browser"</string>
+    <string name="open_by_default_dialog_dismiss_button_text" msgid="3487238795534582291">"OK"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-en-rXC/strings.xml b/libs/WindowManager/Shell/res/values-en-rXC/strings.xml
index bda5132..54346da 100644
--- a/libs/WindowManager/Shell/res/values-en-rXC/strings.xml
+++ b/libs/WindowManager/Shell/res/values-en-rXC/strings.xml
@@ -97,6 +97,9 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‎‎‎‏‏‏‎‏‏‎‏‏‏‎‎‏‎‏‏‎‎‎‏‏‎‎‎‎‎‎‎‎‏‏‏‏‏‏‎‎‎‎‏‎‏‏‏‎‏‏‏‏‎‏‏‏‏‏‎Camera issues?‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎Tap to refit‎‏‎‎‏‎"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‎‎‏‏‎‏‏‎‏‏‏‎‏‏‏‏‏‏‎‏‎‎‏‎‏‏‏‎‏‏‎‏‏‏‎‎‎‎‎‏‎‎‎‎‎‏‏‏‏‎‎‎‎‏‏‎‎‏‎Didn’t fix it?‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎Tap to revert‎‏‎‎‏‎"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‏‎‏‏‎‎‏‎‏‏‎‎‏‎‎‎‎‏‎‎‏‎‎‏‎‎‎‏‎‎‏‏‎‎‏‏‎‎‎‎‎‏‏‎‎‎‏‏‏‏‎‎‏‎‎‏‏‏‎No camera issues? Tap to dismiss.‎‏‎‎‏‎"</string>
+    <string name="windowing_app_handle_education_tooltip" msgid="6398482412956375783">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‎‎‏‏‎‎‏‎‏‏‏‏‏‏‏‎‎‏‏‏‎‏‏‎‏‎‏‎‎‏‏‏‎‏‏‏‎‏‏‎‎‏‎‏‎‏‏‎‏‎‏‏‏‎‎‏‏‏‎Tap to open the app menu‎‏‎‎‏‎"</string>
+    <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="6285279585554484957">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‏‏‎‎‏‏‏‎‎‏‏‏‎‎‏‏‎‎‎‏‏‏‏‎‏‏‎‏‏‏‎‎‏‎‏‏‏‏‏‏‎‏‎‏‎‎‏‏‏‎‏‏‎‏‏‏‎‏‎Tap to show multiple apps together‎‏‎‎‏‎"</string>
+    <string name="windowing_desktop_mode_exit_education_tooltip" msgid="6685429075790085337">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‎‎‏‏‎‎‎‏‏‏‎‏‏‎‏‎‏‎‎‏‎‏‎‎‏‎‏‏‎‏‎‎‎‏‏‎‎‎‏‎‎‏‎‎‏‏‏‏‎‎‏‏‎‏‏‎‎‏‎Return to fullscreen from the app menu‎‏‎‎‏‎"</string>
     <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‏‏‎‏‏‎‏‎‎‏‏‎‏‎‎‎‎‏‏‏‎‏‎‎‎‏‎‎‎‏‏‏‏‎‎‏‏‎‏‎‎‎‎‏‎‎‎‏‏‏‎‏‏‏‏‏‏‎‎See and do more‎‏‎‎‏‎"</string>
     <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‏‏‏‎‎‎‏‏‏‎‏‏‏‏‏‏‏‏‏‏‎‎‎‏‏‎‎‏‎‎‎‎‎‏‏‎‏‎‏‎‏‎‏‏‎‏‏‎‏‎‎‏‏‏‎‎‎‎‏‏‎Drag in another app for split screen‎‏‎‎‏‎"</string>
     <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‏‏‏‏‎‏‏‎‎‏‎‏‏‎‎‏‏‎‏‏‏‎‏‏‎‎‎‎‏‏‏‎‏‎‏‏‎‎‏‎‏‎‎‎‎‎‎‎‎‎‏‎‎‏‏‎‏‎‏‎Double-tap outside an app to reposition it‎‏‎‎‏‎"</string>
@@ -129,8 +132,13 @@
     <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‎‎‎‏‎‏‏‎‏‎‎‎‎‏‎‎‏‏‏‎‏‎‎‎‏‏‎‎‏‏‏‎‎‎‏‎‎‏‎‏‏‏‏‏‎‎‏‏‏‎‎‏‎‎‎‏‎‏‎Open Menu‎‏‎‎‏‎"</string>
     <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‏‎‏‎‏‏‏‎‏‎‏‏‎‏‎‏‏‏‏‏‎‎‎‎‎‎‏‏‏‎‏‎‏‏‎‏‏‎‎‏‎‏‎‎‎‎‏‎‏‏‏‏‎‏‎‏‎‏‏‎Maximize Screen‎‏‎‎‏‎"</string>
     <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‎‎‏‎‏‎‏‎‎‏‎‎‏‏‏‏‏‎‏‏‎‏‏‏‎‎‏‏‏‏‎‎‎‏‎‎‎‎‏‎‏‏‏‎‎‏‏‎‏‏‏‏‎‏‏‎‏‎‎Snap Screen‎‏‎‎‏‎"</string>
-    <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‏‎‏‎‎‏‎‎‎‏‏‎‏‎‎‎‏‏‏‏‏‏‎‎‎‏‏‎‏‎‎‎‏‎‏‎‎‎‏‏‏‏‏‎‎‏‎‏‎‎‏‎‎‎‎‎‏‏‎This app can\'t be resized‎‏‎‎‏‎"</string>
+    <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‏‎‎‎‏‎‏‏‎‎‎‎‎‎‎‏‎‏‎‏‎‏‎‏‏‎‎‎‎‏‏‏‎‏‎‎‏‎‎‏‎‏‎‎‏‎‎‎‎‎‎‏‏‏‎‎‏‏‎‎App can\'t be moved here‎‏‎‎‏‎"</string>
     <string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‏‎‏‏‏‎‎‎‏‎‏‎‎‏‎‏‏‏‏‏‎‎‎‏‏‏‎‎‎‏‎‎‎‎‏‎‏‏‎‏‎‏‎‎‏‎‏‎‎‏‏‏‏‎‎‏‎‏‎Maximize‎‏‎‎‏‎"</string>
     <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‎‎‎‎‎‏‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‎‏‏‎‎‎‏‎‏‎‏‏‎‎‎‎‏‏‎‎‏‎‎‏‏‏‎‏‎‏‏‎‎‎‎‎Snap left‎‏‎‎‏‎"</string>
     <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‎‏‎‏‏‎‎‎‏‏‏‎‏‎‏‎‏‎‎‏‏‏‎‎‎‏‎‏‏‎‎‎‎‎‎‎‎‏‎‏‎‎‏‏‎‏‎‏‏‎‏‏‏‎‏‏‎‎‎‎Snap right‎‏‎‎‏‎"</string>
+    <string name="open_by_default_settings_text" msgid="2526548548598185500">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‎‏‏‎‎‎‏‎‎‎‎‎‎‎‏‏‎‏‎‏‎‎‎‎‏‎‎‏‏‎‎‏‎‏‎‏‏‏‏‏‎‎‏‎‎‏‏‏‏‏‎‎‎‎‏‏‏‎‎‎Open by default settings‎‏‎‎‏‎"</string>
+    <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‎‎‎‎‎‎‎‎‎‎‏‏‎‎‎‏‎‏‏‏‎‎‏‎‏‎‏‎‎‎‏‏‎‏‏‏‎‏‎‏‏‏‏‏‎‎‎‎‏‏‏‎‎‎‏‎‎‏‎Choose how to open web links for this app‎‏‎‎‏‎"</string>
+    <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‎‎‎‏‏‎‏‎‏‏‎‏‏‏‎‏‎‏‎‎‏‏‎‏‎‏‏‎‏‏‎‎‏‎‏‎‎‎‎‎‎‏‎‎‎‎‏‏‏‎‎‏‏‏‏‏‏‏‎‎In the app‎‏‎‎‏‎"</string>
+    <string name="open_by_default_dialog_in_browser_text" msgid="8042769465958497081">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‏‏‏‎‎‏‏‏‎‏‏‎‏‎‏‎‎‎‎‎‏‏‎‏‏‏‏‎‎‎‎‏‎‎‏‏‎‏‎‎‎‎‎‏‏‏‏‎‏‏‎‎‏‏‏‎‎‏‎In your browser‎‏‎‎‏‎"</string>
+    <string name="open_by_default_dialog_dismiss_button_text" msgid="3487238795534582291">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‎‎‎‏‏‎‎‏‎‏‎‎‏‎‏‎‎‏‎‎‏‏‎‏‎‏‎‏‎‏‎‏‏‎‏‏‎‎‏‏‎‎‏‏‎‎‎‎‏‎‎‎‎‏‎‎‏‏‎OK‎‏‎‎‏‎"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-es-rUS/strings.xml b/libs/WindowManager/Shell/res/values-es-rUS/strings.xml
index a4c0363..630d806 100644
--- a/libs/WindowManager/Shell/res/values-es-rUS/strings.xml
+++ b/libs/WindowManager/Shell/res/values-es-rUS/strings.xml
@@ -97,6 +97,9 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"¿Tienes problemas con la cámara?\nPresiona para reajustarla"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"¿No se resolvió?\nPresiona para revertir los cambios"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"¿No tienes problemas con la cámara? Presionar para descartar."</string>
+    <string name="windowing_app_handle_education_tooltip" msgid="6398482412956375783">"Presiona para abrir el menú de la app"</string>
+    <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="6285279585554484957">"Presiona para mostrar varias apps juntas"</string>
+    <string name="windowing_desktop_mode_exit_education_tooltip" msgid="6685429075790085337">"Regresa a pantalla completa desde el menú de la app"</string>
     <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Aprovecha más"</string>
     <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Arrastra otra app para el modo de pantalla dividida"</string>
     <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Presiona dos veces fuera de una app para cambiar su ubicación"</string>
@@ -126,15 +129,16 @@
     <string name="manage_windows_text" msgid="5567366688493093920">"Administrar ventanas"</string>
     <string name="close_text" msgid="4986518933445178928">"Cerrar"</string>
     <string name="collapse_menu_text" msgid="7515008122450342029">"Cerrar menú"</string>
-    <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) -->
-    <skip />
+    <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Abrir el menú"</string>
     <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maximizar pantalla"</string>
     <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Ajustar pantalla"</string>
-    <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"No se puede cambiar el tamaño de esta app"</string>
-    <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) -->
-    <skip />
-    <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) -->
-    <skip />
-    <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) -->
-    <skip />
+    <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"No se puede mover la app aquí"</string>
+    <string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"Maximizar"</string>
+    <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Ajustar a la izquierda"</string>
+    <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"Ajustar a la derecha"</string>
+    <string name="open_by_default_settings_text" msgid="2526548548598185500">"Abrir con la configuración predeterminada"</string>
+    <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Elige cómo abrir vínculos web para esta app"</string>
+    <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"En la app"</string>
+    <string name="open_by_default_dialog_in_browser_text" msgid="8042769465958497081">"En un navegador"</string>
+    <string name="open_by_default_dialog_dismiss_button_text" msgid="3487238795534582291">"Aceptar"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-es/strings.xml b/libs/WindowManager/Shell/res/values-es/strings.xml
index 69f7d7b..9f6b2e65 100644
--- a/libs/WindowManager/Shell/res/values-es/strings.xml
+++ b/libs/WindowManager/Shell/res/values-es/strings.xml
@@ -97,6 +97,9 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"¿Problemas con la cámara?\nToca para reajustar"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"¿No se ha solucionado?\nToca para revertir"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"¿No hay problemas con la cámara? Toca para cerrar."</string>
+    <string name="windowing_app_handle_education_tooltip" msgid="6398482412956375783">"Toca para abrir el menú de aplicaciones"</string>
+    <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="6285279585554484957">"Toca para mostrar varias aplicaciones a la vez"</string>
+    <string name="windowing_desktop_mode_exit_education_tooltip" msgid="6685429075790085337">"Vuelve a pantalla completa desde el menú de aplicaciones"</string>
     <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Consulta más información y haz más"</string>
     <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Arrastra otra aplicación para activar la pantalla dividida"</string>
     <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Toca dos veces fuera de una aplicación para cambiarla de posición"</string>
@@ -126,15 +129,21 @@
     <string name="manage_windows_text" msgid="5567366688493093920">"Gestionar ventanas"</string>
     <string name="close_text" msgid="4986518933445178928">"Cerrar"</string>
     <string name="collapse_menu_text" msgid="7515008122450342029">"Cerrar menú"</string>
-    <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) -->
-    <skip />
+    <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Abrir menú"</string>
     <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maximizar pantalla"</string>
     <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Ajustar pantalla"</string>
-    <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"No se puede cambiar el tamaño de esta aplicación"</string>
-    <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) -->
+    <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"La aplicación no se puede mover aquí"</string>
+    <string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"Maximizar"</string>
+    <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Acoplar a la izquierda"</string>
+    <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"Acoplar a la derecha"</string>
+    <!-- no translation found for open_by_default_settings_text (2526548548598185500) -->
     <skip />
-    <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) -->
+    <!-- no translation found for open_by_default_dialog_subheader_text (1729599730664063881) -->
     <skip />
-    <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) -->
+    <!-- no translation found for open_by_default_dialog_in_app_text (6978022419634199806) -->
+    <skip />
+    <!-- no translation found for open_by_default_dialog_in_browser_text (8042769465958497081) -->
+    <skip />
+    <!-- no translation found for open_by_default_dialog_dismiss_button_text (3487238795534582291) -->
     <skip />
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-et/strings.xml b/libs/WindowManager/Shell/res/values-et/strings.xml
index 3d929f6..25c068b 100644
--- a/libs/WindowManager/Shell/res/values-et/strings.xml
+++ b/libs/WindowManager/Shell/res/values-et/strings.xml
@@ -97,6 +97,9 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Kas teil on kaameraprobleeme?\nPuudutage ümberpaigutamiseks."</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Kas probleemi ei lahendatud?\nPuudutage ennistamiseks."</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Kas kaameraprobleeme pole? Puudutage loobumiseks."</string>
+    <string name="windowing_app_handle_education_tooltip" msgid="6398482412956375783">"Puudutage rakenduse menüü avamiseks"</string>
+    <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="6285279585554484957">"Puudutage mitme rakenduse koos kuvamiseks"</string>
+    <string name="windowing_desktop_mode_exit_education_tooltip" msgid="6685429075790085337">"Minge rakenduse menüüst tagasi täisekraanile"</string>
     <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Vaadake ja tehke rohkem"</string>
     <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Lohistage muusse rakendusse, et jagatud ekraanikuva kasutada"</string>
     <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Topeltpuudutage rakendusest väljaspool, et selle asendit muuta"</string>
@@ -126,15 +129,16 @@
     <string name="manage_windows_text" msgid="5567366688493093920">"Akende haldamine"</string>
     <string name="close_text" msgid="4986518933445178928">"Sule"</string>
     <string name="collapse_menu_text" msgid="7515008122450342029">"Sule menüü"</string>
-    <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) -->
-    <skip />
+    <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Ava menüü"</string>
     <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Kuva täisekraanil"</string>
     <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Kuva poolel ekraanil"</string>
-    <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"Selle rakenduse aknasuurust ei saa muuta"</string>
-    <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) -->
-    <skip />
-    <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) -->
-    <skip />
-    <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) -->
-    <skip />
+    <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Rakendust ei saa siia teisaldada"</string>
+    <string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"Maksimeeri"</string>
+    <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Tõmmake vasakule"</string>
+    <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"Tõmmake paremale"</string>
+    <string name="open_by_default_settings_text" msgid="2526548548598185500">"Avamisviisi vaikeseaded"</string>
+    <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Valige, kuidas avada selle rakenduse puhul veebilinke"</string>
+    <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"Rakenduses"</string>
+    <string name="open_by_default_dialog_in_browser_text" msgid="8042769465958497081">"Brauseris"</string>
+    <string name="open_by_default_dialog_dismiss_button_text" msgid="3487238795534582291">"OK"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-eu/strings.xml b/libs/WindowManager/Shell/res/values-eu/strings.xml
index 39bcf08..ba4cbc8 100644
--- a/libs/WindowManager/Shell/res/values-eu/strings.xml
+++ b/libs/WindowManager/Shell/res/values-eu/strings.xml
@@ -97,6 +97,9 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Arazoak dauzkazu kamerarekin?\nBerriro doitzeko, sakatu hau."</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Ez al da konpondu?\nLeheneratzeko, sakatu hau."</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Ez daukazu arazorik kamerarekin? Baztertzeko, sakatu hau."</string>
+    <string name="windowing_app_handle_education_tooltip" msgid="6398482412956375783">"Sakatu hau aplikazioen menua irekitzeko"</string>
+    <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="6285279585554484957">"Sakatu hau aplikazio bat baino gehiago aldi berean erakusteko"</string>
+    <string name="windowing_desktop_mode_exit_education_tooltip" msgid="6685429075790085337">"Itzuli pantaila osora aplikazioen menutik"</string>
     <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Ikusi eta egin gauza gehiago"</string>
     <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Pantaila zatitua ikusteko, arrastatu beste aplikazio bat"</string>
     <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Aplikazioaren posizioa aldatzeko, sakatu birritan haren kanpoaldea"</string>
@@ -126,15 +129,16 @@
     <string name="manage_windows_text" msgid="5567366688493093920">"Kudeatu leihoak"</string>
     <string name="close_text" msgid="4986518933445178928">"Itxi"</string>
     <string name="collapse_menu_text" msgid="7515008122450342029">"Itxi menua"</string>
-    <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) -->
-    <skip />
+    <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Ireki menua"</string>
     <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Handitu pantaila"</string>
     <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Zatitu pantaila"</string>
-    <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"Ezin zaio aldatu tamaina aplikazio honi"</string>
-    <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) -->
-    <skip />
-    <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) -->
-    <skip />
-    <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) -->
-    <skip />
+    <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Aplikazioa ezin da hona ekarri"</string>
+    <string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"Maximizatu"</string>
+    <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Ezarri ezkerrean"</string>
+    <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"Ezarri eskuinean"</string>
+    <string name="open_by_default_settings_text" msgid="2526548548598185500">"Modu lehenetsian irekitzearen ezarpenak"</string>
+    <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Aukeratu nola ireki sareko estekak aplikazio honetan"</string>
+    <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"Aplikazioan"</string>
+    <string name="open_by_default_dialog_in_browser_text" msgid="8042769465958497081">"Arakatzailean"</string>
+    <string name="open_by_default_dialog_dismiss_button_text" msgid="3487238795534582291">"Ados"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-fa/strings.xml b/libs/WindowManager/Shell/res/values-fa/strings.xml
index 9f607bf..95bad9c 100644
--- a/libs/WindowManager/Shell/res/values-fa/strings.xml
+++ b/libs/WindowManager/Shell/res/values-fa/strings.xml
@@ -97,6 +97,9 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"دوربین مشکل دارد؟\nبرای تنظیم مجدد اندازه تک‌ضرب بزنید"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"مشکل برطرف نشد؟\nبرای برگرداندن تک‌ضرب بزنید"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"دوربین مشکلی ندارد؟ برای بستن تک‌ضرب بزنید."</string>
+    <string name="windowing_app_handle_education_tooltip" msgid="6398482412956375783">"برای باز کردن منو برنامه، تک‌ضرب بزنید"</string>
+    <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="6285279585554484957">"برای نمایش چند برنامه با هم، تک‌ضرب بزنید"</string>
+    <string name="windowing_desktop_mode_exit_education_tooltip" msgid="6685429075790085337">"از منو برنامه به تمام‌صفحه برگردید"</string>
     <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"از چندین برنامه به‌طور هم‌زمان استفاده کنید"</string>
     <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"برای حالت صفحهٔ دونیمه، در برنامه‌ای دیگر بکشید"</string>
     <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"برای جابه‌جا کردن برنامه، بیرون از آن دو تک‌ضرب بزنید"</string>
@@ -126,15 +129,16 @@
     <string name="manage_windows_text" msgid="5567366688493093920">"مدیریت کردن پنجره‌ها"</string>
     <string name="close_text" msgid="4986518933445178928">"بستن"</string>
     <string name="collapse_menu_text" msgid="7515008122450342029">"بستن منو"</string>
-    <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) -->
-    <skip />
+    <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"باز کردن منو"</string>
     <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"بزرگ کردن صفحه"</string>
     <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"بزرگ کردن صفحه"</string>
-    <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"اندازه این برنامه را نمی‌توان تغییر داد"</string>
-    <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) -->
-    <skip />
-    <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) -->
-    <skip />
-    <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) -->
-    <skip />
+    <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"برنامه را نمی‌توان به اینجا منتقل کرد"</string>
+    <string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"بزرگ کردن"</string>
+    <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"کشیدن به‌چپ"</string>
+    <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"کشیدن به‌راست"</string>
+    <string name="open_by_default_settings_text" msgid="2526548548598185500">"تنظیمات باز کردن به‌طور پیش‌فرض"</string>
+    <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"انتخاب روش باز کردن پیوندهای وب مربوط به این برنامه"</string>
+    <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"در برنامه"</string>
+    <string name="open_by_default_dialog_in_browser_text" msgid="8042769465958497081">"در مرورگر"</string>
+    <string name="open_by_default_dialog_dismiss_button_text" msgid="3487238795534582291">"تأیید"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-fi/strings.xml b/libs/WindowManager/Shell/res/values-fi/strings.xml
index 04b6241..9c841af 100644
--- a/libs/WindowManager/Shell/res/values-fi/strings.xml
+++ b/libs/WindowManager/Shell/res/values-fi/strings.xml
@@ -97,6 +97,9 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Onko kameran kanssa ongelmia?\nKorjaa napauttamalla"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Eikö ongelma ratkennut?\nKumoa napauttamalla"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Ei ongelmia kameran kanssa? Hylkää napauttamalla."</string>
+    <string name="windowing_app_handle_education_tooltip" msgid="6398482412956375783">"Avaa sovellusvalikko napauttamalla"</string>
+    <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="6285279585554484957">"Näytä useita sovelluksia yhdessä napauttamalla"</string>
+    <string name="windowing_desktop_mode_exit_education_tooltip" msgid="6685429075790085337">"Palaa koko näytön tilaan sovellusvalikosta"</string>
     <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Näe ja tee enemmän"</string>
     <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Käytä jaettua näyttöä vetämällä tähän toinen sovellus"</string>
     <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Kaksoisnapauta sovelluksen ulkopuolella, jos haluat siirtää sitä"</string>
@@ -126,15 +129,16 @@
     <string name="manage_windows_text" msgid="5567366688493093920">"Hallinnoi ikkunoita"</string>
     <string name="close_text" msgid="4986518933445178928">"Sulje"</string>
     <string name="collapse_menu_text" msgid="7515008122450342029">"Sulje valikko"</string>
-    <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) -->
-    <skip />
+    <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Avaa valikko"</string>
     <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Suurenna näyttö"</string>
     <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Jaa näyttö"</string>
-    <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"Tämän sovellusikkunan kokoa ei voi muuttaa"</string>
-    <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) -->
-    <skip />
-    <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) -->
-    <skip />
-    <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) -->
-    <skip />
+    <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Sovellusta ei voi siirtää tänne"</string>
+    <string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"Suurenna"</string>
+    <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Siirrä vasemmalle"</string>
+    <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"Siirrä oikealle"</string>
+    <string name="open_by_default_settings_text" msgid="2526548548598185500">"Avaa oletusasetusten mukaan"</string>
+    <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Valitse, miten verkkolinkit avataan tässä sovelluksessa"</string>
+    <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"Sovelluksessa"</string>
+    <string name="open_by_default_dialog_in_browser_text" msgid="8042769465958497081">"Selaimella"</string>
+    <string name="open_by_default_dialog_dismiss_button_text" msgid="3487238795534582291">"OK"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml b/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml
index 7312952..c163165 100644
--- a/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml
+++ b/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml
@@ -97,6 +97,9 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Problèmes d\'appareil photo?\nTouchez pour réajuster"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Problème non résolu?\nTouchez pour rétablir"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Aucun problème d\'appareil photo? Touchez pour ignorer."</string>
+    <string name="windowing_app_handle_education_tooltip" msgid="6398482412956375783">"Toucher ici pour ouvrir le menu de l\'appli"</string>
+    <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="6285279585554484957">"Toucher ici pour afficher plusieurs applis ensemble"</string>
+    <string name="windowing_desktop_mode_exit_education_tooltip" msgid="6685429075790085337">"Revenir au mode Plein écran à partir du menu de l\'appli"</string>
     <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Voir et en faire plus"</string>
     <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Faites glisser une autre appli pour utiliser l\'écran partagé"</string>
     <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Touchez deux fois à côté d\'une appli pour la repositionner"</string>
@@ -126,15 +129,21 @@
     <string name="manage_windows_text" msgid="5567366688493093920">"Gérer les fenêtres"</string>
     <string name="close_text" msgid="4986518933445178928">"Fermer"</string>
     <string name="collapse_menu_text" msgid="7515008122450342029">"Fermer le menu"</string>
-    <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) -->
-    <skip />
+    <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Ouvrir le menu"</string>
     <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Agrandir l\'écran"</string>
     <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Aligner l\'écran"</string>
-    <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"Impossible de redimensionner cette appli"</string>
-    <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) -->
+    <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Impossible de déplacer l\'appli ici"</string>
+    <string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"Agrandir"</string>
+    <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Épingler à gauche"</string>
+    <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"Épingler à droite"</string>
+    <!-- no translation found for open_by_default_settings_text (2526548548598185500) -->
     <skip />
-    <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) -->
+    <!-- no translation found for open_by_default_dialog_subheader_text (1729599730664063881) -->
     <skip />
-    <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) -->
+    <!-- no translation found for open_by_default_dialog_in_app_text (6978022419634199806) -->
+    <skip />
+    <!-- no translation found for open_by_default_dialog_in_browser_text (8042769465958497081) -->
+    <skip />
+    <!-- no translation found for open_by_default_dialog_dismiss_button_text (3487238795534582291) -->
     <skip />
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-fr/strings.xml b/libs/WindowManager/Shell/res/values-fr/strings.xml
index 8f4e58f..b2a6f16 100644
--- a/libs/WindowManager/Shell/res/values-fr/strings.xml
+++ b/libs/WindowManager/Shell/res/values-fr/strings.xml
@@ -97,6 +97,9 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Problèmes d\'appareil photo ?\nAppuyez pour réajuster"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Problème non résolu ?\nAppuyez pour rétablir"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Aucun problème d\'appareil photo ? Appuyez pour ignorer."</string>
+    <string name="windowing_app_handle_education_tooltip" msgid="6398482412956375783">"Appuyer pour ouvrir le menu de l\'appli"</string>
+    <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="6285279585554484957">"Appuyer pour afficher plusieurs applis simultanément"</string>
+    <string name="windowing_desktop_mode_exit_education_tooltip" msgid="6685429075790085337">"Revenir en plein écran depuis le menu de l\'appli"</string>
     <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Voir et interagir plus"</string>
     <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Faites glisser une autre appli pour utiliser l\'écran partagé"</string>
     <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Appuyez deux fois en dehors d\'une appli pour la repositionner"</string>
@@ -126,15 +129,21 @@
     <string name="manage_windows_text" msgid="5567366688493093920">"Gérer les fenêtres"</string>
     <string name="close_text" msgid="4986518933445178928">"Fermer"</string>
     <string name="collapse_menu_text" msgid="7515008122450342029">"Fermer le menu"</string>
-    <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) -->
-    <skip />
+    <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Ouvrir le menu"</string>
     <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Mettre en plein écran"</string>
     <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Fractionner l\'écran"</string>
-    <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"Impossible de redimensionner cette appli"</string>
-    <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) -->
+    <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Impossible de déplacer l\'appli ici"</string>
+    <string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"Agrandir"</string>
+    <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Ancrer à gauche"</string>
+    <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"Ancrer à droite"</string>
+    <!-- no translation found for open_by_default_settings_text (2526548548598185500) -->
     <skip />
-    <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) -->
+    <!-- no translation found for open_by_default_dialog_subheader_text (1729599730664063881) -->
     <skip />
-    <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) -->
+    <!-- no translation found for open_by_default_dialog_in_app_text (6978022419634199806) -->
+    <skip />
+    <!-- no translation found for open_by_default_dialog_in_browser_text (8042769465958497081) -->
+    <skip />
+    <!-- no translation found for open_by_default_dialog_dismiss_button_text (3487238795534582291) -->
     <skip />
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-gl/strings.xml b/libs/WindowManager/Shell/res/values-gl/strings.xml
index 5c0aa07..0cc559f 100644
--- a/libs/WindowManager/Shell/res/values-gl/strings.xml
+++ b/libs/WindowManager/Shell/res/values-gl/strings.xml
@@ -97,6 +97,9 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Tes problemas coa cámara?\nToca para reaxustala"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Non se solucionaron os problemas?\nToca para reverter o seu tratamento"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Non hai problemas coa cámara? Tocar para ignorar."</string>
+    <string name="windowing_app_handle_education_tooltip" msgid="6398482412956375783">"Toca para abrir o menú da aplicación"</string>
+    <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="6285279585554484957">"Toca para mostrar varias aplicacións xuntas"</string>
+    <string name="windowing_desktop_mode_exit_education_tooltip" msgid="6685429075790085337">"Volve á pantalla completa desde o menú da aplicación"</string>
     <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Ver e facer máis"</string>
     <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Arrastra outra aplicación para usar a pantalla dividida"</string>
     <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Toca dúas veces fóra da aplicación para cambiala de posición"</string>
@@ -126,15 +129,16 @@
     <string name="manage_windows_text" msgid="5567366688493093920">"Xestionar as ventás"</string>
     <string name="close_text" msgid="4986518933445178928">"Pechar"</string>
     <string name="collapse_menu_text" msgid="7515008122450342029">"Pechar o menú"</string>
-    <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) -->
-    <skip />
+    <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Abrir o menú"</string>
     <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maximizar pantalla"</string>
     <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Encaixar pantalla"</string>
-    <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"Non se pode cambiar o tamaño desta aplicación"</string>
-    <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) -->
-    <skip />
-    <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) -->
-    <skip />
-    <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) -->
-    <skip />
+    <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Non se pode mover aquí a aplicación"</string>
+    <string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"Maximizar"</string>
+    <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Axustar á esquerda"</string>
+    <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"Axustar á dereita"</string>
+    <string name="open_by_default_settings_text" msgid="2526548548598185500">"Abrir coa configuración predeterminada"</string>
+    <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Escoller como abrir as ligazóns web para esta aplicación"</string>
+    <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"Na aplicación"</string>
+    <string name="open_by_default_dialog_in_browser_text" msgid="8042769465958497081">"No navegador"</string>
+    <string name="open_by_default_dialog_dismiss_button_text" msgid="3487238795534582291">"Aceptar"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-gu/strings.xml b/libs/WindowManager/Shell/res/values-gu/strings.xml
index a382d0b..460f870 100644
--- a/libs/WindowManager/Shell/res/values-gu/strings.xml
+++ b/libs/WindowManager/Shell/res/values-gu/strings.xml
@@ -97,6 +97,9 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"કૅમેરામાં સમસ્યાઓ છે?\nફરીથી ફિટ કરવા માટે ટૅપ કરો"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"સુધારો નથી થયો?\nપહેલાંના પર પાછું ફેરવવા માટે ટૅપ કરો"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"કૅમેરામાં કોઈ સમસ્યા નથી? છોડી દેવા માટે ટૅપ કરો."</string>
+    <string name="windowing_app_handle_education_tooltip" msgid="6398482412956375783">"ઍપ મેનૂ ખોલવા માટે ટૅપ કરો"</string>
+    <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="6285279585554484957">"એકથી વધુ ઍપ એકસાથે બતાવવા માટે ટૅપ કરો"</string>
+    <string name="windowing_desktop_mode_exit_education_tooltip" msgid="6685429075790085337">"ઍપ મેનૂમાંથી પૂર્ણસ્ક્રીન પર પાછા ફરો"</string>
     <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"જુઓ અને બીજું ઘણું કરો"</string>
     <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"વિભાજિત સ્ક્રીન માટે કોઈ અન્ય ઍપમાં ખેંચો"</string>
     <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"કોઈ ઍપની જગ્યા બદલવા માટે, તેની બહાર બે વાર ટૅપ કરો"</string>
@@ -126,15 +129,16 @@
     <string name="manage_windows_text" msgid="5567366688493093920">"વિન્ડો મેનેજ કરો"</string>
     <string name="close_text" msgid="4986518933445178928">"બંધ કરો"</string>
     <string name="collapse_menu_text" msgid="7515008122450342029">"મેનૂ બંધ કરો"</string>
-    <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) -->
-    <skip />
+    <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"મેનૂ ખોલો"</string>
     <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"સ્ક્રીન કરો મોટી કરો"</string>
     <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"સ્ક્રીન સ્નૅપ કરો"</string>
-    <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"આ ઍપના કદમાં વધઘટ કરી શકાતો નથી"</string>
-    <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) -->
-    <skip />
-    <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) -->
-    <skip />
-    <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) -->
-    <skip />
+    <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"ઍપ અહીં ખસેડી શકાતી નથી"</string>
+    <string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"મોટું કરો"</string>
+    <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"ડાબે સ્નૅપ કરો"</string>
+    <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"જમણે સ્નૅપ કરો"</string>
+    <string name="open_by_default_settings_text" msgid="2526548548598185500">"\'ડિફૉલ્ટ તરીકે ખોલો\' સેટિંગ"</string>
+    <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"આ ઍપ માટે વેબ લિંક ખોલવાની રીત પસંદ કરો"</string>
+    <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"ઍપમાં"</string>
+    <string name="open_by_default_dialog_in_browser_text" msgid="8042769465958497081">"તમારા બ્રાઉઝરમાં"</string>
+    <string name="open_by_default_dialog_dismiss_button_text" msgid="3487238795534582291">"ઓકે"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-hi/strings.xml b/libs/WindowManager/Shell/res/values-hi/strings.xml
index 3760820..17ceca1 100644
--- a/libs/WindowManager/Shell/res/values-hi/strings.xml
+++ b/libs/WindowManager/Shell/res/values-hi/strings.xml
@@ -97,6 +97,9 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"क्या कैमरे से जुड़ी कोई समस्या है?\nफिर से फ़िट करने के लिए टैप करें"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"क्या समस्या ठीक नहीं हुई?\nपहले जैसा करने के लिए टैप करें"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"क्या कैमरे से जुड़ी कोई समस्या नहीं है? खारिज करने के लिए टैप करें."</string>
+    <string name="windowing_app_handle_education_tooltip" msgid="6398482412956375783">"ऐप्लिकेशन मेन्यू खोलने के लिए टैप करें"</string>
+    <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="6285279585554484957">"कई ऐप्लिकेशन एक साथ दिखाने के लिए टैप करें"</string>
+    <string name="windowing_desktop_mode_exit_education_tooltip" msgid="6685429075790085337">"ऐप्लिकेशन मेन्यू से फ़ुलस्क्रीन मोड पर वापस जाएं"</string>
     <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"पूरी जानकारी लेकर, बेहतर तरीके से काम करें"</string>
     <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"स्प्लिट स्क्रीन का इस्तेमाल करने के लिए, किसी अन्य ऐप्लिकेशन को खींचें और छोड़ें"</string>
     <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"किसी ऐप्लिकेशन की जगह बदलने के लिए, उसके बाहर दो बार टैप करें"</string>
@@ -129,8 +132,13 @@
     <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"मेन्यू खोलें"</string>
     <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"स्क्रीन को बड़ा करें"</string>
     <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"स्नैप स्क्रीन"</string>
-    <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"इस ऐप्लिकेशन का साइज़ नहीं बदला जा सकता"</string>
+    <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"ऐप्लिकेशन को यहां मूव नहीं किया जा सकता"</string>
     <string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"बड़ा करें"</string>
     <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"बाईं ओर स्नैप करें"</string>
     <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"दाईं ओर स्नैप करें"</string>
+    <string name="open_by_default_settings_text" msgid="2526548548598185500">"डिफ़ॉल्ट सेटिंग के हिसाब से खोलें"</string>
+    <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"इस ऐप्लिकेशन के लिए वेब लिंक खोलने का तरीका चुनें"</string>
+    <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"ऐप्लिकेशन में"</string>
+    <string name="open_by_default_dialog_in_browser_text" msgid="8042769465958497081">"आपके ब्राउज़र में"</string>
+    <string name="open_by_default_dialog_dismiss_button_text" msgid="3487238795534582291">"ठीक है"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-hr/strings.xml b/libs/WindowManager/Shell/res/values-hr/strings.xml
index f233c02..20fa546 100644
--- a/libs/WindowManager/Shell/res/values-hr/strings.xml
+++ b/libs/WindowManager/Shell/res/values-hr/strings.xml
@@ -97,6 +97,9 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Problemi s fotoaparatom?\nDodirnite za popravak"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Problem nije riješen?\nDodirnite za vraćanje"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Nemate problema s fotoaparatom? Dodirnite za odbacivanje."</string>
+    <string name="windowing_app_handle_education_tooltip" msgid="6398482412956375783">"Dodirnite za otvaranje izbornika aplikacije"</string>
+    <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="6285279585554484957">"Dodirnite za prikaz više aplikacija zajedno"</string>
+    <string name="windowing_desktop_mode_exit_education_tooltip" msgid="6685429075790085337">"Vratite se na cijeli zaslon iz izbornika aplikacije"</string>
     <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Gledajte i učinite više"</string>
     <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Povucite drugu aplikaciju unutra da biste podijelili zaslon"</string>
     <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Dvaput dodirnite izvan aplikacije da biste je premjestili"</string>
@@ -126,15 +129,16 @@
     <string name="manage_windows_text" msgid="5567366688493093920">"Upravljanje prozorima"</string>
     <string name="close_text" msgid="4986518933445178928">"Zatvorite"</string>
     <string name="collapse_menu_text" msgid="7515008122450342029">"Zatvorite izbornik"</string>
-    <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) -->
-    <skip />
+    <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Otvaranje izbornika"</string>
     <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maksimalno povećaj zaslon"</string>
     <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Izradi snimku zaslona"</string>
-    <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"Nije moguće promijeniti veličinu aplikacije"</string>
-    <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) -->
-    <skip />
-    <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) -->
-    <skip />
-    <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) -->
-    <skip />
+    <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Aplikacija se ne može premjestiti ovdje"</string>
+    <string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"Maksimiziraj"</string>
+    <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Poravnaj lijevo"</string>
+    <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"Poravnaj desno"</string>
+    <string name="open_by_default_settings_text" msgid="2526548548598185500">"Otvori prema zadanim postavkama"</string>
+    <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Odaberite način otvaranja web-veza za ovu aplikaciju"</string>
+    <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"U aplikaciji"</string>
+    <string name="open_by_default_dialog_in_browser_text" msgid="8042769465958497081">"U pregledniku"</string>
+    <string name="open_by_default_dialog_dismiss_button_text" msgid="3487238795534582291">"U redu"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-hu/strings.xml b/libs/WindowManager/Shell/res/values-hu/strings.xml
index fb44cd8..78cec15 100644
--- a/libs/WindowManager/Shell/res/values-hu/strings.xml
+++ b/libs/WindowManager/Shell/res/values-hu/strings.xml
@@ -97,6 +97,9 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Kamerával kapcsolatos problémába ütközött?\nKoppintson a megoldáshoz."</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Nem sikerült a hiba kijavítása?\nKoppintson a visszaállításhoz."</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Nincsenek problémái kamerával? Koppintson az elvetéshez."</string>
+    <string name="windowing_app_handle_education_tooltip" msgid="6398482412956375783">"Koppintson az alkalmazásmenü megnyitásához"</string>
+    <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="6285279585554484957">"Koppintson több alkalmazás együttes megjelenítéséhez"</string>
+    <string name="windowing_desktop_mode_exit_education_tooltip" msgid="6685429075790085337">"A teljes képernyőre az alkalmazásmenüben térhet vissza"</string>
     <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Több mindent láthat és tehet"</string>
     <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Húzzon ide egy másik alkalmazást az osztott képernyő használatához"</string>
     <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Koppintson duplán az alkalmazáson kívül az áthelyezéséhez"</string>
@@ -129,8 +132,13 @@
     <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Menü megnyitása"</string>
     <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Képernyő méretének maximalizálása"</string>
     <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Igazodás a képernyő adott részéhez"</string>
-    <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"Ezt az alkalmazást nem lehet átméretezni"</string>
+    <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Az alkalmazás nem helyezhető át ide"</string>
     <string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"Teljes méret"</string>
     <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Balra igazítás"</string>
     <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"Jobbra igazítás"</string>
+    <string name="open_by_default_settings_text" msgid="2526548548598185500">"Alapértelmezett beállítások megnyitása"</string>
+    <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Az app webes linkjeinek megnyitásához használt módszer"</string>
+    <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"Az alkalmazásban"</string>
+    <string name="open_by_default_dialog_in_browser_text" msgid="8042769465958497081">"A böngészőben"</string>
+    <string name="open_by_default_dialog_dismiss_button_text" msgid="3487238795534582291">"OK"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-hy/strings.xml b/libs/WindowManager/Shell/res/values-hy/strings.xml
index cd21faa..1461322d 100644
--- a/libs/WindowManager/Shell/res/values-hy/strings.xml
+++ b/libs/WindowManager/Shell/res/values-hy/strings.xml
@@ -97,6 +97,9 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Տեսախցիկի հետ կապված խնդիրնե՞ր կան։\nՀպեք՝ վերակարգավորելու համար։"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Չհաջողվե՞ց շտկել։\nՀպեք՝ փոփոխությունները չեղարկելու համար։"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Տեսախցիկի հետ կապված խնդիրներ չկա՞ն։ Փակելու համար հպեք։"</string>
+    <string name="windowing_app_handle_education_tooltip" msgid="6398482412956375783">"Հպեք՝ հավելվածի ընտրացանկը բացելու համար"</string>
+    <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="6285279585554484957">"Հպեք՝ էկրանին մի քանի հավելված միասին դիտելու համար"</string>
+    <string name="windowing_desktop_mode_exit_education_tooltip" msgid="6685429075790085337">"Հավելվածի ընտրացանկից վերադառնալ լիաէկրան ռեժիմ"</string>
     <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Միաժամանակ կատարեք մի քանի առաջադրանք"</string>
     <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Քաշեք մյուս հավելվածի մեջ՝ էկրանի տրոհումն օգտագործելու համար"</string>
     <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Կրկնակի հպեք հավելվածի կողքին՝ այն տեղափոխելու համար"</string>
@@ -126,15 +129,16 @@
     <string name="manage_windows_text" msgid="5567366688493093920">"Կառավարել պատուհանները"</string>
     <string name="close_text" msgid="4986518933445178928">"Փակել"</string>
     <string name="collapse_menu_text" msgid="7515008122450342029">"Փակել ընտրացանկը"</string>
-    <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) -->
-    <skip />
+    <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Բացել ընտրացանկը"</string>
     <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Ծավալել էկրանը"</string>
     <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Ծալել էկրանը"</string>
-    <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"Այս հավելվածի չափը հնարավոր չէ փոխել"</string>
-    <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) -->
-    <skip />
-    <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) -->
-    <skip />
-    <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) -->
-    <skip />
+    <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Հավելվածը հնարավոր չէ տեղափոխել այստեղ"</string>
+    <string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"Ծավալել"</string>
+    <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Ամրացնել ձախ կողմում"</string>
+    <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"Ամրացնել աջ կողմում"</string>
+    <string name="open_by_default_settings_text" msgid="2526548548598185500">"Բացել կարգավորումներն ըստ կանխադրման"</string>
+    <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Ընտրեք՝ ինչպես բացել այս հավելվածի վեբ հղումները"</string>
+    <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"Հավելվածում"</string>
+    <string name="open_by_default_dialog_in_browser_text" msgid="8042769465958497081">"Ձեր դիտարկիչում"</string>
+    <string name="open_by_default_dialog_dismiss_button_text" msgid="3487238795534582291">"Եղավ"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-in/strings.xml b/libs/WindowManager/Shell/res/values-in/strings.xml
index ba0683d..23626e4 100644
--- a/libs/WindowManager/Shell/res/values-in/strings.xml
+++ b/libs/WindowManager/Shell/res/values-in/strings.xml
@@ -97,6 +97,9 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Masalah kamera?\nKetuk untuk memperbaiki"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Tidak dapat diperbaiki?\nKetuk untuk mengembalikan"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Tidak ada masalah kamera? Ketuk untuk menutup."</string>
+    <string name="windowing_app_handle_education_tooltip" msgid="6398482412956375783">"Ketuk untuk membuka menu aplikasi"</string>
+    <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="6285279585554484957">"Ketuk untuk menampilkan beberapa aplikasi secara bersamaan"</string>
+    <string name="windowing_desktop_mode_exit_education_tooltip" msgid="6685429075790085337">"Kembali ke layar penuh dari menu aplikasi"</string>
     <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Lihat dan lakukan lebih banyak hal"</string>
     <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Tarik aplikasi lain untuk menggunakan layar terpisah"</string>
     <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Ketuk dua kali di luar aplikasi untuk mengubah posisinya"</string>
@@ -126,15 +129,16 @@
     <string name="manage_windows_text" msgid="5567366688493093920">"Kelola Jendela"</string>
     <string name="close_text" msgid="4986518933445178928">"Tutup"</string>
     <string name="collapse_menu_text" msgid="7515008122450342029">"Tutup Menu"</string>
-    <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) -->
-    <skip />
+    <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Buka Menu"</string>
     <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Perbesar Layar"</string>
     <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Gabungkan Layar"</string>
-    <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"Ukuran aplikasi ini tidak dapat diubah"</string>
-    <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) -->
-    <skip />
-    <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) -->
-    <skip />
-    <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) -->
-    <skip />
+    <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Aplikasi tidak dapat dipindahkan ke sini"</string>
+    <string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"Maksimalkan"</string>
+    <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Maksimalkan ke kiri"</string>
+    <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"Maksimalkan ke kanan"</string>
+    <string name="open_by_default_settings_text" msgid="2526548548598185500">"Buka dengan setelan default"</string>
+    <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Pilih cara membuka link web untuk aplikasi ini"</string>
+    <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"Di aplikasi"</string>
+    <string name="open_by_default_dialog_in_browser_text" msgid="8042769465958497081">"Di browser Anda"</string>
+    <string name="open_by_default_dialog_dismiss_button_text" msgid="3487238795534582291">"Oke"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-is/strings.xml b/libs/WindowManager/Shell/res/values-is/strings.xml
index b427eaf..6ae4c7c 100644
--- a/libs/WindowManager/Shell/res/values-is/strings.xml
+++ b/libs/WindowManager/Shell/res/values-is/strings.xml
@@ -97,6 +97,9 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Myndavélavesen?\nÝttu til að breyta stærð"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Ennþá vesen?\nÝttu til að afturkalla"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Ekkert myndavélavesen? Ýttu til að hunsa."</string>
+    <string name="windowing_app_handle_education_tooltip" msgid="6398482412956375783">"Ýttu til að opna forritavalmyndina"</string>
+    <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="6285279585554484957">"Ýttu til að sjá mörg forrit saman"</string>
+    <string name="windowing_desktop_mode_exit_education_tooltip" msgid="6685429075790085337">"Opnaðu allan skjáinn aftur á forritavalmyndinni"</string>
     <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Sjáðu og gerðu meira"</string>
     <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Dragðu annað forrit inn til að nota skjáskiptingu"</string>
     <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Ýttu tvisvar utan við forrit til að færa það"</string>
@@ -126,15 +129,16 @@
     <string name="manage_windows_text" msgid="5567366688493093920">"Stjórna gluggum"</string>
     <string name="close_text" msgid="4986518933445178928">"Loka"</string>
     <string name="collapse_menu_text" msgid="7515008122450342029">"Loka valmynd"</string>
-    <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) -->
-    <skip />
+    <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Opna valmynd"</string>
     <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Stækka skjá"</string>
     <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Smelluskjár"</string>
-    <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"Ekki er hægt að breyta stærð þessa forrits"</string>
-    <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) -->
-    <skip />
-    <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) -->
-    <skip />
-    <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) -->
-    <skip />
+    <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Ekki er hægt að færa forritið hingað"</string>
+    <string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"Stækka"</string>
+    <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Smella til vinstri"</string>
+    <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"Smella til hægri"</string>
+    <string name="open_by_default_settings_text" msgid="2526548548598185500">"Stillingar sjálfvirkrar opnunar"</string>
+    <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Veldu hvernig veftenglar opnast í forritinu"</string>
+    <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"Í forritinu"</string>
+    <string name="open_by_default_dialog_in_browser_text" msgid="8042769465958497081">"Í vafranum"</string>
+    <string name="open_by_default_dialog_dismiss_button_text" msgid="3487238795534582291">"Í lagi"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-it/strings.xml b/libs/WindowManager/Shell/res/values-it/strings.xml
index 9eb9d4e..b564245 100644
--- a/libs/WindowManager/Shell/res/values-it/strings.xml
+++ b/libs/WindowManager/Shell/res/values-it/strings.xml
@@ -97,6 +97,9 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Problemi con la fotocamera?\nTocca per risolverli"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Il problema non si è risolto?\nTocca per ripristinare"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Nessun problema con la fotocamera? Tocca per ignorare."</string>
+    <string name="windowing_app_handle_education_tooltip" msgid="6398482412956375783">"Tocca per aprire il menu dell\'app"</string>
+    <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="6285279585554484957">"Tocca per mostrare più app insieme"</string>
+    <string name="windowing_desktop_mode_exit_education_tooltip" msgid="6685429075790085337">"Torna allo schermo intero dal menu dell\'app"</string>
     <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Visualizza più contenuti e fai di più"</string>
     <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Trascina in un\'altra app per usare lo schermo diviso"</string>
     <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Tocca due volte fuori da un\'app per riposizionarla"</string>
@@ -126,15 +129,21 @@
     <string name="manage_windows_text" msgid="5567366688493093920">"Gestisci finestre"</string>
     <string name="close_text" msgid="4986518933445178928">"Chiudi"</string>
     <string name="collapse_menu_text" msgid="7515008122450342029">"Chiudi il menu"</string>
-    <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) -->
-    <skip />
+    <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Apri il menu"</string>
     <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Massimizza schermo"</string>
     <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Aggancia schermo"</string>
-    <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"Non è possibile ridimensionare questa app"</string>
-    <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) -->
+    <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Impossibile spostare l\'app qui"</string>
+    <string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"Ingrandisci"</string>
+    <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Aggancia a sinistra"</string>
+    <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"Aggancia a destra"</string>
+    <!-- no translation found for open_by_default_settings_text (2526548548598185500) -->
     <skip />
-    <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) -->
+    <!-- no translation found for open_by_default_dialog_subheader_text (1729599730664063881) -->
     <skip />
-    <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) -->
+    <!-- no translation found for open_by_default_dialog_in_app_text (6978022419634199806) -->
+    <skip />
+    <!-- no translation found for open_by_default_dialog_in_browser_text (8042769465958497081) -->
+    <skip />
+    <!-- no translation found for open_by_default_dialog_dismiss_button_text (3487238795534582291) -->
     <skip />
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-iw/strings.xml b/libs/WindowManager/Shell/res/values-iw/strings.xml
index 3e82198..41765e3 100644
--- a/libs/WindowManager/Shell/res/values-iw/strings.xml
+++ b/libs/WindowManager/Shell/res/values-iw/strings.xml
@@ -97,6 +97,9 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"בעיות במצלמה?\nאפשר להקיש כדי לבצע התאמה מחדש"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"הבעיה לא נפתרה?\nאפשר להקיש כדי לחזור לגרסה הקודמת"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"אין בעיות במצלמה? אפשר להקיש כדי לסגור."</string>
+    <string name="windowing_app_handle_education_tooltip" msgid="6398482412956375783">"צריך להקיש כדי לפתוח את תפריט האפליקציה"</string>
+    <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="6285279585554484957">"אפשר להקיש כדי להציג כמה אפליקציות יחד"</string>
+    <string name="windowing_desktop_mode_exit_education_tooltip" msgid="6685429075790085337">"חזרה למסך מלא מתפריט האפליקציה"</string>
     <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"רוצה לראות ולעשות יותר?"</string>
     <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"צריך לגרור אפליקציה אחרת כדי להשתמש במסך המפוצל"</string>
     <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"צריך להקיש הקשה כפולה מחוץ לאפליקציה כדי למקם אותה מחדש"</string>
@@ -126,15 +129,16 @@
     <string name="manage_windows_text" msgid="5567366688493093920">"ניהול החלונות"</string>
     <string name="close_text" msgid="4986518933445178928">"סגירה"</string>
     <string name="collapse_menu_text" msgid="7515008122450342029">"סגירת התפריט"</string>
-    <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) -->
-    <skip />
+    <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"פתיחת התפריט"</string>
     <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"הגדלת המסך"</string>
     <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"כיווץ המסך"</string>
-    <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"לא ניתן לשנות את גודל החלון של האפליקציה הזו"</string>
-    <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) -->
-    <skip />
-    <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) -->
-    <skip />
-    <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) -->
-    <skip />
+    <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"לא ניתן להעביר את האפליקציה לכאן"</string>
+    <string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"הגדלה"</string>
+    <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"הצמדה לשמאל"</string>
+    <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"הצמדה לימין"</string>
+    <string name="open_by_default_settings_text" msgid="2526548548598185500">"הגדרות לפתיחה כברירת מחדל"</string>
+    <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"בחירת האופן שבו קישורים לדפי אינטרנט אחרים ייפתחו באפליקציה הזו"</string>
+    <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"באפליקציה"</string>
+    <string name="open_by_default_dialog_in_browser_text" msgid="8042769465958497081">"בדפדפן"</string>
+    <string name="open_by_default_dialog_dismiss_button_text" msgid="3487238795534582291">"אישור"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-ja/strings.xml b/libs/WindowManager/Shell/res/values-ja/strings.xml
index 1225b62..c7dfd45 100644
--- a/libs/WindowManager/Shell/res/values-ja/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ja/strings.xml
@@ -97,6 +97,9 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"カメラに関する問題の場合は、\nタップすると修正できます"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"修正されなかった場合は、\nタップすると元に戻ります"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"カメラに関する問題でない場合は、タップすると閉じます。"</string>
+    <string name="windowing_app_handle_education_tooltip" msgid="6398482412956375783">"タップするとアプリメニューが開きます"</string>
+    <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="6285279585554484957">"タップすると複数のアプリが同時に表示されます"</string>
+    <string name="windowing_desktop_mode_exit_education_tooltip" msgid="6685429075790085337">"アプリメニューから全画面表示に戻ります"</string>
     <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"表示を拡大して機能を強化"</string>
     <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"分割画面にするにはもう 1 つのアプリをドラッグしてください"</string>
     <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"位置を変えるにはアプリの外側をダブルタップしてください"</string>
@@ -129,8 +132,13 @@
     <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"メニューを開く"</string>
     <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"画面の最大化"</string>
     <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"画面のスナップ"</string>
-    <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"このアプリはサイズ変更できません"</string>
+    <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"アプリはここに移動できません"</string>
     <string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"最大化"</string>
     <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"左にスナップ"</string>
     <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"右にスナップ"</string>
+    <string name="open_by_default_settings_text" msgid="2526548548598185500">"デフォルトの設定で開く"</string>
+    <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"このアプリのウェブリンクを開く方法を選択"</string>
+    <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"アプリ内"</string>
+    <string name="open_by_default_dialog_in_browser_text" msgid="8042769465958497081">"ブラウザ内"</string>
+    <string name="open_by_default_dialog_dismiss_button_text" msgid="3487238795534582291">"OK"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-ka/strings.xml b/libs/WindowManager/Shell/res/values-ka/strings.xml
index 3e1f726..4986c2d 100644
--- a/libs/WindowManager/Shell/res/values-ka/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ka/strings.xml
@@ -97,6 +97,9 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"კამერად პრობლემები აქვს?\nშეეხეთ გამოსასწორებლად"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"არ გამოსწორდა?\nშეეხეთ წინა ვერსიის დასაბრუნებლად"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"კამერას პრობლემები არ აქვს? შეეხეთ უარყოფისთვის."</string>
+    <string name="windowing_app_handle_education_tooltip" msgid="6398482412956375783">"შეეხეთ აპის მენიუს გასახსნელად"</string>
+    <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="6285279585554484957">"შეეხეთ რამდენიმე აპის ერთად საჩვენებლად"</string>
+    <string name="windowing_desktop_mode_exit_education_tooltip" msgid="6685429075790085337">"სრულეკრანიან რეჟიმზე დაბრუნდით აპის მენიუდან"</string>
     <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"მეტის ნახვა და გაკეთება"</string>
     <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"ეკრანის გასაყოფად ჩავლებით გადაიტანეთ სხვა აპში"</string>
     <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"ორმაგად შეეხეთ აპის გარშემო სივრცეს, რათა ის სხვაგან გადაიტანოთ"</string>
@@ -129,8 +132,13 @@
     <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"მენიუს გახსნა"</string>
     <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"აპლიკაციის გაშლა სრულ ეკრანზე"</string>
     <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"აპლიკაციის დაპატარავება ეკრანზე"</string>
-    <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"აპის ზომის შეცვლა შეუძლებელია"</string>
+    <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"აპის აქ გადატანა შეუძლებელია"</string>
     <string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"მაქსიმალურად გაშლა"</string>
     <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"მარცხნივ გადატანა"</string>
     <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"მარჯვნივ გადატანა"</string>
+    <string name="open_by_default_settings_text" msgid="2526548548598185500">"პარამეტრების ნაგულისხმევად გახსნა"</string>
+    <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"ამ აპისთვის ვებ ბმულების გახსნის წესის არჩევა"</string>
+    <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"აპში"</string>
+    <string name="open_by_default_dialog_in_browser_text" msgid="8042769465958497081">"თქვენს ბრაუზერში"</string>
+    <string name="open_by_default_dialog_dismiss_button_text" msgid="3487238795534582291">"კარგი"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-kk/strings.xml b/libs/WindowManager/Shell/res/values-kk/strings.xml
index dd4e5c9..7c49ae5 100644
--- a/libs/WindowManager/Shell/res/values-kk/strings.xml
+++ b/libs/WindowManager/Shell/res/values-kk/strings.xml
@@ -97,6 +97,9 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Камерада қателер шықты ма?\nЖөндеу үшін түртіңіз."</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Жөнделмеді ме?\nҚайтару үшін түртіңіз."</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Камерада қателер шықпады ма? Жабу үшін түртіңіз."</string>
+    <string name="windowing_app_handle_education_tooltip" msgid="6398482412956375783">"Қолданба мәзірін ашу үшін түртіңіз"</string>
+    <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="6285279585554484957">"Бірнеше қолданбаны қатар көрсету үшін түртіңіз"</string>
+    <string name="windowing_desktop_mode_exit_education_tooltip" msgid="6685429075790085337">"Қолданба мәзірінен толық экран режиміне қайту"</string>
     <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Қосымша ақпаратты қарап, әрекеттер жасау"</string>
     <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Экранды бөлу үшін басқа қолданбаға өтіңіз."</string>
     <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Қолданбаның орнын өзгерту үшін одан тыс жерді екі рет түртіңіз."</string>
@@ -126,15 +129,16 @@
     <string name="manage_windows_text" msgid="5567366688493093920">"Терезелерді басқару"</string>
     <string name="close_text" msgid="4986518933445178928">"Жабу"</string>
     <string name="collapse_menu_text" msgid="7515008122450342029">"Мәзірді жабу"</string>
-    <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) -->
-    <skip />
+    <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Мәзірді ашу"</string>
     <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Экранды ұлғайту"</string>
     <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Экранды бөлу"</string>
-    <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"Бұл қолданбаның өлшемі өзгертілмейді."</string>
-    <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) -->
-    <skip />
-    <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) -->
-    <skip />
-    <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) -->
-    <skip />
+    <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Қолданба бұл жерге қойылмайды."</string>
+    <string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"Жаю"</string>
+    <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Солға тіркеу"</string>
+    <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"Оңға тіркеу"</string>
+    <string name="open_by_default_settings_text" msgid="2526548548598185500">"Әдепкісінше ашу параметрлері"</string>
+    <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Осы қолданбадағы веб-сілтемелерді ашу жолын таңдаңыз"</string>
+    <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"Қолданбада"</string>
+    <string name="open_by_default_dialog_in_browser_text" msgid="8042769465958497081">"Браузерде"</string>
+    <string name="open_by_default_dialog_dismiss_button_text" msgid="3487238795534582291">"Жарайды"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-km/strings.xml b/libs/WindowManager/Shell/res/values-km/strings.xml
index 96fe62e..c6af1252 100644
--- a/libs/WindowManager/Shell/res/values-km/strings.xml
+++ b/libs/WindowManager/Shell/res/values-km/strings.xml
@@ -97,6 +97,9 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"មានបញ្ហា​ពាក់ព័ន្ធនឹង​កាមេរ៉ាឬ?\nចុចដើម្បី​ដោះស្រាយ"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"មិនបាន​ដោះស្រាយ​បញ្ហានេះទេឬ?\nចុចដើម្បី​ត្រឡប់"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"មិនមាន​បញ្ហាពាក់ព័ន្ធនឹង​កាមេរ៉ាទេឬ? ចុចដើម្បី​ច្រានចោល។"</string>
+    <string name="windowing_app_handle_education_tooltip" msgid="6398482412956375783">"ចុច​ដើម្បីបើក​ម៉ឺនុយ​កម្មវិធី"</string>
+    <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="6285279585554484957">"ចុច​ដើម្បីបង្ហាញ​កម្មវិធី​ច្រើនរួមគ្នា"</string>
+    <string name="windowing_desktop_mode_exit_education_tooltip" msgid="6685429075790085337">"ត្រឡប់ទៅ​អេក្រង់​ពេញវិញ​ពីម៉ឺនុយ​កម្មវិធី"</string>
     <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"មើលឃើញ និងធ្វើបានកាន់តែច្រើន"</string>
     <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"អូស​កម្មវិធី​មួយ​ទៀត​ចូល ដើម្បី​ប្រើ​មុខងារ​បំបែកអេក្រង់"</string>
     <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"ចុចពីរដង​នៅ​ក្រៅ​កម្មវិធី ដើម្បី​ប្ដូរ​ទីតាំង​កម្មវិធី​នោះ"</string>
@@ -126,15 +129,16 @@
     <string name="manage_windows_text" msgid="5567366688493093920">"គ្រប់គ្រង​វិនដូ"</string>
     <string name="close_text" msgid="4986518933445178928">"បិទ"</string>
     <string name="collapse_menu_text" msgid="7515008122450342029">"បិទ​ម៉ឺនុយ"</string>
-    <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) -->
-    <skip />
+    <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"បើកម៉ឺនុយ"</string>
     <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"ពង្រីកអេក្រង់"</string>
     <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"ថតអេក្រង់"</string>
-    <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"មិនអាចប្ដូរទំហំ​កម្មវិធីនេះ​បានទេ"</string>
-    <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) -->
-    <skip />
-    <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) -->
-    <skip />
-    <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) -->
-    <skip />
+    <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"មិនអាចផ្លាស់ទីកម្មវិធីមកទីនេះបានទេ"</string>
+    <string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"ពង្រីក"</string>
+    <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"ផ្លាស់ទីទៅឆ្វេង"</string>
+    <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"ផ្លាស់ទីទៅស្ដាំ"</string>
+    <string name="open_by_default_settings_text" msgid="2526548548598185500">"ការកំណត់បើកតាមលំនាំដើម"</string>
+    <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"ជ្រើសរើសរបៀបបើកតំណបណ្ដាញសម្រាប់កម្មវិធីនេះ"</string>
+    <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"នៅក្នុងកម្មវិធី"</string>
+    <string name="open_by_default_dialog_in_browser_text" msgid="8042769465958497081">"នៅក្នុង​កម្មវិធីរុករកតាម​អ៊ីនធឺណិត​របស់អ្នក"</string>
+    <string name="open_by_default_dialog_dismiss_button_text" msgid="3487238795534582291">"យល់ព្រម"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-kn/strings.xml b/libs/WindowManager/Shell/res/values-kn/strings.xml
index b38f744..498ad0f 100644
--- a/libs/WindowManager/Shell/res/values-kn/strings.xml
+++ b/libs/WindowManager/Shell/res/values-kn/strings.xml
@@ -97,6 +97,9 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"ಕ್ಯಾಮರಾ ಸಮಸ್ಯೆಗಳಿವೆಯೇ?\nಮರುಹೊಂದಿಸಲು ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"ಅದನ್ನು ಸರಿಪಡಿಸಲಿಲ್ಲವೇ?\nಹಿಂತಿರುಗಿಸಲು ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"ಕ್ಯಾಮರಾ ಸಮಸ್ಯೆಗಳಿಲ್ಲವೇ? ವಜಾಗೊಳಿಸಲು ಟ್ಯಾಪ್ ಮಾಡಿ."</string>
+    <string name="windowing_app_handle_education_tooltip" msgid="6398482412956375783">"ಆ್ಯಪ್‌ ಮೆನುವನ್ನು ತೆರೆಯಲು ಟ್ಯಾಪ್‌ ಮಾಡಿ"</string>
+    <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="6285279585554484957">"ಅನೇಕ ಆ್ಯಪ್‌ಗಳನ್ನು ಒಟ್ಟಿಗೆ ತೋರಿಸಲು ಟ್ಯಾಪ್‌ ಮಾಡಿ"</string>
+    <string name="windowing_desktop_mode_exit_education_tooltip" msgid="6685429075790085337">"ಆ್ಯಪ್‌ ಮೆನುವಿನಿಂದ ಫುಲ್‌ಸ್ಕ್ರೀನ್‌ಗೆ ಹಿಂತಿರುಗಿ"</string>
     <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"ನೋಡಿ ಮತ್ತು ಹೆಚ್ಚಿನದನ್ನು ಮಾಡಿ"</string>
     <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"ಸ್ಪ್ಲಿಟ್‌ ಸ್ಕ್ರೀನ್‌ಗಾಗಿ ಮತ್ತೊಂದು ಆ್ಯಪ್‌ನಲ್ಲಿ ಡ್ರ್ಯಾಗ್ ಮಾಡಿ"</string>
     <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"ಆ್ಯಪ್ ಒಂದರ ಸ್ಥಾನವನ್ನು ಬದಲಾಯಿಸಲು ಅದರ ಹೊರಗೆ ಡಬಲ್-ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
@@ -126,15 +129,16 @@
     <string name="manage_windows_text" msgid="5567366688493093920">"ವಿಂಡೋಗಳನ್ನು ನಿರ್ವಹಿಸಿ"</string>
     <string name="close_text" msgid="4986518933445178928">"ಮುಚ್ಚಿ"</string>
     <string name="collapse_menu_text" msgid="7515008122450342029">"ಮೆನು ಮುಚ್ಚಿ"</string>
-    <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) -->
-    <skip />
+    <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"ಮೆನು ತೆರೆಯಿರಿ"</string>
     <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"ಸ್ಕ್ರೀನ್ ಅನ್ನು ಮ್ಯಾಕ್ಸಿಮೈಸ್ ಮಾಡಿ"</string>
     <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"ಸ್ನ್ಯಾಪ್ ಸ್ಕ್ರೀನ್"</string>
-    <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"ಈ ಆ್ಯಪ್ ಅನ್ನು ಮರುಗಾತ್ರಗೊಳಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ"</string>
-    <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) -->
-    <skip />
-    <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) -->
-    <skip />
-    <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) -->
-    <skip />
+    <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"ಆ್ಯಪ್ ಅನ್ನು ಇಲ್ಲಿಗೆ ಸರಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ"</string>
+    <string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"ಮ್ಯಾಕ್ಸಿಮೈಸ್ ಮಾಡಿ"</string>
+    <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"ಎಡಕ್ಕೆ ಸ್ನ್ಯಾಪ್ ಮಾಡಿ"</string>
+    <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"ಬಲಕ್ಕೆ ಸ್ನ್ಯಾಪ್ ಮಾಡಿ"</string>
+    <string name="open_by_default_settings_text" msgid="2526548548598185500">"ಡೀಫಾಲ್ಟ್ ಸೆಟ್ಟಿಂಗ್‌ಗಳಿಂದ ತೆರೆಯಿರಿ"</string>
+    <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"ಈ ಆ್ಯಪ್‌ಗೆ ವೆಬ್ ಲಿಂಕ್‌ಗಳನ್ನು ಹೇಗೆ ತೆರೆಯಬೇಕು ಎಂಬುದನ್ನು ಆಯ್ಕೆಮಾಡಿ"</string>
+    <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"ಆ್ಯಪ್‌ನಲ್ಲಿ"</string>
+    <string name="open_by_default_dialog_in_browser_text" msgid="8042769465958497081">"ನಿಮ್ಮ ಬ್ರೌಸರ್‌ನಲ್ಲಿ"</string>
+    <string name="open_by_default_dialog_dismiss_button_text" msgid="3487238795534582291">"ಸರಿ"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-ko/strings.xml b/libs/WindowManager/Shell/res/values-ko/strings.xml
index 421d466..a92d3cb 100644
--- a/libs/WindowManager/Shell/res/values-ko/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ko/strings.xml
@@ -97,6 +97,9 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"카메라 문제가 있나요?\n해결하려면 탭하세요."</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"해결되지 않았나요?\n되돌리려면 탭하세요."</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"카메라에 문제가 없나요? 닫으려면 탭하세요."</string>
+    <string name="windowing_app_handle_education_tooltip" msgid="6398482412956375783">"탭하여 앱 메뉴 열기"</string>
+    <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="6285279585554484957">"탭하여 여러 앱을 함께 표시하기"</string>
+    <string name="windowing_desktop_mode_exit_education_tooltip" msgid="6685429075790085337">"앱 메뉴에서 전체 화면으로 돌아가기"</string>
     <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"더 많은 정보를 보고 더 많은 작업을 처리하세요"</string>
     <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"화면 분할을 사용하려면 다른 앱을 드래그해 가져옵니다."</string>
     <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"앱 위치를 조정하려면 앱 외부를 두 번 탭합니다."</string>
@@ -126,15 +129,16 @@
     <string name="manage_windows_text" msgid="5567366688493093920">"창 관리"</string>
     <string name="close_text" msgid="4986518933445178928">"닫기"</string>
     <string name="collapse_menu_text" msgid="7515008122450342029">"메뉴 닫기"</string>
-    <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) -->
-    <skip />
+    <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"메뉴 열기"</string>
     <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"화면 최대화"</string>
     <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"화면 분할"</string>
-    <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"이 앱은 크기를 조절할 수 없습니다."</string>
-    <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) -->
-    <skip />
-    <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) -->
-    <skip />
-    <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) -->
-    <skip />
+    <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"앱을 여기로 이동할 수 없음"</string>
+    <string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"최대화하기"</string>
+    <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"왼쪽으로 맞추기"</string>
+    <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"오른쪽으로 맞추기"</string>
+    <string name="open_by_default_settings_text" msgid="2526548548598185500">"기본값으로 열기 설정"</string>
+    <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"이 앱에서 웹 링크를 여는 방법을 선택하세요"</string>
+    <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"앱에서"</string>
+    <string name="open_by_default_dialog_in_browser_text" msgid="8042769465958497081">"브라우저에서"</string>
+    <string name="open_by_default_dialog_dismiss_button_text" msgid="3487238795534582291">"확인"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-ky/strings.xml b/libs/WindowManager/Shell/res/values-ky/strings.xml
index abafd7a..b01659d 100644
--- a/libs/WindowManager/Shell/res/values-ky/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ky/strings.xml
@@ -97,6 +97,9 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Камерада маселелер келип чыктыбы?\nОңдоо үчүн таптаңыз"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Оңдолгон жокпу?\nАртка кайтаруу үчүн таптаңыз"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Камерада маселе жокпу? Этибарга албоо үчүн таптаңыз."</string>
+    <string name="windowing_app_handle_education_tooltip" msgid="6398482412956375783">"Колдонмонун менюсун ачуу үчүн таптап коюңуз"</string>
+    <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="6285279585554484957">"Бир нече колдонмону чогуу көрүү үчүн таптап коюңуз"</string>
+    <string name="windowing_desktop_mode_exit_education_tooltip" msgid="6685429075790085337">"Колдонмонун менюсунан толук экранга кайтыңыз"</string>
     <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Көрүп, көбүрөөк нерселерди жасаңыз"</string>
     <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Экранды бөлүү үчүн башка колдонмону сүйрөңүз"</string>
     <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Колдонмону жылдыруу үчүн сырт жагын эки жолу таптаңыз"</string>
@@ -126,15 +129,16 @@
     <string name="manage_windows_text" msgid="5567366688493093920">"Терезелерди тескөө"</string>
     <string name="close_text" msgid="4986518933445178928">"Жабуу"</string>
     <string name="collapse_menu_text" msgid="7515008122450342029">"Менюну жабуу"</string>
-    <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) -->
-    <skip />
+    <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Менюну ачуу"</string>
     <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Экранды чоңойтуу"</string>
     <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Экранды сүрөткө тартып алуу"</string>
-    <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"Бул колдонмонун өлчөмүн өзгөртүүгө болбойт"</string>
-    <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) -->
-    <skip />
-    <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) -->
-    <skip />
-    <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) -->
-    <skip />
+    <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Колдонмону бул жерге жылдырууга болбойт"</string>
+    <string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"Чоңойтуу"</string>
+    <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Солго жылдыруу"</string>
+    <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"Оңго жылдыруу"</string>
+    <string name="open_by_default_settings_text" msgid="2526548548598185500">"Демейки шартта ачуу параметрлери"</string>
+    <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Колдонмодо шилтемелер кантип ачылышы керек экенин тандаңыз"</string>
+    <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"Колдонмодо"</string>
+    <string name="open_by_default_dialog_in_browser_text" msgid="8042769465958497081">"Серепчиңизде"</string>
+    <string name="open_by_default_dialog_dismiss_button_text" msgid="3487238795534582291">"Жарайт"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-lo/strings.xml b/libs/WindowManager/Shell/res/values-lo/strings.xml
index 4e10621..f3e7169 100644
--- a/libs/WindowManager/Shell/res/values-lo/strings.xml
+++ b/libs/WindowManager/Shell/res/values-lo/strings.xml
@@ -97,6 +97,9 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"ມີບັນຫາກ້ອງຖ່າຍຮູບບໍ?\nແຕະເພື່ອປັບໃໝ່"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"ບໍ່ໄດ້ແກ້ໄຂມັນບໍ?\nແຕະເພື່ອແປງກັບຄືນ"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"ບໍ່ມີບັນຫາກ້ອງຖ່າຍຮູບບໍ? ແຕະເພື່ອ​ປິດ​ໄວ້."</string>
+    <string name="windowing_app_handle_education_tooltip" msgid="6398482412956375783">"ແຕະເພື່ອເປີດເມນູແອັບ"</string>
+    <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="6285279585554484957">"ແຕະເພື່ອສະແດງແອັບຫຼາຍລາຍການພ້ອມກັນ"</string>
+    <string name="windowing_desktop_mode_exit_education_tooltip" msgid="6685429075790085337">"ກັບຄືນໄປຫາໂໝດເຕັມຈໍຈາກເມນູແອັບ"</string>
     <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"ເບິ່ງ ແລະ ເຮັດຫຼາຍຂຶ້ນ"</string>
     <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"ລາກໄປໄວ້ໃນແອັບອື່ນເພື່ອແບ່ງໜ້າຈໍ"</string>
     <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"ແຕະສອງເທື່ອໃສ່ນອກແອັບໃດໜຶ່ງເພື່ອຈັດຕຳແໜ່ງຂອງມັນຄືນໃໝ່"</string>
@@ -129,8 +132,13 @@
     <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"ເປີດເມນູ"</string>
     <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"ປັບຈໍໃຫຍ່ສຸດ"</string>
     <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"ສະແນັບໜ້າຈໍ"</string>
-    <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"ບໍ່ສາມາດປັບຂະໜາດແອັບນີ້ໄດ້"</string>
+    <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"ບໍ່ສາມາດຍ້າຍແອັບມາບ່ອນນີ້ໄດ້"</string>
     <string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"ຂະຫຍາຍໃຫຍ່ສຸດ"</string>
     <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"ແນບຊ້າຍ"</string>
     <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"ແນບຂວາ"</string>
+    <string name="open_by_default_settings_text" msgid="2526548548598185500">"ເປີດຕາມການຕັ້ງຄ່າເລີ່ມຕົ້ນ"</string>
+    <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"ເລືອກວິທີເປີດລິ້ງເວັບສຳລັບແອັບນີ້"</string>
+    <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"ໃນແອັບ"</string>
+    <string name="open_by_default_dialog_in_browser_text" msgid="8042769465958497081">"ໃນໂປຣແກຣມທ່ອງເວັບຂອງທ່ານ"</string>
+    <string name="open_by_default_dialog_dismiss_button_text" msgid="3487238795534582291">"ຕົກລົງ"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-lt/strings.xml b/libs/WindowManager/Shell/res/values-lt/strings.xml
index 6d3c58c..719cf60 100644
--- a/libs/WindowManager/Shell/res/values-lt/strings.xml
+++ b/libs/WindowManager/Shell/res/values-lt/strings.xml
@@ -97,6 +97,9 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Iškilo problemų dėl kameros?\nPalieskite, kad pritaikytumėte iš naujo"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Nepavyko pataisyti?\nPalieskite, kad grąžintumėte"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Nėra jokių problemų dėl kameros? Palieskite, kad atsisakytumėte."</string>
+    <string name="windowing_app_handle_education_tooltip" msgid="6398482412956375783">"Palieskite, kad atidarytumėte programos meniu"</string>
+    <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="6285279585554484957">"Palieskite, kad būtų rodomos kelios programos kartu"</string>
+    <string name="windowing_desktop_mode_exit_education_tooltip" msgid="6685429075790085337">"Grįžkite į viso ekrano režimą iš programos meniu"</string>
     <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Daugiau turinio ir funkcijų"</string>
     <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Vilkite kitoje programoje, kad galėtumėte naudoti išskaidyto ekrano režimą"</string>
     <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Dukart palieskite už programos ribų, kad pakeistumėte jos poziciją"</string>
@@ -129,8 +132,13 @@
     <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Atidaryti meniu"</string>
     <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Išskleisti ekraną"</string>
     <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Sutraukti ekraną"</string>
-    <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"Negalima keisti šios programos dydžio"</string>
+    <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Programos negalima perkelti čia"</string>
     <string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"Padidinti"</string>
     <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Pritraukti kairėje"</string>
     <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"Pritraukti dešinėje"</string>
+    <string name="open_by_default_settings_text" msgid="2526548548598185500">"Atidaryti pagal numatytuosius nustatymus"</string>
+    <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Pasirinkite, kaip atidaryti šios programos žiniatinklio nuorodas"</string>
+    <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"Programoje"</string>
+    <string name="open_by_default_dialog_in_browser_text" msgid="8042769465958497081">"Naršyklėje"</string>
+    <string name="open_by_default_dialog_dismiss_button_text" msgid="3487238795534582291">"Gerai"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-lv/strings.xml b/libs/WindowManager/Shell/res/values-lv/strings.xml
index 2f235ba..1649a2e 100644
--- a/libs/WindowManager/Shell/res/values-lv/strings.xml
+++ b/libs/WindowManager/Shell/res/values-lv/strings.xml
@@ -97,6 +97,9 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Vai ir problēmas ar kameru?\nPieskarieties, lai tās novērstu."</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Vai problēma netika novērsta?\nPieskarieties, lai atjaunotu."</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Vai nav problēmu ar kameru? Pieskarieties, lai nerādītu."</string>
+    <string name="windowing_app_handle_education_tooltip" msgid="6398482412956375783">"Lai atvērtu lietotnes izvēlni, pieskarieties."</string>
+    <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="6285279585554484957">"Lai parādītu vairākas lietotnes kopā, pieskarieties."</string>
+    <string name="windowing_desktop_mode_exit_education_tooltip" msgid="6685429075790085337">"Varat atgriezties pilnekrāna režīmā no lietotnes izvēlnes."</string>
     <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Uzziniet un paveiciet vairāk"</string>
     <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Lai izmantotu sadalītu ekrānu, ievelciet vēl vienu lietotni"</string>
     <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Lai pārvietotu lietotni, veiciet dubultskārienu ārpus lietotnes"</string>
@@ -126,15 +129,16 @@
     <string name="manage_windows_text" msgid="5567366688493093920">"Pārvaldīt logus"</string>
     <string name="close_text" msgid="4986518933445178928">"Aizvērt"</string>
     <string name="collapse_menu_text" msgid="7515008122450342029">"Aizvērt izvēlni"</string>
-    <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) -->
-    <skip />
+    <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Atvērt izvēlni"</string>
     <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maksimizēt ekrānu"</string>
     <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Fiksēt ekrānu"</string>
-    <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"Šīs lietotnes loga lielumu nevar mainīt."</string>
-    <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) -->
-    <skip />
-    <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) -->
-    <skip />
-    <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) -->
-    <skip />
+    <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Lietotni nevar pārvietot šeit."</string>
+    <string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"Maksimizēt"</string>
+    <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Piestiprināt pa kreisi"</string>
+    <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"Piestiprināt pa labi"</string>
+    <string name="open_by_default_settings_text" msgid="2526548548598185500">"Atvērt pēc noklusējuma iestatījumiem"</string>
+    <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Izvēlieties, kā atvērt šajā lietotnē norādītās saites"</string>
+    <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"Lietotnē"</string>
+    <string name="open_by_default_dialog_in_browser_text" msgid="8042769465958497081">"Pārlūkprogrammā"</string>
+    <string name="open_by_default_dialog_dismiss_button_text" msgid="3487238795534582291">"Labi"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-mk/strings.xml b/libs/WindowManager/Shell/res/values-mk/strings.xml
index e58d8fc..4922d04 100644
--- a/libs/WindowManager/Shell/res/values-mk/strings.xml
+++ b/libs/WindowManager/Shell/res/values-mk/strings.xml
@@ -97,6 +97,9 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Проблеми со камерата?\nДопрете за да се совпадне повторно"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Не се поправи?\nДопрете за враќање"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Нема проблеми со камерата? Допрете за отфрлање."</string>
+    <string name="windowing_app_handle_education_tooltip" msgid="6398482412956375783">"Допрете за да го отворите менито со апликации"</string>
+    <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="6285279585554484957">"Допрете за да се прикажат повеќе апликации заедно"</string>
+    <string name="windowing_desktop_mode_exit_education_tooltip" msgid="6685429075790085337">"Вратете се на цел екран од менито со апликации"</string>
     <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Погледнете и направете повеќе"</string>
     <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Повлечете друга апликација за поделен екран"</string>
     <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Допрете двапати надвор од некоја апликација за да ја преместите"</string>
@@ -126,15 +129,21 @@
     <string name="manage_windows_text" msgid="5567366688493093920">"Управувајте со прозорци"</string>
     <string name="close_text" msgid="4986518933445178928">"Затворете"</string>
     <string name="collapse_menu_text" msgid="7515008122450342029">"Затворете го менито"</string>
-    <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) -->
-    <skip />
+    <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Отвори го менито"</string>
     <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Максимизирај го екранот"</string>
     <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Подели го екранот на половина"</string>
-    <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"Не може да се промени големината на апликацијава"</string>
-    <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) -->
+    <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Апликацијата не може да се премести овде"</string>
+    <string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"Максимизирај"</string>
+    <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Фотографирај лево"</string>
+    <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"Фотографирај десно"</string>
+    <!-- no translation found for open_by_default_settings_text (2526548548598185500) -->
     <skip />
-    <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) -->
+    <!-- no translation found for open_by_default_dialog_subheader_text (1729599730664063881) -->
     <skip />
-    <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) -->
+    <!-- no translation found for open_by_default_dialog_in_app_text (6978022419634199806) -->
+    <skip />
+    <!-- no translation found for open_by_default_dialog_in_browser_text (8042769465958497081) -->
+    <skip />
+    <!-- no translation found for open_by_default_dialog_dismiss_button_text (3487238795534582291) -->
     <skip />
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-ml/strings.xml b/libs/WindowManager/Shell/res/values-ml/strings.xml
index a48df0b..4df5d6f 100644
--- a/libs/WindowManager/Shell/res/values-ml/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ml/strings.xml
@@ -97,6 +97,9 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"ക്യാമറ പ്രശ്നങ്ങളുണ്ടോ?\nശരിയാക്കാൻ ടാപ്പ് ചെയ്യുക"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"അത് പരിഹരിച്ചില്ലേ?\nപുനഃസ്ഥാപിക്കാൻ ടാപ്പ് ചെയ്യുക"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"ക്യാമറാ പ്രശ്നങ്ങളൊന്നുമില്ലേ? നിരസിക്കാൻ ടാപ്പ് ചെയ്യുക."</string>
+    <string name="windowing_app_handle_education_tooltip" msgid="6398482412956375783">"ആപ്പ് മെനു തുറക്കാൻ ടാപ്പ് ചെയ്യുക"</string>
+    <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="6285279585554484957">"ഒന്നിലധികം ആപ്പുകൾ ഒരുമിച്ച് കാണിക്കാൻ ടാപ്പ് ചെയ്യുക"</string>
+    <string name="windowing_desktop_mode_exit_education_tooltip" msgid="6685429075790085337">"ആപ്പ് മെനുവിൽ നിന്ന് പൂർണ്ണസ്‌ക്രീനിലേക്ക് മടങ്ങുക"</string>
     <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"കൂടുതൽ കാണുക, ചെയ്യുക"</string>
     <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"സ്‌ക്രീൻ വിഭജന മോഡിന്, മറ്റൊരു ആപ്പ് വലിച്ചിടുക"</string>
     <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"ആപ്പിന്റെ സ്ഥാനം മാറ്റാൻ അതിന് പുറത്ത് ഡബിൾ ടാപ്പ് ചെയ്യുക"</string>
@@ -129,8 +132,13 @@
     <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"മെനു തുറക്കുക"</string>
     <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"സ്‌ക്രീൻ വലുതാക്കുക"</string>
     <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"സ്‌ക്രീൻ സ്‌നാപ്പ് ചെയ്യുക"</string>
-    <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"ഈ ആപ്പിന്റെ വലുപ്പം മാറ്റാനാകില്ല"</string>
+    <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"ആപ്പ് ഇവിടേക്ക് നീക്കാനാകില്ല"</string>
     <string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"വലുതാക്കുക"</string>
     <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"ഇടതുവശത്തേക്ക് സ്‌നാപ്പ് ചെയ്യുക"</string>
     <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"വലതുവശത്തേക്ക് സ്‌നാപ്പ് ചെയ്യുക"</string>
+    <string name="open_by_default_settings_text" msgid="2526548548598185500">"ഡിഫോൾട്ട് ക്രമീകരണം ഉപയോഗിച്ച് തുറക്കുക"</string>
+    <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"ഈ ആപ്പിനായി വെബ് ലിങ്കുകൾ എങ്ങനെ തുറക്കണമെന്ന് തിരഞ്ഞെടുക്കൂ"</string>
+    <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"ആപ്പിൽ"</string>
+    <string name="open_by_default_dialog_in_browser_text" msgid="8042769465958497081">"നിങ്ങളുടെ ബ്രൗസറിൽ"</string>
+    <string name="open_by_default_dialog_dismiss_button_text" msgid="3487238795534582291">"ശരി"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-mn/strings.xml b/libs/WindowManager/Shell/res/values-mn/strings.xml
index f7e6a6c..70f6a08 100644
--- a/libs/WindowManager/Shell/res/values-mn/strings.xml
+++ b/libs/WindowManager/Shell/res/values-mn/strings.xml
@@ -97,6 +97,9 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Камерын асуудал гарсан уу?\nДахин тааруулахын тулд товшино уу"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Үүнийг засаагүй юу?\nБуцаахын тулд товшино уу"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Камерын асуудал байхгүй юу? Хаахын тулд товшино уу."</string>
+    <string name="windowing_app_handle_education_tooltip" msgid="6398482412956375783">"Аппын цэсийг нээхийн тулд товшино уу"</string>
+    <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="6285279585554484957">"Олон аппыг хамтад нь харуулахын тулд товшино уу"</string>
+    <string name="windowing_desktop_mode_exit_education_tooltip" msgid="6685429075790085337">"Аппын цэсээс бүтэн дэлгэц рүү буцна уу"</string>
     <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Харж илүү ихийг хий"</string>
     <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Дэлгэц хуваах горимд ашиглахын тулд өөр аппыг чирнэ үү"</string>
     <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Аппыг дахин байрлуулахын тулд гадна талд нь хоёр товшино"</string>
@@ -126,15 +129,16 @@
     <string name="manage_windows_text" msgid="5567366688493093920">"Windows-г удирдах"</string>
     <string name="close_text" msgid="4986518933445178928">"Хаах"</string>
     <string name="collapse_menu_text" msgid="7515008122450342029">"Цэсийг хаах"</string>
-    <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) -->
-    <skip />
+    <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Цэсийг нээх"</string>
     <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Дэлгэцийг томруулах"</string>
     <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Дэлгэцийг таллах"</string>
-    <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"Энэ аппын хэмжээг өөрчлөх боломжгүй"</string>
-    <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) -->
-    <skip />
-    <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) -->
-    <skip />
-    <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) -->
-    <skip />
+    <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Аппыг ийш зөөх боломжгүй"</string>
+    <string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"Томруулах"</string>
+    <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Зүүн тийш зэрэгцүүлэх"</string>
+    <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"Баруун тийш зэрэгцүүлэх"</string>
+    <string name="open_by_default_settings_text" msgid="2526548548598185500">"Өгөгдмөл тохиргоогоор нээх"</string>
+    <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Энэ аппад веб холбоосыг хэрхэн нээхийг сонгоно уу"</string>
+    <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"Аппад"</string>
+    <string name="open_by_default_dialog_in_browser_text" msgid="8042769465958497081">"Хөтчидөө"</string>
+    <string name="open_by_default_dialog_dismiss_button_text" msgid="3487238795534582291">"OK"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-mr/strings.xml b/libs/WindowManager/Shell/res/values-mr/strings.xml
index 4832284..e284486 100644
--- a/libs/WindowManager/Shell/res/values-mr/strings.xml
+++ b/libs/WindowManager/Shell/res/values-mr/strings.xml
@@ -97,6 +97,9 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"कॅमेराशी संबंधित काही समस्या आहेत का?\nपुन्हा फिट करण्यासाठी टॅप करा"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"निराकरण झाले नाही?\nरिव्हर्ट करण्यासाठी कृपया टॅप करा"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"कॅमेराशी संबंधित कोणत्याही समस्या नाहीत का? डिसमिस करण्‍यासाठी टॅप करा."</string>
+    <string name="windowing_app_handle_education_tooltip" msgid="6398482412956375783">"अ‍ॅप मेनू उघडण्यासाठी टॅप करा"</string>
+    <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="6285279585554484957">"एकाहून अधिक ॲप्स एकत्र दाखवण्यासाठी टॅप करा"</string>
+    <string name="windowing_desktop_mode_exit_education_tooltip" msgid="6685429075790085337">"ॲप मेनूमधून फुलस्क्रीनवर परत या"</string>
     <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"पहा आणि आणखी बरेच काही करा"</string>
     <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"स्प्लिट स्क्रीन वापरण्यासाठी दुसरे ॲप ड्रॅग करा"</string>
     <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"ॲपची स्थिती पुन्हा बदलण्यासाठी, त्याच्या बाहेर दोनदा टॅप करा"</string>
@@ -126,15 +129,16 @@
     <string name="manage_windows_text" msgid="5567366688493093920">"विंडो व्यवस्थापित करा"</string>
     <string name="close_text" msgid="4986518933445178928">"बंद करा"</string>
     <string name="collapse_menu_text" msgid="7515008122450342029">"मेनू बंद करा"</string>
-    <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) -->
-    <skip />
+    <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"मेनू उघडा"</string>
     <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"स्क्रीन मोठी करा"</string>
     <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"स्क्रीन स्नॅप करा"</string>
-    <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"या अ‍ॅपचा आकार बदलला जाऊ शकत नाही"</string>
-    <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) -->
-    <skip />
-    <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) -->
-    <skip />
-    <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) -->
-    <skip />
+    <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"अ‍ॅप इथे हलवू शकत नाही"</string>
+    <string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"मोठे करा"</string>
+    <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"डावीकडे स्नॅप करा"</string>
+    <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"उजवीकडे स्नॅप करा"</string>
+    <string name="open_by_default_settings_text" msgid="2526548548598185500">"बाय डीफॉल्ट सेटिंग्ज उघडा"</string>
+    <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"या अ‍ॅपसाठीच्या वेब लिंक कशा उघडाव्यात हे निवडा"</string>
+    <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"ॲपमध्ये"</string>
+    <string name="open_by_default_dialog_in_browser_text" msgid="8042769465958497081">"तुमच्या ब्राउझरमध्ये"</string>
+    <string name="open_by_default_dialog_dismiss_button_text" msgid="3487238795534582291">"ओके"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-ms/strings.xml b/libs/WindowManager/Shell/res/values-ms/strings.xml
index 15ccfbb..59032fb 100644
--- a/libs/WindowManager/Shell/res/values-ms/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ms/strings.xml
@@ -97,6 +97,9 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Isu kamera?\nKetik untuk memuatkan semula"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Isu tidak dibetulkan?\nKetik untuk kembali"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Tiada isu kamera? Ketik untuk mengetepikan."</string>
+    <string name="windowing_app_handle_education_tooltip" msgid="6398482412956375783">"Ketik untuk membuka menu apl"</string>
+    <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="6285279585554484957">"Ketik untuk memaparkan berbilang apl serentak"</string>
+    <string name="windowing_desktop_mode_exit_education_tooltip" msgid="6685429075790085337">"Kembali kepada skrin penuh daripada menu apl"</string>
     <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Lihat dan lakukan lebih"</string>
     <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Seret masuk apl lain untuk menggunakan skrin pisah"</string>
     <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Ketik dua kali di luar apl untuk menempatkan semula apl itu"</string>
@@ -129,8 +132,13 @@
     <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Buka Menu"</string>
     <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maksimumkan Skrin"</string>
     <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Tangkap Skrin"</string>
-    <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"Apl ini tidak boleh diubah saiz"</string>
+    <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Apl tidak boleh dialihkan ke sini"</string>
     <string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"Maksimumkan"</string>
     <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Autojajar ke kiri"</string>
     <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"Autojajar ke kanan"</string>
+    <string name="open_by_default_settings_text" msgid="2526548548598185500">"Buka tetapan secara lalai"</string>
+    <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Pilih cara membuka pautan web untuk apl ini"</string>
+    <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"Pada apl"</string>
+    <string name="open_by_default_dialog_in_browser_text" msgid="8042769465958497081">"Pada penyemak imbas"</string>
+    <string name="open_by_default_dialog_dismiss_button_text" msgid="3487238795534582291">"OK"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-my/strings.xml b/libs/WindowManager/Shell/res/values-my/strings.xml
index aac6f84..7b952c1 100644
--- a/libs/WindowManager/Shell/res/values-my/strings.xml
+++ b/libs/WindowManager/Shell/res/values-my/strings.xml
@@ -97,6 +97,9 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"ကင်မရာပြဿနာလား။\nပြင်ဆင်ရန် တို့ပါ"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"ကောင်းမသွားဘူးလား။\nပြန်ပြောင်းရန် တို့ပါ"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"ကင်မရာပြဿနာ မရှိဘူးလား။ ပယ်ရန် တို့ပါ။"</string>
+    <string name="windowing_app_handle_education_tooltip" msgid="6398482412956375783">"အက်ပ်မီနူးကိုဖွင့်ရန် တို့ပါ"</string>
+    <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="6285279585554484957">"အက်ပ်များစွာကို အတူတကွပြရန် တို့ပါ"</string>
+    <string name="windowing_desktop_mode_exit_education_tooltip" msgid="6685429075790085337">"အက်ပ်မီနူးမှ ဖန်သားပြင်အပြည့်သို့ ပြန်သွားပါ"</string>
     <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"ကြည့်ပြီး ပိုမိုလုပ်ဆောင်ပါ"</string>
     <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"မျက်နှာပြင် ခွဲ၍ပြသခြင်းအတွက် အက်ပ်နောက်တစ်ခုကို ဖိဆွဲပါ"</string>
     <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"နေရာပြန်ချရန် အက်ပ်အပြင်ဘက်ကို နှစ်ချက်တို့ပါ"</string>
@@ -126,15 +129,16 @@
     <string name="manage_windows_text" msgid="5567366688493093920">"ဝင်းဒိုးများ စီမံရန်"</string>
     <string name="close_text" msgid="4986518933445178928">"ပိတ်ရန်"</string>
     <string name="collapse_menu_text" msgid="7515008122450342029">"မီနူး ပိတ်ရန်"</string>
-    <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) -->
-    <skip />
+    <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"မီနူး ဖွင့်ရန်"</string>
     <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"စခရင်ကို ချဲ့မည်"</string>
     <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"စခရင်ကို ချုံ့မည်"</string>
-    <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"ဤအက်ပ်ကို အရွယ်ပြင်၍ မရပါ"</string>
-    <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) -->
-    <skip />
-    <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) -->
-    <skip />
-    <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) -->
-    <skip />
+    <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"အက်ပ်ကို ဤနေရာသို့ ရွှေ့၍မရပါ"</string>
+    <string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"ချဲ့ရန်"</string>
+    <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"ဘယ်တွင် ချဲ့ရန်"</string>
+    <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"ညာတွင် ချဲ့ရန်"</string>
+    <string name="open_by_default_settings_text" msgid="2526548548598185500">"မူရင်းဆက်တင်ဖြင့် ဖွင့်ရန်"</string>
+    <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"ဤအက်ပ်အတွက် ဝဘ်လင့်ခ်များ မည်သို့ဖွင့်မည်ကို ရွေးပါ"</string>
+    <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"အက်ပ်တွင်"</string>
+    <string name="open_by_default_dialog_in_browser_text" msgid="8042769465958497081">"သင်၏ဘရောင်ဇာတွင်"</string>
+    <string name="open_by_default_dialog_dismiss_button_text" msgid="3487238795534582291">"OK"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-nb/strings.xml b/libs/WindowManager/Shell/res/values-nb/strings.xml
index 175133d..8733a7f 100644
--- a/libs/WindowManager/Shell/res/values-nb/strings.xml
+++ b/libs/WindowManager/Shell/res/values-nb/strings.xml
@@ -97,6 +97,9 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Har du kameraproblemer?\nTrykk for å tilpasse"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Ble ikke problemet løst?\nTrykk for å gå tilbake"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Har du ingen kameraproblemer? Trykk for å lukke."</string>
+    <string name="windowing_app_handle_education_tooltip" msgid="6398482412956375783">"Trykk for å åpne appmenyen"</string>
+    <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="6285279585554484957">"Trykk for å vise flere apper sammen"</string>
+    <string name="windowing_desktop_mode_exit_education_tooltip" msgid="6685429075790085337">"Gå tilbake til fullskjerm fra appmenyen"</string>
     <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Se og gjør mer"</string>
     <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Dra inn en annen app for å bruke delt skjerm"</string>
     <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Dobbelttrykk utenfor en app for å flytte den"</string>
@@ -126,15 +129,16 @@
     <string name="manage_windows_text" msgid="5567366688493093920">"Administrer vinduene"</string>
     <string name="close_text" msgid="4986518933445178928">"Lukk"</string>
     <string name="collapse_menu_text" msgid="7515008122450342029">"Lukk menyen"</string>
-    <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) -->
-    <skip />
+    <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Åpne menyen"</string>
     <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maksimer skjermen"</string>
     <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Fest skjermen"</string>
-    <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"Du kan ikke endre størrelse på denne appen"</string>
-    <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) -->
-    <skip />
-    <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) -->
-    <skip />
-    <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) -->
-    <skip />
+    <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Appen kan ikke flyttes hit"</string>
+    <string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"Maksimer"</string>
+    <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Fest til venstre"</string>
+    <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"Fest til høyre"</string>
+    <string name="open_by_default_settings_text" msgid="2526548548598185500">"Innstillinger for åpning som standard"</string>
+    <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Velg hvordan nettlinker skal åpnes for denne appen"</string>
+    <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"I appen"</string>
+    <string name="open_by_default_dialog_in_browser_text" msgid="8042769465958497081">"I nettleseren"</string>
+    <string name="open_by_default_dialog_dismiss_button_text" msgid="3487238795534582291">"OK"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-ne/strings.xml b/libs/WindowManager/Shell/res/values-ne/strings.xml
index d3a7e12..cdd2a1f 100644
--- a/libs/WindowManager/Shell/res/values-ne/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ne/strings.xml
@@ -97,6 +97,9 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"क्यामेरासम्बन्धी समस्या देखियो?\nसमस्या हल गर्न ट्याप गर्नुहोस्"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"समस्या हल भएन?\nपहिलेको जस्तै बनाउन ट्याप गर्नुहोस्"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"क्यामेरासम्बन्धी कुनै पनि समस्या छैन? खारेज गर्न ट्याप गर्नुहोस्।"</string>
+    <string name="windowing_app_handle_education_tooltip" msgid="6398482412956375783">"एपको मेनु खोल्न ट्याप गर्नुहोस्"</string>
+    <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="6285279585554484957">"एकभन्दा बढी एपहरू सँगै देखाउन ट्याप गर्नुहोस्"</string>
+    <string name="windowing_desktop_mode_exit_education_tooltip" msgid="6685429075790085337">"एपको मेनुबाट फुल स्क्रिनमा फर्कनुहोस्"</string>
     <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"थप कुरा हेर्नुहोस् र गर्नुहोस्"</string>
     <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"स्प्लिट स्क्रिन मोड प्रयोग गर्न अर्को एप ड्रयाग एन्ड ड्रप गर्नुहोस्"</string>
     <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"तपाईं जुन एपको स्थिति मिलाउन चाहनुहुन्छ सोही एपको बाहिर डबल ट्याप गर्नुहोस्"</string>
@@ -126,15 +129,16 @@
     <string name="manage_windows_text" msgid="5567366688493093920">"विन्डोहरू व्यवस्थापन गर्नुहोस्"</string>
     <string name="close_text" msgid="4986518933445178928">"बन्द गर्नुहोस्"</string>
     <string name="collapse_menu_text" msgid="7515008122450342029">"मेनु बन्द गर्नुहोस्"</string>
-    <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) -->
-    <skip />
+    <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"मेनु खोल्नुहोस्"</string>
     <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"स्क्रिन ठुलो बनाउनुहोस्"</string>
     <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"स्क्रिन स्न्याप गर्नुहोस्"</string>
-    <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"यो एपको आकार बदल्न मिल्दैन"</string>
-    <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) -->
-    <skip />
-    <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) -->
-    <skip />
-    <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) -->
-    <skip />
+    <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"एप सारेर यहाँ ल्याउन सकिएन"</string>
+    <string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"ठुलो बनाउनुहोस्"</string>
+    <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"बायाँतिर स्न्याप गर्नुहोस्"</string>
+    <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"दायाँतिर स्न्याप गर्नुहोस्"</string>
+    <string name="open_by_default_settings_text" msgid="2526548548598185500">"डिफल्ट सेटिङअनुसार खोल्नुहोस्"</string>
+    <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"यो एपका वेब लिंकहरू खोल्ने तरिका छनौट गर्नुहोस्"</string>
+    <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"एपमा"</string>
+    <string name="open_by_default_dialog_in_browser_text" msgid="8042769465958497081">"तपाईंको ब्राउजरमा"</string>
+    <string name="open_by_default_dialog_dismiss_button_text" msgid="3487238795534582291">"ठिक छ"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-nl/strings.xml b/libs/WindowManager/Shell/res/values-nl/strings.xml
index 747afe3..d8a2856 100644
--- a/libs/WindowManager/Shell/res/values-nl/strings.xml
+++ b/libs/WindowManager/Shell/res/values-nl/strings.xml
@@ -97,6 +97,9 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Cameraproblemen?\nTik om opnieuw passend te maken."</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Is dit geen oplossing?\nTik om terug te zetten."</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Geen cameraproblemen? Tik om te sluiten."</string>
+    <string name="windowing_app_handle_education_tooltip" msgid="6398482412956375783">"Tik om het app-menu te openen"</string>
+    <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="6285279585554484957">"Tik om meerdere apps tegelijk te tonen"</string>
+    <string name="windowing_desktop_mode_exit_education_tooltip" msgid="6685429075790085337">"Terug naar volledig scherm vanuit het app-menu"</string>
     <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Zie en doe meer"</string>
     <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Sleep een andere app hier naartoe om het scherm te splitsen"</string>
     <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Dubbeltik naast een app om deze opnieuw te positioneren"</string>
@@ -126,15 +129,16 @@
     <string name="manage_windows_text" msgid="5567366688493093920">"Vensters beheren"</string>
     <string name="close_text" msgid="4986518933445178928">"Sluiten"</string>
     <string name="collapse_menu_text" msgid="7515008122450342029">"Menu sluiten"</string>
-    <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) -->
-    <skip />
+    <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Menu openen"</string>
     <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Scherm maximaliseren"</string>
     <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Scherm halveren"</string>
-    <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"Het formaat van deze app kan niet worden aangepast"</string>
-    <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) -->
-    <skip />
-    <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) -->
-    <skip />
-    <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) -->
-    <skip />
+    <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Kan de app niet hierheen verplaatsen"</string>
+    <string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"Maximaliseren"</string>
+    <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Links uitlijnen"</string>
+    <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"Rechts uitlijnen"</string>
+    <string name="open_by_default_settings_text" msgid="2526548548598185500">"Instellingen voor Standaard openen"</string>
+    <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Kies hoe je weblinks voor deze app wilt openen"</string>
+    <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"In de app"</string>
+    <string name="open_by_default_dialog_in_browser_text" msgid="8042769465958497081">"In je browser"</string>
+    <string name="open_by_default_dialog_dismiss_button_text" msgid="3487238795534582291">"OK"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-or/strings.xml b/libs/WindowManager/Shell/res/values-or/strings.xml
index a5adcbe..baf009e 100644
--- a/libs/WindowManager/Shell/res/values-or/strings.xml
+++ b/libs/WindowManager/Shell/res/values-or/strings.xml
@@ -97,6 +97,9 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"କ୍ୟାମେରାରେ ସମସ୍ୟା ଅଛି?\nପୁଣି ଫିଟ କରିବାକୁ ଟାପ କରନ୍ତୁ"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"ଏହାର ସମାଧାନ ହୋଇନାହିଁ?\nଫେରିଯିବା ପାଇଁ ଟାପ କରନ୍ତୁ"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"କ୍ୟାମେରାରେ କିଛି ସମସ୍ୟା ନାହିଁ? ଖାରଜ କରିବାକୁ ଟାପ କରନ୍ତୁ।"</string>
+    <string name="windowing_app_handle_education_tooltip" msgid="6398482412956375783">"ଆପ ମେନୁ ଖୋଲିବାକୁ ଟାପ କରନ୍ତୁ"</string>
+    <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="6285279585554484957">"ଏକାଠି ଏକାଧିକ ଆପ୍ସ ଦେଖାଇବା ପାଇଁ ଟାପ କରନ୍ତୁ"</string>
+    <string name="windowing_desktop_mode_exit_education_tooltip" msgid="6685429075790085337">"ଆପ ମେନୁରୁ ପୂର୍ଣ୍ଣସ୍କ୍ରିନକୁ ଫେରନ୍ତୁ"</string>
     <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"ଦେଖନ୍ତୁ ଏବଂ ଆହୁରି ଅନେକ କିଛି କରନ୍ତୁ"</string>
     <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"ସ୍ପ୍ଲିଟ ସ୍କ୍ରିନ ପାଇଁ ଅନ୍ୟ ଏକ ଆପକୁ ଡ୍ରାଗ କରନ୍ତୁ"</string>
     <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"ଏକ ଆପକୁ ରିପୋଜିସନ କରିବା ପାଇଁ ଏହାର ବାହାରେ ଦୁଇଥର-ଟାପ କରନ୍ତୁ"</string>
@@ -126,15 +129,21 @@
     <string name="manage_windows_text" msgid="5567366688493093920">"ୱିଣ୍ଡୋଗୁଡ଼ିକୁ ପରିଚାଳନା କରନ୍ତୁ"</string>
     <string name="close_text" msgid="4986518933445178928">"ବନ୍ଦ କରନ୍ତୁ"</string>
     <string name="collapse_menu_text" msgid="7515008122450342029">"ମେନୁ ବନ୍ଦ କରନ୍ତୁ"</string>
-    <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) -->
-    <skip />
+    <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"ମେନୁ ଖୋଲନ୍ତୁ"</string>
     <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"ସ୍କ୍ରିନକୁ ବଡ଼ କରନ୍ତୁ"</string>
     <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"ସ୍କ୍ରିନକୁ ସ୍ନାପ କରନ୍ତୁ"</string>
-    <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"ଏହି ଆପକୁ ରିସାଇଜ କରାଯାଇପାରିବ ନାହିଁ"</string>
-    <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) -->
+    <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"ଆପକୁ ଏଠାକୁ ମୁଭ କରାଯାଇପାରିବ ନାହିଁ"</string>
+    <string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"ବଡ଼ କରନ୍ତୁ"</string>
+    <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"ବାମରେ ସ୍ନାପ କରନ୍ତୁ"</string>
+    <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"ଡାହାଣରେ ସ୍ନାପ କରନ୍ତୁ"</string>
+    <!-- no translation found for open_by_default_settings_text (2526548548598185500) -->
     <skip />
-    <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) -->
+    <!-- no translation found for open_by_default_dialog_subheader_text (1729599730664063881) -->
     <skip />
-    <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) -->
+    <!-- no translation found for open_by_default_dialog_in_app_text (6978022419634199806) -->
+    <skip />
+    <!-- no translation found for open_by_default_dialog_in_browser_text (8042769465958497081) -->
+    <skip />
+    <!-- no translation found for open_by_default_dialog_dismiss_button_text (3487238795534582291) -->
     <skip />
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-pa/strings.xml b/libs/WindowManager/Shell/res/values-pa/strings.xml
index e11cc1c..06e1f54 100644
--- a/libs/WindowManager/Shell/res/values-pa/strings.xml
+++ b/libs/WindowManager/Shell/res/values-pa/strings.xml
@@ -97,6 +97,9 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"ਕੀ ਕੈਮਰੇ ਸੰਬੰਧੀ ਸਮੱਸਿਆਵਾਂ ਹਨ?\nਮੁੜ-ਫਿੱਟ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"ਕੀ ਇਹ ਠੀਕ ਨਹੀਂ ਹੋਈ?\nਵਾਪਸ ਉਹੀ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"ਕੀ ਕੈਮਰੇ ਸੰਬੰਧੀ ਕੋਈ ਸਮੱਸਿਆ ਨਹੀਂ ਹੈ? ਖਾਰਜ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ।"</string>
+    <string name="windowing_app_handle_education_tooltip" msgid="6398482412956375783">"ਐਪ ਮੀਨੂ ਨੂੰ ਖੋਲ੍ਹਣ ਲਈ ਟੈਪ ਕਰੋ"</string>
+    <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="6285279585554484957">"ਕਈ ਐਪਾਂ ਇਕੱਠੀਆਂ ਦਿਖਾਉਣ ਲਈ ਟੈਪ ਕਰੋ"</string>
+    <string name="windowing_desktop_mode_exit_education_tooltip" msgid="6685429075790085337">"ਐਪ ਮੀਨੂ ਤੋਂ ਪੂਰੀ-ਸਕ੍ਰੀਨ ਮੋਡ \'ਤੇ ਵਾਪਸ ਜਾਓ"</string>
     <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"ਦੇਖੋ ਅਤੇ ਹੋਰ ਬਹੁਤ ਕੁਝ ਕਰੋ"</string>
     <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"ਸਪਲਿਟ ਸਕ੍ਰੀਨ ਦੇ ਲਈ ਕਿਸੇ ਹੋਰ ਐਪ ਵਿੱਚ ਘਸੀਟੋ"</string>
     <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"ਕਿਸੇ ਐਪ ਦੀ ਜਗ੍ਹਾ ਬਦਲਣ ਲਈ ਉਸ ਦੇ ਬਾਹਰ ਡਬਲ ਟੈਪ ਕਰੋ"</string>
@@ -129,8 +132,13 @@
     <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"ਮੀਨੂ ਖੋਲ੍ਹੋ"</string>
     <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"ਸਕ੍ਰੀਨ ਦਾ ਆਕਾਰ ਵਧਾਓ"</string>
     <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"ਸਕ੍ਰੀਨ ਨੂੰ ਸਨੈਪ ਕਰੋ"</string>
-    <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"ਇਸ ਐਪ ਦਾ ਆਕਾਰ ਬਦਲਿਆ ਨਹੀਂ ਜਾ ਸਕਦਾ"</string>
+    <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"ਐਪ ਨੂੰ ਇੱਥੇ ਨਹੀਂ ਲਿਜਾਇਆ ਜਾ ਸਕਦਾ"</string>
     <string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"ਵੱਡਾ ਕਰੋ"</string>
     <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"ਖੱਬੇ ਪਾਸੇ ਸਨੈਪ ਕਰੋ"</string>
     <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"ਸੱਜੇ ਪਾਸੇ ਸਨੈਪ ਕਰੋ"</string>
+    <string name="open_by_default_settings_text" msgid="2526548548598185500">"ਪੂਰਵ-ਨਿਰਧਾਰਿਤ ਸੈਟਿੰਗਾਂ ਮੁਤਾਬਕ ਖੋਲ੍ਹੋ"</string>
+    <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"ਇਸ ਐਪ ਲਈ ਵੈੱਬ ਲਿੰਕਾਂ ਨੂੰ ਖੋਲ੍ਹਣ ਦਾ ਤਰੀਕਾ ਚੁਣੋ"</string>
+    <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"ਐਪ ਵਿੱਚ"</string>
+    <string name="open_by_default_dialog_in_browser_text" msgid="8042769465958497081">"ਤੁਹਾਡੇ ਬ੍ਰਾਊਜ਼ਰ ਵਿੱਚ"</string>
+    <string name="open_by_default_dialog_dismiss_button_text" msgid="3487238795534582291">"ਠੀਕ ਹੈ"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-pl/strings.xml b/libs/WindowManager/Shell/res/values-pl/strings.xml
index 2640c0f..90d374c 100644
--- a/libs/WindowManager/Shell/res/values-pl/strings.xml
+++ b/libs/WindowManager/Shell/res/values-pl/strings.xml
@@ -97,6 +97,9 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Problemy z aparatem?\nKliknij, aby dopasować"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Naprawa się nie udała?\nKliknij, aby cofnąć"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Brak problemów z aparatem? Kliknij, aby zamknąć"</string>
+    <string name="windowing_app_handle_education_tooltip" msgid="6398482412956375783">"Kliknij, aby otworzyć menu aplikacji"</string>
+    <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="6285279585554484957">"Kliknij, aby wyświetlić jednocześnie kilka aplikacji"</string>
+    <string name="windowing_desktop_mode_exit_education_tooltip" msgid="6685429075790085337">"Wróć do trybu pełnoekranowego z menu aplikacji"</string>
     <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Zobacz i zrób więcej"</string>
     <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Aby podzielić ekran, przeciągnij drugą aplikację"</string>
     <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Kliknij dwukrotnie poza aplikacją, aby ją przenieść"</string>
@@ -129,8 +132,13 @@
     <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Otwórz menu"</string>
     <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maksymalizuj ekran"</string>
     <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Przyciągnij ekran"</string>
-    <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"Nie można zmienić rozmiaru tej aplikacji"</string>
+    <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Nie można przenieść aplikacji tutaj"</string>
     <string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"Maksymalizuj"</string>
     <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Przyciągnij do lewej"</string>
     <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"Przyciągnij do prawej"</string>
+    <string name="open_by_default_settings_text" msgid="2526548548598185500">"Ustawienia domyślnego otwierania"</string>
+    <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Wybierz, gdzie chcesz otwierać linki z tej aplikacji"</string>
+    <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"W aplikacji"</string>
+    <string name="open_by_default_dialog_in_browser_text" msgid="8042769465958497081">"W przeglądarce"</string>
+    <string name="open_by_default_dialog_dismiss_button_text" msgid="3487238795534582291">"OK"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-pt-rBR/strings.xml b/libs/WindowManager/Shell/res/values-pt-rBR/strings.xml
index 18048ff..a7cf9d8 100644
--- a/libs/WindowManager/Shell/res/values-pt-rBR/strings.xml
+++ b/libs/WindowManager/Shell/res/values-pt-rBR/strings.xml
@@ -97,12 +97,9 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Problemas com a câmera?\nToque para ajustar o enquadramento"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"O problema não foi corrigido?\nToque para reverter"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Não tem problemas com a câmera? Toque para dispensar."</string>
-    <!-- no translation found for windowing_app_handle_education_tooltip (6398482412956375783) -->
-    <skip />
-    <!-- no translation found for windowing_desktop_mode_image_button_education_tooltip (6285279585554484957) -->
-    <skip />
-    <!-- no translation found for windowing_desktop_mode_exit_education_tooltip (6685429075790085337) -->
-    <skip />
+    <string name="windowing_app_handle_education_tooltip" msgid="6398482412956375783">"Toque para abrir o menu do app"</string>
+    <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="6285279585554484957">"Toque para mostrar vários apps juntos"</string>
+    <string name="windowing_desktop_mode_exit_education_tooltip" msgid="6685429075790085337">"Volte para a tela cheia no menu do app"</string>
     <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Veja e faça mais"</string>
     <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Arraste outro app para dividir a tela"</string>
     <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Toque duas vezes fora de um app para reposicionar"</string>
@@ -135,9 +132,13 @@
     <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Abrir o menu"</string>
     <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Ampliar tela"</string>
     <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Ajustar tela"</string>
-    <!-- no translation found for desktop_mode_non_resizable_snap_text (3771776422751387878) -->
-    <skip />
+    <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Não é possível mover o app para cá"</string>
     <string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"Maximizar"</string>
     <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Ajustar à esquerda"</string>
     <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"Ajustar à direita"</string>
+    <string name="open_by_default_settings_text" msgid="2526548548598185500">"Configurações \"Abrir por padrão\""</string>
+    <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Escolha como abrir links da Web para este app"</string>
+    <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"No app"</string>
+    <string name="open_by_default_dialog_in_browser_text" msgid="8042769465958497081">"No navegador"</string>
+    <string name="open_by_default_dialog_dismiss_button_text" msgid="3487238795534582291">"OK"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-pt-rPT/strings.xml b/libs/WindowManager/Shell/res/values-pt-rPT/strings.xml
index 46f8b38..40241b4 100644
--- a/libs/WindowManager/Shell/res/values-pt-rPT/strings.xml
+++ b/libs/WindowManager/Shell/res/values-pt-rPT/strings.xml
@@ -97,6 +97,9 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Problemas com a câmara?\nToque aqui para reajustar"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Não foi corrigido?\nToque para reverter"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Nenhum problema com a câmara? Toque para ignorar."</string>
+    <string name="windowing_app_handle_education_tooltip" msgid="6398482412956375783">"Toque para abrir o menu de apps"</string>
+    <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="6285279585554484957">"Toque para mostrar várias apps em conjunto"</string>
+    <string name="windowing_desktop_mode_exit_education_tooltip" msgid="6685429075790085337">"Regresse ao ecrã inteiro a partir do menu de apps"</string>
     <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Veja e faça mais"</string>
     <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Arraste outra app para usar o ecrã dividido"</string>
     <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Toque duas vezes fora de uma app para a reposicionar"</string>
@@ -129,8 +132,13 @@
     <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Abrir menu"</string>
     <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maximizar ecrã"</string>
     <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Encaixar ecrã"</string>
-    <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"Não é possível redimensionar esta app"</string>
+    <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Não é possível mover a app para aqui"</string>
     <string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"Maximizar"</string>
     <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Encaixar à esquerda"</string>
     <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"Encaixar à direita"</string>
+    <string name="open_by_default_settings_text" msgid="2526548548598185500">"Definições de Abrir por predefinição"</string>
+    <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Escolha como abrir links da Web para esta app"</string>
+    <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"Na app"</string>
+    <string name="open_by_default_dialog_in_browser_text" msgid="8042769465958497081">"No navegador"</string>
+    <string name="open_by_default_dialog_dismiss_button_text" msgid="3487238795534582291">"OK"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-pt/strings.xml b/libs/WindowManager/Shell/res/values-pt/strings.xml
index 75c445c..a7cf9d8 100644
--- a/libs/WindowManager/Shell/res/values-pt/strings.xml
+++ b/libs/WindowManager/Shell/res/values-pt/strings.xml
@@ -97,6 +97,9 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Problemas com a câmera?\nToque para ajustar o enquadramento"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"O problema não foi corrigido?\nToque para reverter"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Não tem problemas com a câmera? Toque para dispensar."</string>
+    <string name="windowing_app_handle_education_tooltip" msgid="6398482412956375783">"Toque para abrir o menu do app"</string>
+    <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="6285279585554484957">"Toque para mostrar vários apps juntos"</string>
+    <string name="windowing_desktop_mode_exit_education_tooltip" msgid="6685429075790085337">"Volte para a tela cheia no menu do app"</string>
     <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Veja e faça mais"</string>
     <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Arraste outro app para dividir a tela"</string>
     <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Toque duas vezes fora de um app para reposicionar"</string>
@@ -126,15 +129,16 @@
     <string name="manage_windows_text" msgid="5567366688493093920">"Gerenciar janelas"</string>
     <string name="close_text" msgid="4986518933445178928">"Fechar"</string>
     <string name="collapse_menu_text" msgid="7515008122450342029">"Fechar menu"</string>
-    <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) -->
-    <skip />
+    <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Abrir o menu"</string>
     <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Ampliar tela"</string>
     <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Ajustar tela"</string>
-    <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"Não é possível redimensionar o app"</string>
-    <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) -->
-    <skip />
-    <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) -->
-    <skip />
-    <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) -->
-    <skip />
+    <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Não é possível mover o app para cá"</string>
+    <string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"Maximizar"</string>
+    <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Ajustar à esquerda"</string>
+    <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"Ajustar à direita"</string>
+    <string name="open_by_default_settings_text" msgid="2526548548598185500">"Configurações \"Abrir por padrão\""</string>
+    <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Escolha como abrir links da Web para este app"</string>
+    <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"No app"</string>
+    <string name="open_by_default_dialog_in_browser_text" msgid="8042769465958497081">"No navegador"</string>
+    <string name="open_by_default_dialog_dismiss_button_text" msgid="3487238795534582291">"OK"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-ro/strings.xml b/libs/WindowManager/Shell/res/values-ro/strings.xml
index 3c763ea..f323ff8 100644
--- a/libs/WindowManager/Shell/res/values-ro/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ro/strings.xml
@@ -97,6 +97,9 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Ai probleme cu camera foto?\nAtinge pentru a reîncadra"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Nu ai remediat problema?\nAtinge pentru a reveni"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Nu ai probleme cu camera foto? Atinge pentru a închide."</string>
+    <string name="windowing_app_handle_education_tooltip" msgid="6398482412956375783">"Atinge pentru a deschide meniul aplicației"</string>
+    <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="6285279585554484957">"Atinge pentru a afișa mai multe aplicații împreună"</string>
+    <string name="windowing_desktop_mode_exit_education_tooltip" msgid="6685429075790085337">"Revino la ecranul complet din meniul aplicației"</string>
     <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Vezi și fă mai multe"</string>
     <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Trage în altă aplicație pentru a folosi ecranul împărțit"</string>
     <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Atinge de două ori lângă o aplicație pentru a o repoziționa"</string>
@@ -126,15 +129,16 @@
     <string name="manage_windows_text" msgid="5567366688493093920">"Gestionează ferestrele"</string>
     <string name="close_text" msgid="4986518933445178928">"Închide"</string>
     <string name="collapse_menu_text" msgid="7515008122450342029">"Închide meniul"</string>
-    <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) -->
-    <skip />
+    <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Deschide meniul"</string>
     <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maximizează fereastra"</string>
     <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Micșorează fereastra și fixeaz-o"</string>
-    <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"Aplicația nu poate fi redimensionată"</string>
-    <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) -->
-    <skip />
-    <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) -->
-    <skip />
-    <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) -->
-    <skip />
+    <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Aplicația nu poate fi mutată aici"</string>
+    <string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"Maximizează"</string>
+    <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Trage la stânga"</string>
+    <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"Trage la dreapta"</string>
+    <string name="open_by_default_settings_text" msgid="2526548548598185500">"Setări de deschidere în mod prestabilit"</string>
+    <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Alege modul de deschidere a linkurilor web pentru aplicație"</string>
+    <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"În aplicație"</string>
+    <string name="open_by_default_dialog_in_browser_text" msgid="8042769465958497081">"În browser"</string>
+    <string name="open_by_default_dialog_dismiss_button_text" msgid="3487238795534582291">"OK"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-ru/strings.xml b/libs/WindowManager/Shell/res/values-ru/strings.xml
index affd0cb..45da723 100644
--- a/libs/WindowManager/Shell/res/values-ru/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ru/strings.xml
@@ -97,6 +97,9 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Проблемы с камерой?\nНажмите, чтобы исправить."</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Не помогло?\nНажмите, чтобы отменить изменения."</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Нет проблем с камерой? Нажмите, чтобы закрыть."</string>
+    <string name="windowing_app_handle_education_tooltip" msgid="6398482412956375783">"Нажмите, чтобы открыть меню приложения"</string>
+    <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="6285279585554484957">"Нажмите, чтобы на экране размещались сразу несколько приложений"</string>
+    <string name="windowing_desktop_mode_exit_education_tooltip" msgid="6685429075790085337">"Вернуться из меню приложения в режим полного экрана"</string>
     <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Выполняйте несколько задач одновременно"</string>
     <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Перетащите сюда другое приложение, чтобы использовать разделение экрана."</string>
     <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Чтобы переместить приложение, дважды нажмите рядом с ним."</string>
@@ -129,8 +132,13 @@
     <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Открыть меню"</string>
     <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Развернуть на весь экран"</string>
     <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Свернуть"</string>
-    <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"Изменить размер приложения нельзя."</string>
+    <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Приложение нельзя сюда переместить"</string>
     <string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"Развернуть"</string>
     <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Привязать слева"</string>
     <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"Привязать справа"</string>
+    <string name="open_by_default_settings_text" msgid="2526548548598185500">"Настройки, регулирующие, как по умолчанию открываются ссылки"</string>
+    <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Выберите, где будут открываться ссылки из этого приложения"</string>
+    <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"В приложении"</string>
+    <string name="open_by_default_dialog_in_browser_text" msgid="8042769465958497081">"В браузере"</string>
+    <string name="open_by_default_dialog_dismiss_button_text" msgid="3487238795534582291">"ОК"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-si/strings.xml b/libs/WindowManager/Shell/res/values-si/strings.xml
index ed76269..0b1a239 100644
--- a/libs/WindowManager/Shell/res/values-si/strings.xml
+++ b/libs/WindowManager/Shell/res/values-si/strings.xml
@@ -97,6 +97,9 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"කැමරා ගැටලුද?\nයළි සවි කිරීමට තට්ටු කරන්න"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"එය විසඳුවේ නැතිද?\nප්‍රතිවර්තනය කිරීමට තට්ටු කරන්න"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"කැමරා ගැටලු නොමැතිද? ඉවත දැමීමට තට්ටු කරන්න"</string>
+    <string name="windowing_app_handle_education_tooltip" msgid="6398482412956375783">"යෙදුම් මෙනුව විවෘත කිරීමට තට්ටු කරන්න"</string>
+    <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="6285279585554484957">"යෙදුම් කිහිපයක් එකට පෙන්වීමට තට්ටු කරන්න"</string>
+    <string name="windowing_desktop_mode_exit_education_tooltip" msgid="6685429075790085337">"යෙදුම් මෙනුවෙන් පූර්ණ තිරය වෙත ආපසු යන්න"</string>
     <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"බලන්න සහ තවත් දේ කරන්න"</string>
     <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"බෙදුම් තිරය සඳහා වෙනත් යෙදුමකට අදින්න"</string>
     <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"යෙදුමක් නැවත ස්ථානගත කිරීමට පිටතින් දෙවරක් තට්ටු කරන්න"</string>
@@ -126,15 +129,16 @@
     <string name="manage_windows_text" msgid="5567366688493093920">"කවුළු කළමනාකරණය කරන්න"</string>
     <string name="close_text" msgid="4986518933445178928">"වසන්න"</string>
     <string name="collapse_menu_text" msgid="7515008122450342029">"මෙනුව වසන්න"</string>
-    <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) -->
-    <skip />
+    <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"මෙනුව විවෘත කරන්න"</string>
     <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"තිරය උපරිම කරන්න"</string>
     <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"ස්නැප් තිරය"</string>
-    <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"මෙම යෙදුම ප්‍රතිප්‍රමාණ කළ නොහැක"</string>
-    <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) -->
-    <skip />
-    <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) -->
-    <skip />
-    <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) -->
-    <skip />
+    <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"යෙදුම මෙතැනට ගෙන යා නොහැක"</string>
+    <string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"විහිදන්න"</string>
+    <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"වමට ස්නැප් කරන්න"</string>
+    <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"දකුණට ස්නැප් කරන්න"</string>
+    <string name="open_by_default_settings_text" msgid="2526548548598185500">"පෙරනිමි සැකසීම් මඟින් විවෘත කරන්න"</string>
+    <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"මෙම යෙදුම සඳහා වෙබ් සබැඳි විවෘත කරන ආකාරය තෝරා ගන්න"</string>
+    <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"යෙදුම තුළ"</string>
+    <string name="open_by_default_dialog_in_browser_text" msgid="8042769465958497081">"ඔබේ බ්‍රව්සරය තුළ"</string>
+    <string name="open_by_default_dialog_dismiss_button_text" msgid="3487238795534582291">"හරි"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-sk/strings.xml b/libs/WindowManager/Shell/res/values-sk/strings.xml
index 529a693..7d1a408 100644
--- a/libs/WindowManager/Shell/res/values-sk/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sk/strings.xml
@@ -97,6 +97,9 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Problémy s kamerou?\nKlepnutím znova upravte."</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Nevyriešilo sa to?\nKlepnutím sa vráťte."</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Nemáte problémy s kamerou? Klepnutím zatvoríte."</string>
+    <string name="windowing_app_handle_education_tooltip" msgid="6398482412956375783">"Klepnúť a otvoriť tak ponuku aplikácií"</string>
+    <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="6285279585554484957">"Klepnúť a zobraziť tak viacero aplikácií naraz"</string>
+    <string name="windowing_desktop_mode_exit_education_tooltip" msgid="6685429075790085337">"Prejsť späť na celú obrazovku z ponuky aplikácií"</string>
     <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Zobrazte si a zvládnite toho viac"</string>
     <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Rozdelenú obrazovku môžete použiť presunutím do inej aplikácie"</string>
     <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Dvojitým klepnutím mimo aplikácie zmeníte jej pozíciu"</string>
@@ -126,15 +129,16 @@
     <string name="manage_windows_text" msgid="5567366688493093920">"Správa okien"</string>
     <string name="close_text" msgid="4986518933445178928">"Zavrieť"</string>
     <string name="collapse_menu_text" msgid="7515008122450342029">"Zavrieť ponuku"</string>
-    <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) -->
-    <skip />
+    <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Otvoriť ponuku"</string>
     <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maximalizovať obrazovku"</string>
     <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Zobraziť polovicu obrazovky"</string>
-    <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"Veľkosť tejto aplikácie sa nedá zmeniť"</string>
-    <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) -->
-    <skip />
-    <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) -->
-    <skip />
-    <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) -->
-    <skip />
+    <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Aplikácia sa sem nedá presunúť"</string>
+    <string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"Maximalizovať"</string>
+    <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Prichytiť vľavo"</string>
+    <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"Prichytiť vpravo"</string>
+    <string name="open_by_default_settings_text" msgid="2526548548598185500">"Otvárať podľa predvolených nastavení"</string>
+    <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Vyberte, ako sa majú v tejto aplikácii otvárať webové odkazy"</string>
+    <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"V aplikácii"</string>
+    <string name="open_by_default_dialog_in_browser_text" msgid="8042769465958497081">"V prehliadači"</string>
+    <string name="open_by_default_dialog_dismiss_button_text" msgid="3487238795534582291">"OK"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-sl/strings.xml b/libs/WindowManager/Shell/res/values-sl/strings.xml
index 280346d..a50397f 100644
--- a/libs/WindowManager/Shell/res/values-sl/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sl/strings.xml
@@ -97,6 +97,9 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Težave s fotoaparatom?\nDotaknite se za vnovično prilagoditev"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"To ni odpravilo težave?\nDotaknite se za povrnitev"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Nimate težav s fotoaparatom? Dotaknite se za opustitev."</string>
+    <string name="windowing_app_handle_education_tooltip" msgid="6398482412956375783">"Dotaknite se, če želite odpreti meni aplikacije"</string>
+    <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="6285279585554484957">"Dotaknite se, če želite prikazati več aplikacij hkrati"</string>
+    <string name="windowing_desktop_mode_exit_education_tooltip" msgid="6685429075790085337">"Nazaj v celozaslonski način iz menija aplikacije"</string>
     <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Oglejte si in naredite več"</string>
     <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Za razdeljeni zaslon povlecite sem še eno aplikacijo."</string>
     <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Dvakrat se dotaknite zunaj aplikacije, če jo želite prestaviti."</string>
@@ -129,8 +132,13 @@
     <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Odpri meni"</string>
     <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maksimiraj zaslon"</string>
     <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Pripni zaslon"</string>
-    <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"Velikosti te aplikacije ni mogoče spremeniti"</string>
+    <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Aplikacije ni mogoče premakniti sem"</string>
     <string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"Maksimiraj"</string>
     <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Pripni levo"</string>
     <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"Pripni desno"</string>
+    <string name="open_by_default_settings_text" msgid="2526548548598185500">"Nastavitve privzetega odpiranja"</string>
+    <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Izberite način odpiranja spletnih povezav za to aplikacijo"</string>
+    <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"V aplikaciji"</string>
+    <string name="open_by_default_dialog_in_browser_text" msgid="8042769465958497081">"V brskalniku"</string>
+    <string name="open_by_default_dialog_dismiss_button_text" msgid="3487238795534582291">"V redu"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-sq/strings.xml b/libs/WindowManager/Shell/res/values-sq/strings.xml
index a4a7e74..480e2a4 100644
--- a/libs/WindowManager/Shell/res/values-sq/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sq/strings.xml
@@ -97,6 +97,9 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Ka probleme me kamerën?\nTrokit për ta ripërshtatur"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Nuk u rregullua?\nTrokit për ta rikthyer"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Nuk ka probleme me kamerën? Trokit për ta shpërfillur."</string>
+    <string name="windowing_app_handle_education_tooltip" msgid="6398482412956375783">"Trokit për të hapur menynë e aplikacionit"</string>
+    <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="6285279585554484957">"Trokit për të shfaqur disa aplikacione bashkë"</string>
+    <string name="windowing_desktop_mode_exit_education_tooltip" msgid="6685429075790085337">"Kthehu tek ekrani i plotë nga menyja e aplikacionit"</string>
     <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Shiko dhe bëj më shumë"</string>
     <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Zvarrite në një aplikacion tjetër për ekranin e ndarë"</string>
     <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Trokit dy herë jashtë një aplikacioni për ta ripozicionuar"</string>
@@ -126,15 +129,21 @@
     <string name="manage_windows_text" msgid="5567366688493093920">"Menaxho dritaret"</string>
     <string name="close_text" msgid="4986518933445178928">"Mbyll"</string>
     <string name="collapse_menu_text" msgid="7515008122450342029">"Mbyll menynë"</string>
-    <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) -->
-    <skip />
+    <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Hap menynë"</string>
     <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maksimizo ekranin"</string>
     <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Regjistro ekranin"</string>
-    <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"Përmasat e këtij aplikacioni nuk mund të ndryshohen"</string>
-    <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) -->
+    <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Aplikacioni nuk mund të zhvendoset këtu"</string>
+    <string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"Maksimizo"</string>
+    <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Zhvendos majtas"</string>
+    <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"Zhvendos djathtas"</string>
+    <!-- no translation found for open_by_default_settings_text (2526548548598185500) -->
     <skip />
-    <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) -->
+    <!-- no translation found for open_by_default_dialog_subheader_text (1729599730664063881) -->
     <skip />
-    <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) -->
+    <!-- no translation found for open_by_default_dialog_in_app_text (6978022419634199806) -->
+    <skip />
+    <!-- no translation found for open_by_default_dialog_in_browser_text (8042769465958497081) -->
+    <skip />
+    <!-- no translation found for open_by_default_dialog_dismiss_button_text (3487238795534582291) -->
     <skip />
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-sr/strings.xml b/libs/WindowManager/Shell/res/values-sr/strings.xml
index 9545ccf..d8debc0 100644
--- a/libs/WindowManager/Shell/res/values-sr/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sr/strings.xml
@@ -97,6 +97,9 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Имате проблема са камером?\nДодирните да бисте поново уклопили"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Проблем није решен?\nДодирните да бисте вратили"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Немате проблема са камером? Додирните да бисте одбацили."</string>
+    <string name="windowing_app_handle_education_tooltip" msgid="6398482412956375783">"Додирните да бисте отворили мени апликације"</string>
+    <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="6285279585554484957">"Додирните да бисте приказали више апликација заједно"</string>
+    <string name="windowing_desktop_mode_exit_education_tooltip" msgid="6685429075790085337">"Вратите се из менија апликације на приказ преко целог екрана"</string>
     <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Видите и урадите више"</string>
     <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Превуците другу апликацију да бисте користили подељени екран"</string>
     <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Двапут додирните изван апликације да бисте променили њену позицију"</string>
@@ -126,15 +129,16 @@
     <string name="manage_windows_text" msgid="5567366688493093920">"Управљајте прозорима"</string>
     <string name="close_text" msgid="4986518933445178928">"Затворите"</string>
     <string name="collapse_menu_text" msgid="7515008122450342029">"Затворите мени"</string>
-    <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) -->
-    <skip />
+    <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Отворите мени"</string>
     <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Повећај екран"</string>
     <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Уклопи екран"</string>
-    <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"Величина ове апликације не може да се промени"</string>
-    <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) -->
-    <skip />
-    <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) -->
-    <skip />
-    <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) -->
-    <skip />
+    <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Апликација не може да се премести овде"</string>
+    <string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"Увећајте"</string>
+    <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Прикачите лево"</string>
+    <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"Прикачите десно"</string>
+    <string name="open_by_default_settings_text" msgid="2526548548598185500">"Подешавање Подразумевано отварај"</string>
+    <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Одаберите начин отварања веб-линкова за ову апликацију"</string>
+    <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"У апликацији"</string>
+    <string name="open_by_default_dialog_in_browser_text" msgid="8042769465958497081">"У прегледачу"</string>
+    <string name="open_by_default_dialog_dismiss_button_text" msgid="3487238795534582291">"Потврди"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-sv/strings.xml b/libs/WindowManager/Shell/res/values-sv/strings.xml
index aa74bde..e262a9b 100644
--- a/libs/WindowManager/Shell/res/values-sv/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sv/strings.xml
@@ -97,6 +97,9 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Problem med kameran?\nTryck för att anpassa på nytt"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Löstes inte problemet?\nTryck för att återställa"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Inga problem med kameran? Tryck för att ignorera."</string>
+    <string name="windowing_app_handle_education_tooltip" msgid="6398482412956375783">"Tryck för att öppna appmenyn"</string>
+    <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="6285279585554484957">"Tryck för att visa flera appar tillsammans"</string>
+    <string name="windowing_desktop_mode_exit_education_tooltip" msgid="6685429075790085337">"Återgå till helskärm från appmenyn"</string>
     <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Se och gör mer"</string>
     <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Dra till en annan app för att dela upp skärmen"</string>
     <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Tryck snabbt två gånger utanför en app för att flytta den"</string>
@@ -129,8 +132,13 @@
     <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Öppna menyn"</string>
     <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maximera skärmen"</string>
     <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Fäst skärmen"</string>
-    <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"Det går inte att ändra storlek på appen"</string>
+    <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Det går inte att flytta appen hit"</string>
     <string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"Utöka"</string>
     <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Fäst till vänster"</string>
     <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"Fäst till höger"</string>
+    <string name="open_by_default_settings_text" msgid="2526548548598185500">"Inställningar för öppna som standard"</string>
+    <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Välj hur webblänkar ska öppnas för den här appen"</string>
+    <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"I appen"</string>
+    <string name="open_by_default_dialog_in_browser_text" msgid="8042769465958497081">"I webbläsaren"</string>
+    <string name="open_by_default_dialog_dismiss_button_text" msgid="3487238795534582291">"OK"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-sw/strings.xml b/libs/WindowManager/Shell/res/values-sw/strings.xml
index c6ce023..b1679c0 100644
--- a/libs/WindowManager/Shell/res/values-sw/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sw/strings.xml
@@ -97,6 +97,9 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Je, kuna hitilafu za kamera?\nGusa ili urekebishe"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Umeshindwa kurekebisha?\nGusa ili urejeshe nakala ya awali"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Je, hakuna hitilafu za kamera? Gusa ili uondoe."</string>
+    <string name="windowing_app_handle_education_tooltip" msgid="6398482412956375783">"Gusa ili ufungue menyu ya programu"</string>
+    <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="6285279585554484957">"Gusa ili uonyeshe programu nyingi kwa pamoja"</string>
+    <string name="windowing_desktop_mode_exit_education_tooltip" msgid="6685429075790085337">"Rudi kwenye skrini nzima katika menyu ya programu"</string>
     <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Angalia na ufanye zaidi"</string>
     <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Buruta katika programu nyingine ili utumie skrini iliyogawanywa"</string>
     <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Gusa mara mbili nje ya programu ili uihamishe"</string>
@@ -126,15 +129,16 @@
     <string name="manage_windows_text" msgid="5567366688493093920">"Dhibiti Windows"</string>
     <string name="close_text" msgid="4986518933445178928">"Funga"</string>
     <string name="collapse_menu_text" msgid="7515008122450342029">"Funga Menyu"</string>
-    <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) -->
-    <skip />
+    <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Fungua Menyu"</string>
     <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Panua Dirisha kwenye Skrini"</string>
     <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Panga Madirisha kwenye Skrini"</string>
-    <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"Huwezi kubadilisha ukubwa wa programu hii"</string>
-    <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) -->
-    <skip />
-    <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) -->
-    <skip />
-    <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) -->
-    <skip />
+    <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Imeshindwa kuhamishia programu hapa"</string>
+    <string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"Panua"</string>
+    <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Telezesha kushoto"</string>
+    <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"Telezesha kulia"</string>
+    <string name="open_by_default_settings_text" msgid="2526548548598185500">"Fungua kwa mipangilio chaguomsingi"</string>
+    <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Chagua jinsi ya kufungua viungo vya wavuti vya programu hii"</string>
+    <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"Kwenye programu"</string>
+    <string name="open_by_default_dialog_in_browser_text" msgid="8042769465958497081">"Kwenye kivinjari chako"</string>
+    <string name="open_by_default_dialog_dismiss_button_text" msgid="3487238795534582291">"Sawa"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-ta/strings.xml b/libs/WindowManager/Shell/res/values-ta/strings.xml
index 2c2f319..8df170d 100644
--- a/libs/WindowManager/Shell/res/values-ta/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ta/strings.xml
@@ -97,6 +97,9 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"கேமரா தொடர்பான சிக்கல்களா?\nமீண்டும் பொருத்த தட்டவும்"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"சிக்கல்கள் சரிசெய்யப்படவில்லையா?\nமாற்றியமைக்க தட்டவும்"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"கேமரா தொடர்பான சிக்கல்கள் எதுவும் இல்லையா? நிராகரிக்க தட்டவும்."</string>
+    <string name="windowing_app_handle_education_tooltip" msgid="6398482412956375783">"ஆப்ஸ் மெனுவைத் திறக்க தட்டவும்"</string>
+    <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="6285279585554484957">"பல ஆப்ஸை ஒன்றாகக் காட்ட தட்டவும்"</string>
+    <string name="windowing_desktop_mode_exit_education_tooltip" msgid="6685429075790085337">"ஆப்ஸ் மெனுவில் இருந்து முழுத்திரைக்குச் செல்லும்"</string>
     <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"பலவற்றைப் பார்த்தல் மற்றும் செய்தல்"</string>
     <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"திரைப் பிரிப்புக்கு மற்றொரு ஆப்ஸை இழுக்கலாம்"</string>
     <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"ஆப்ஸை இடம் மாற்ற அதன் வெளியில் இருமுறை தட்டலாம்"</string>
@@ -126,15 +129,16 @@
     <string name="manage_windows_text" msgid="5567366688493093920">"சாளரங்களை நிர்வகிக்கலாம்"</string>
     <string name="close_text" msgid="4986518933445178928">"மூடும்"</string>
     <string name="collapse_menu_text" msgid="7515008122450342029">"மெனுவை மூடும்"</string>
-    <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) -->
-    <skip />
+    <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"மெனுவைத் திறக்கும்"</string>
     <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"திரையைப் பெரிதாக்கு"</string>
     <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"திரையை ஸ்னாப் செய்"</string>
-    <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"இந்த ஆப்ஸின் அளவை மாற்ற முடியாது"</string>
-    <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) -->
-    <skip />
-    <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) -->
-    <skip />
-    <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) -->
-    <skip />
+    <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"ஆப்ஸை இங்கே நகர்த்த முடியாது"</string>
+    <string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"பெரிதாக்கும்"</string>
+    <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"இடதுபுறம் நகர்த்தும்"</string>
+    <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"வலதுபுறம் நகர்த்தும்"</string>
+    <string name="open_by_default_settings_text" msgid="2526548548598185500">"இயல்பாக அமைப்புகளைத் திறக்கும்"</string>
+    <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"இந்த ஆப்ஸில் வலை இணைப்புகளைத் திறக்கும் வழிமுறையைத் தேர்வுசெய்யுங்கள்"</string>
+    <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"ஆப்ஸில்"</string>
+    <string name="open_by_default_dialog_in_browser_text" msgid="8042769465958497081">"உங்கள் பிரவுசரில்"</string>
+    <string name="open_by_default_dialog_dismiss_button_text" msgid="3487238795534582291">"சரி"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-te/strings.xml b/libs/WindowManager/Shell/res/values-te/strings.xml
index 8691c9d..82523b6 100644
--- a/libs/WindowManager/Shell/res/values-te/strings.xml
+++ b/libs/WindowManager/Shell/res/values-te/strings.xml
@@ -97,6 +97,9 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"కెమెరా సమస్యలు ఉన్నాయా?\nరీఫిట్ చేయడానికి ట్యాప్ చేయండి"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"దాని సమస్యను పరిష్కరించలేదా?\nపూర్వస్థితికి మార్చడానికి ట్యాప్ చేయండి"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"కెమెరా సమస్యలు లేవా? తీసివేయడానికి ట్యాప్ చేయండి."</string>
+    <string name="windowing_app_handle_education_tooltip" msgid="6398482412956375783">"యాప్ మెనూని తెరవడానికి ట్యాప్ చేయండి"</string>
+    <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="6285279585554484957">"పలు యాప్‌లను కలిపి చూడటానికి ట్యాప్ చేయండి"</string>
+    <string name="windowing_desktop_mode_exit_education_tooltip" msgid="6685429075790085337">"యాప్ మెనూ నుండి ఫుల్ స్క్రీన్‌కు తిరిగి రండి"</string>
     <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"చూసి, మరిన్ని చేయండి"</string>
     <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"స్ప్లిట్ స్క్రీన్ కోసం మరొక యాప్‌లోకి లాగండి"</string>
     <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"యాప్ స్థానాన్ని మార్చడానికి దాని వెలుపల డబుల్-ట్యాప్ చేయండి"</string>
@@ -126,15 +129,16 @@
     <string name="manage_windows_text" msgid="5567366688493093920">"విండోలను మేనేజ్ చేయండి"</string>
     <string name="close_text" msgid="4986518933445178928">"మూసివేయండి"</string>
     <string name="collapse_menu_text" msgid="7515008122450342029">"మెనూను మూసివేయండి"</string>
-    <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) -->
-    <skip />
+    <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"మెనూను తెరవండి"</string>
     <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"స్క్రీన్ సైజ్‌ను పెంచండి"</string>
     <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"స్క్రీన్‌ను స్నాప్ చేయండి"</string>
-    <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"ఈ యాప్ సైజ్‌ను మార్చడం సాధ్యపడదు"</string>
-    <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) -->
-    <skip />
-    <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) -->
-    <skip />
-    <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) -->
-    <skip />
+    <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"యాప్‌ను ఇక్కడకి తరలించడం సాధ్యం కాదు"</string>
+    <string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"మ్యాగ్జిమైజ్ చేయండి"</string>
+    <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"ఎడమ వైపున స్నాప్ చేయండి"</string>
+    <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"కుడి వైపున స్నాప్ చేయండి"</string>
+    <string name="open_by_default_settings_text" msgid="2526548548598185500">"ఆటోమేటిక్ సెట్టింగ్‌ల ద్వారా తెరవండి"</string>
+    <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"ఈ యాప్‌నకు సంబంధించిన వెబ్ లింక్‌లను ఎలా తెరవాలో ఎంచుకోండి"</string>
+    <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"యాప్‌లో"</string>
+    <string name="open_by_default_dialog_in_browser_text" msgid="8042769465958497081">"మీ బ్రౌజర్‌లో"</string>
+    <string name="open_by_default_dialog_dismiss_button_text" msgid="3487238795534582291">"సరే"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-th/strings.xml b/libs/WindowManager/Shell/res/values-th/strings.xml
index 07e1416..cc7a603 100644
--- a/libs/WindowManager/Shell/res/values-th/strings.xml
+++ b/libs/WindowManager/Shell/res/values-th/strings.xml
@@ -97,6 +97,9 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"หากพบปัญหากับกล้อง\nแตะเพื่อแก้ไข"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"หากไม่ได้แก้ไข\nแตะเพื่อเปลี่ยนกลับ"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"หากไม่พบปัญหากับกล้อง แตะเพื่อปิด"</string>
+    <string name="windowing_app_handle_education_tooltip" msgid="6398482412956375783">"แตะเพื่อเปิดเมนูแอป"</string>
+    <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="6285279585554484957">"แตะเพื่อแสดงแอปหลายรายการพร้อมกัน"</string>
+    <string name="windowing_desktop_mode_exit_education_tooltip" msgid="6685429075790085337">"กลับไปที่เต็มหน้าจอจากเมนูแอป"</string>
     <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"รับชมและทำสิ่งต่างๆ ได้มากขึ้น"</string>
     <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"ลากไปไว้ในแอปอื่นเพื่อแยกหน้าจอ"</string>
     <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"แตะสองครั้งด้านนอกแอปเพื่อเปลี่ยนตำแหน่ง"</string>
@@ -126,15 +129,16 @@
     <string name="manage_windows_text" msgid="5567366688493093920">"จัดการหน้าต่าง"</string>
     <string name="close_text" msgid="4986518933445178928">"ปิด"</string>
     <string name="collapse_menu_text" msgid="7515008122450342029">"ปิดเมนู"</string>
-    <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) -->
-    <skip />
+    <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"เปิดเมนู"</string>
     <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"ขยายหน้าจอให้ใหญ่สุด"</string>
     <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"สแนปหน้าจอ"</string>
-    <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"ปรับขนาดแอปนี้ไม่ได้"</string>
-    <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) -->
-    <skip />
-    <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) -->
-    <skip />
-    <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) -->
-    <skip />
+    <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"ย้ายแอปมาที่นี่ไม่ได้"</string>
+    <string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"ขยายใหญ่สุด"</string>
+    <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"จัดพอดีกับทางซ้าย"</string>
+    <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"จัดพอดีกับทางขวา"</string>
+    <string name="open_by_default_settings_text" msgid="2526548548598185500">"เปิดตามการตั้งค่าเริ่มต้น"</string>
+    <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"เลือกวิธีเปิดเว็บลิงก์สำหรับแอปนี้"</string>
+    <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"ในแอป"</string>
+    <string name="open_by_default_dialog_in_browser_text" msgid="8042769465958497081">"ในเบราว์เซอร์"</string>
+    <string name="open_by_default_dialog_dismiss_button_text" msgid="3487238795534582291">"ตกลง"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-tl/strings.xml b/libs/WindowManager/Shell/res/values-tl/strings.xml
index 477700e..bb543f3 100644
--- a/libs/WindowManager/Shell/res/values-tl/strings.xml
+++ b/libs/WindowManager/Shell/res/values-tl/strings.xml
@@ -97,6 +97,9 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"May mga isyu sa camera?\nI-tap para i-refit"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Hindi ito naayos?\nI-tap para i-revert"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Walang isyu sa camera? I-tap para i-dismiss."</string>
+    <string name="windowing_app_handle_education_tooltip" msgid="6398482412956375783">"I-tap para buksan ang menu ng app"</string>
+    <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="6285279585554484957">"I-tap para ipakita nang magkakasama ang maraming app"</string>
+    <string name="windowing_desktop_mode_exit_education_tooltip" msgid="6685429075790085337">"Bumalik sa fullscreen mula sa menu ng app"</string>
     <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Tumingin at gumawa ng higit pa"</string>
     <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Mag-drag ng isa pang app para sa split screen"</string>
     <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Mag-double tap sa labas ng app para baguhin ang posisyon nito"</string>
@@ -126,15 +129,16 @@
     <string name="manage_windows_text" msgid="5567366688493093920">"Pamahalaan ang Mga Window"</string>
     <string name="close_text" msgid="4986518933445178928">"Isara"</string>
     <string name="collapse_menu_text" msgid="7515008122450342029">"Isara ang Menu"</string>
-    <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) -->
-    <skip />
+    <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Buksan ang Menu"</string>
     <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"I-maximize ang Screen"</string>
     <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"I-snap ang Screen"</string>
-    <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"Hindi nare-resize ang app na ito"</string>
-    <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) -->
-    <skip />
-    <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) -->
-    <skip />
-    <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) -->
-    <skip />
+    <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Hindi mailipat dito ang app"</string>
+    <string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"I-maximize"</string>
+    <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"I-snap pakaliwa"</string>
+    <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"I-snap pakanan"</string>
+    <string name="open_by_default_settings_text" msgid="2526548548598185500">"Buksan sa pamamagitan ng mga default na setting"</string>
+    <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Piliin kung paano magbukas ng web link para sa app na ito"</string>
+    <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"Sa app"</string>
+    <string name="open_by_default_dialog_in_browser_text" msgid="8042769465958497081">"Sa iyong browser"</string>
+    <string name="open_by_default_dialog_dismiss_button_text" msgid="3487238795534582291">"OK"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-tr/strings.xml b/libs/WindowManager/Shell/res/values-tr/strings.xml
index b0c2539..c8dcefb 100644
--- a/libs/WindowManager/Shell/res/values-tr/strings.xml
+++ b/libs/WindowManager/Shell/res/values-tr/strings.xml
@@ -97,6 +97,9 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Kameranızda sorun mu var?\nDüzeltmek için dokunun"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Bu işlem sorunu düzeltmedi mi?\nİşlemi geri almak için dokunun"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Kameranızda sorun yok mu? Kapatmak için dokunun."</string>
+    <string name="windowing_app_handle_education_tooltip" msgid="6398482412956375783">"Uygulama menüsünü açmak için dokunun"</string>
+    <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="6285279585554484957">"Birden fazla uygulamayı birlikte göstermek için dokunun"</string>
+    <string name="windowing_desktop_mode_exit_education_tooltip" msgid="6685429075790085337">"Uygulama menüsünden tam ekrana dönün"</string>
     <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Daha fazlasını görün ve yapın"</string>
     <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Bölünmüş ekran için başka bir uygulamayı sürükleyin"</string>
     <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Yeniden konumlandırmak için uygulamanın dışına iki kez dokunun"</string>
@@ -126,15 +129,16 @@
     <string name="manage_windows_text" msgid="5567366688493093920">"Pencereleri yönet"</string>
     <string name="close_text" msgid="4986518933445178928">"Kapat"</string>
     <string name="collapse_menu_text" msgid="7515008122450342029">"Menüyü kapat"</string>
-    <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) -->
-    <skip />
+    <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Menüyü aç"</string>
     <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Ekranı Büyüt"</string>
     <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Ekranın Yarısına Tuttur"</string>
-    <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"Bu uygulama yeniden boyutlandırılamaz"</string>
-    <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) -->
-    <skip />
-    <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) -->
-    <skip />
-    <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) -->
-    <skip />
+    <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Uygulama buraya taşınamıyor"</string>
+    <string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"Ekranı kapla"</string>
+    <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Sola tuttur"</string>
+    <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"Sağa tuttur"</string>
+    <string name="open_by_default_settings_text" msgid="2526548548598185500">"Varsayılan olarak açma ayarları"</string>
+    <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Bu uygulama için web bağlantılarının nasıl açılacağını seçin"</string>
+    <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"Uygulamada"</string>
+    <string name="open_by_default_dialog_in_browser_text" msgid="8042769465958497081">"Tarayıcınızda"</string>
+    <string name="open_by_default_dialog_dismiss_button_text" msgid="3487238795534582291">"Tamam"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-uk/strings.xml b/libs/WindowManager/Shell/res/values-uk/strings.xml
index dd64c66..90a3bc33b 100644
--- a/libs/WindowManager/Shell/res/values-uk/strings.xml
+++ b/libs/WindowManager/Shell/res/values-uk/strings.xml
@@ -97,6 +97,9 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Проблеми з камерою?\nНатисніть, щоб пристосувати"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Проблему не вирішено?\nНатисніть, щоб скасувати зміни"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Немає проблем із камерою? Торкніться, щоб закрити."</string>
+    <string name="windowing_app_handle_education_tooltip" msgid="6398482412956375783">"Натисніть, щоб відкрити меню додатка"</string>
+    <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="6285279585554484957">"Натисніть, щоб переглянути кілька додатків одночасно"</string>
+    <string name="windowing_desktop_mode_exit_education_tooltip" msgid="6685429075790085337">"Повернутися з меню додатка в повноекранний режим"</string>
     <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Більше простору та можливостей"</string>
     <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Щоб перейти в режим розділення екрана, перетягніть сюди інший додаток"</string>
     <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Щоб перемістити додаток, двічі торкніться області поза ним"</string>
@@ -126,15 +129,21 @@
     <string name="manage_windows_text" msgid="5567366688493093920">"Керувати вікнами"</string>
     <string name="close_text" msgid="4986518933445178928">"Закрити"</string>
     <string name="collapse_menu_text" msgid="7515008122450342029">"Закрити меню"</string>
-    <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) -->
-    <skip />
+    <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Відкрити меню"</string>
     <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Розгорнути екран"</string>
     <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Зафіксувати екран"</string>
-    <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"Розмір вікна цього додатка не можна змінити"</string>
-    <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) -->
+    <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Сюди не можна перемістити додаток"</string>
+    <string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"Розгорнути"</string>
+    <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Закріпити ліворуч"</string>
+    <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"Закріпити праворуч"</string>
+    <!-- no translation found for open_by_default_settings_text (2526548548598185500) -->
     <skip />
-    <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) -->
+    <!-- no translation found for open_by_default_dialog_subheader_text (1729599730664063881) -->
     <skip />
-    <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) -->
+    <!-- no translation found for open_by_default_dialog_in_app_text (6978022419634199806) -->
+    <skip />
+    <!-- no translation found for open_by_default_dialog_in_browser_text (8042769465958497081) -->
+    <skip />
+    <!-- no translation found for open_by_default_dialog_dismiss_button_text (3487238795534582291) -->
     <skip />
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-ur/strings.xml b/libs/WindowManager/Shell/res/values-ur/strings.xml
index aa311c2..eca6801 100644
--- a/libs/WindowManager/Shell/res/values-ur/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ur/strings.xml
@@ -97,6 +97,9 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"کیمرے کے مسائل؟\nدوبارہ فٹ کرنے کیلئے تھپتھپائیں"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"یہ حل نہیں ہوا؟\nلوٹانے کیلئے تھپتھپائیں"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"کوئی کیمرے کا مسئلہ نہیں ہے؟ برخاست کرنے کیلئے تھپتھپائیں۔"</string>
+    <string name="windowing_app_handle_education_tooltip" msgid="6398482412956375783">"ایپ مینو کھولنے کیلئے تھپتھپائیں"</string>
+    <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="6285279585554484957">"متعدد ایپس ایک ساتھ دکھانے کیلئے تھپتھپائیں"</string>
+    <string name="windowing_desktop_mode_exit_education_tooltip" msgid="6685429075790085337">"ایپ مینو سے مکمل اسکرین پر واپس جائیں"</string>
     <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"دیکھیں اور بہت کچھ کریں"</string>
     <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"اسپلٹ اسکرین کے ليے دوسری ایپ میں گھسیٹیں"</string>
     <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"کسی ایپ کی پوزیشن تبدیل کرنے کے لیے اس ایپ کے باہر دو بار تھپتھپائیں"</string>
@@ -126,15 +129,16 @@
     <string name="manage_windows_text" msgid="5567366688493093920">"‏‫Windows کا نظم کریں"</string>
     <string name="close_text" msgid="4986518933445178928">"بند کریں"</string>
     <string name="collapse_menu_text" msgid="7515008122450342029">"مینیو بند کریں"</string>
-    <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) -->
-    <skip />
+    <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"مینو کھولیں"</string>
     <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"اسکرین کو بڑا کریں"</string>
     <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"اسکرین کا اسناپ شاٹ لیں"</string>
-    <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"اس ایپ کا سائز تبدیل نہیں کیا جا سکتا"</string>
-    <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) -->
-    <skip />
-    <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) -->
-    <skip />
-    <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) -->
-    <skip />
+    <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"ایپ کو یہاں منتقل نہیں کیا جا سکتا"</string>
+    <string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"بڑا کریں"</string>
+    <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"دائیں منتقل کریں"</string>
+    <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"بائیں منتقل کریں"</string>
+    <string name="open_by_default_settings_text" msgid="2526548548598185500">"بطور ڈیفالٹ ترتیبات کھولیں"</string>
+    <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"اس ایپ کے لیے ویب لنکس کھولنے کا طریقہ منتخب کریں"</string>
+    <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"ایپ میں"</string>
+    <string name="open_by_default_dialog_in_browser_text" msgid="8042769465958497081">"آپ کے براؤزر میں"</string>
+    <string name="open_by_default_dialog_dismiss_button_text" msgid="3487238795534582291">"ٹھیک ہے"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-uz/strings.xml b/libs/WindowManager/Shell/res/values-uz/strings.xml
index cd0ca82..4b163f7 100644
--- a/libs/WindowManager/Shell/res/values-uz/strings.xml
+++ b/libs/WindowManager/Shell/res/values-uz/strings.xml
@@ -97,6 +97,9 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Kamera nosozmi?\nQayta moslash uchun bosing"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Tuzatilmadimi?\nQaytarish uchun bosing"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Kamera muammosizmi? Yopish uchun bosing."</string>
+    <string name="windowing_app_handle_education_tooltip" msgid="6398482412956375783">"Ilova menyusini ochish uchun bosing"</string>
+    <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="6285279585554484957">"Bir nechta ilovani birga chiqarish uchun bosing"</string>
+    <string name="windowing_desktop_mode_exit_education_tooltip" msgid="6685429075790085337">"Ilova menyusidan butun ekranga qayting"</string>
     <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Yana boshqa amallar"</string>
     <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Ekranni ikkiga ajratish uchun boshqa ilovani bu yerga torting"</string>
     <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Qayta joylash uchun ilova tashqarisiga ikki marta bosing"</string>
@@ -129,8 +132,18 @@
     <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Menyuni ochish"</string>
     <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Ekranni yoyish"</string>
     <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Ekranni biriktirish"</string>
-    <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"Bu ilova hajmini oʻzgartirish imkonsiz"</string>
+    <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Ilova bu yerga surilmaydi"</string>
     <string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"Yoyish"</string>
     <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Chapga tortish"</string>
     <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"Oʻngga tortish"</string>
+    <!-- no translation found for open_by_default_settings_text (2526548548598185500) -->
+    <skip />
+    <!-- no translation found for open_by_default_dialog_subheader_text (1729599730664063881) -->
+    <skip />
+    <!-- no translation found for open_by_default_dialog_in_app_text (6978022419634199806) -->
+    <skip />
+    <!-- no translation found for open_by_default_dialog_in_browser_text (8042769465958497081) -->
+    <skip />
+    <!-- no translation found for open_by_default_dialog_dismiss_button_text (3487238795534582291) -->
+    <skip />
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-vi/strings.xml b/libs/WindowManager/Shell/res/values-vi/strings.xml
index abac3fe..e381c98 100644
--- a/libs/WindowManager/Shell/res/values-vi/strings.xml
+++ b/libs/WindowManager/Shell/res/values-vi/strings.xml
@@ -97,6 +97,9 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Có vấn đề với máy ảnh?\nHãy nhấn để sửa lỗi"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Bạn chưa khắc phục vấn đề?\nHãy nhấn để hủy bỏ"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Không có vấn đề với máy ảnh? Hãy nhấn để đóng."</string>
+    <string name="windowing_app_handle_education_tooltip" msgid="6398482412956375783">"Nhấn để mở trình đơn ứng dụng"</string>
+    <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="6285279585554484957">"Nhấn để hiển thị nhiều ứng dụng cùng lúc"</string>
+    <string name="windowing_desktop_mode_exit_education_tooltip" msgid="6685429075790085337">"Quay lại chế độ toàn màn hình từ trình đơn ứng dụng"</string>
     <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Xem và làm được nhiều việc hơn"</string>
     <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Kéo một ứng dụng khác vào để chia đôi màn hình"</string>
     <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Nhấn đúp bên ngoài ứng dụng để đặt lại vị trí"</string>
@@ -126,15 +129,16 @@
     <string name="manage_windows_text" msgid="5567366688493093920">"Quản lý cửa sổ"</string>
     <string name="close_text" msgid="4986518933445178928">"Đóng"</string>
     <string name="collapse_menu_text" msgid="7515008122450342029">"Đóng trình đơn"</string>
-    <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) -->
-    <skip />
+    <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Mở Trình đơn"</string>
     <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Mở rộng màn hình"</string>
     <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Điều chỉnh kích thước màn hình"</string>
-    <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"Không thể đổi kích thước của ứng dụng này"</string>
-    <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) -->
-    <skip />
-    <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) -->
-    <skip />
-    <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) -->
-    <skip />
+    <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Không di chuyển được ứng dụng đến đây"</string>
+    <string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"Phóng to tối đa"</string>
+    <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Di chuyển nhanh sang trái"</string>
+    <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"Di chuyển nhanh sang phải"</string>
+    <string name="open_by_default_settings_text" msgid="2526548548598185500">"Mở các chế độ cài đặt theo mặc định"</string>
+    <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Chọn cách mở đường liên kết trang web cho ứng dụng này"</string>
+    <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"Trong ứng dụng"</string>
+    <string name="open_by_default_dialog_in_browser_text" msgid="8042769465958497081">"Trên trình duyệt"</string>
+    <string name="open_by_default_dialog_dismiss_button_text" msgid="3487238795534582291">"OK"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml b/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml
index 5a61dec..e39a64d 100644
--- a/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml
+++ b/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml
@@ -97,6 +97,9 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"相机有问题?\n点按即可整修"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"没有解决此问题?\n点按即可恢复"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"相机没有问题?点按即可忽略。"</string>
+    <string name="windowing_app_handle_education_tooltip" msgid="6398482412956375783">"点按可打开应用菜单"</string>
+    <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="6285279585554484957">"点按可同时显示多个应用"</string>
+    <string name="windowing_desktop_mode_exit_education_tooltip" msgid="6685429075790085337">"从应用菜单可返回到全屏"</string>
     <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"查看和处理更多任务"</string>
     <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"拖入另一个应用,即可使用分屏模式"</string>
     <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"在某个应用外连续点按两次,即可调整它的位置"</string>
@@ -126,15 +129,16 @@
     <string name="manage_windows_text" msgid="5567366688493093920">"管理窗口"</string>
     <string name="close_text" msgid="4986518933445178928">"关闭"</string>
     <string name="collapse_menu_text" msgid="7515008122450342029">"关闭菜单"</string>
-    <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) -->
-    <skip />
+    <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"打开菜单"</string>
     <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"最大化屏幕"</string>
     <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"屏幕快照"</string>
-    <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"无法调整此应用的大小"</string>
-    <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) -->
-    <skip />
-    <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) -->
-    <skip />
-    <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) -->
-    <skip />
+    <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"无法将应用移至此处"</string>
+    <string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"最大化"</string>
+    <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"贴靠左侧"</string>
+    <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"贴靠右侧"</string>
+    <string name="open_by_default_settings_text" msgid="2526548548598185500">"默认打开设置"</string>
+    <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"选择如何打开此应用中的网页链接"</string>
+    <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"在此应用内"</string>
+    <string name="open_by_default_dialog_in_browser_text" msgid="8042769465958497081">"在浏览器中"</string>
+    <string name="open_by_default_dialog_dismiss_button_text" msgid="3487238795534582291">"确定"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml b/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml
index e1c303e..6cd2567 100644
--- a/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml
+++ b/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml
@@ -97,6 +97,9 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"相機有問題?\n輕按即可修正"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"未能修正問題?\n輕按即可還原"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"相機冇問題?㩒一下就可以即可閂咗佢。"</string>
+    <string name="windowing_app_handle_education_tooltip" msgid="6398482412956375783">"輕按即可開啟應用程式選單"</string>
+    <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="6285279585554484957">"輕按即可同時顯示多個應用程式"</string>
+    <string name="windowing_desktop_mode_exit_education_tooltip" msgid="6685429075790085337">"從應用程式選單返回全螢幕"</string>
     <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"瀏覽更多內容及執行更多操作"</string>
     <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"拖入另一個應用程式即可分割螢幕"</string>
     <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"在應用程式外輕按兩下即可調整位置"</string>
@@ -126,15 +129,16 @@
     <string name="manage_windows_text" msgid="5567366688493093920">"管理視窗"</string>
     <string name="close_text" msgid="4986518933445178928">"關閉"</string>
     <string name="collapse_menu_text" msgid="7515008122450342029">"關閉選單"</string>
-    <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) -->
-    <skip />
+    <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"打開選單"</string>
     <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"畫面最大化"</string>
     <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"貼齊畫面"</string>
-    <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"此應用程式無法調整大小"</string>
-    <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) -->
-    <skip />
-    <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) -->
-    <skip />
-    <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) -->
-    <skip />
+    <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"應用程式無法移至這裡"</string>
+    <string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"最大化"</string>
+    <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"貼齊左邊"</string>
+    <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"貼齊右邊"</string>
+    <string name="open_by_default_settings_text" msgid="2526548548598185500">"採用預設設定打開"</string>
+    <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"選擇此應用程式開啟網絡連結的方式"</string>
+    <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"在應用程式內"</string>
+    <string name="open_by_default_dialog_in_browser_text" msgid="8042769465958497081">"在瀏覽器中"</string>
+    <string name="open_by_default_dialog_dismiss_button_text" msgid="3487238795534582291">"確定"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml b/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml
index 97e36c3..c14f664 100644
--- a/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml
+++ b/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml
@@ -97,6 +97,9 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"相機有問題嗎?\n輕觸即可修正"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"未修正問題嗎?\n輕觸即可還原"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"相機沒問題嗎?輕觸即可關閉。"</string>
+    <string name="windowing_app_handle_education_tooltip" msgid="6398482412956375783">"輕觸即可開啟應用程式選單"</string>
+    <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="6285279585554484957">"輕觸即可一次顯示多個應用程式"</string>
+    <string name="windowing_desktop_mode_exit_education_tooltip" msgid="6685429075790085337">"從應用程式選單返回全螢幕"</string>
     <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"瀏覽更多內容及執行更多操作"</string>
     <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"拖進另一個應用程式即可使用分割畫面模式"</string>
     <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"在應用程式外輕觸兩下即可調整位置"</string>
@@ -126,15 +129,16 @@
     <string name="manage_windows_text" msgid="5567366688493093920">"管理視窗"</string>
     <string name="close_text" msgid="4986518933445178928">"關閉"</string>
     <string name="collapse_menu_text" msgid="7515008122450342029">"關閉選單"</string>
-    <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) -->
-    <skip />
+    <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"開啟選單"</string>
     <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"畫面最大化"</string>
     <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"貼齊畫面"</string>
-    <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"這個應用程式無法調整大小"</string>
-    <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) -->
-    <skip />
-    <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) -->
-    <skip />
-    <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) -->
-    <skip />
+    <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"應用程式無法移至此處"</string>
+    <string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"最大化"</string>
+    <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"靠左對齊"</string>
+    <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"靠右對齊"</string>
+    <string name="open_by_default_settings_text" msgid="2526548548598185500">"開啟連結的預設設定"</string>
+    <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"選擇如何開啟這個應用程式的網頁連結"</string>
+    <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"使用應用程式"</string>
+    <string name="open_by_default_dialog_in_browser_text" msgid="8042769465958497081">"使用瀏覽器"</string>
+    <string name="open_by_default_dialog_dismiss_button_text" msgid="3487238795534582291">"確定"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-zu/strings.xml b/libs/WindowManager/Shell/res/values-zu/strings.xml
index 74c7169..70a3542 100644
--- a/libs/WindowManager/Shell/res/values-zu/strings.xml
+++ b/libs/WindowManager/Shell/res/values-zu/strings.xml
@@ -97,6 +97,9 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Izinkinga zekhamera?\nThepha ukuze uyilinganise kabusha"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Akuyilungisanga?\nThepha ukuze ubuyele"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Azikho izinkinga zekhamera? Thepha ukuze ucashise."</string>
+    <string name="windowing_app_handle_education_tooltip" msgid="6398482412956375783">"Thepha ukuze uvule imenyu ye-app"</string>
+    <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="6285279585554484957">"Thepha ukuze ubonise ama-app amaningi ndawonye"</string>
+    <string name="windowing_desktop_mode_exit_education_tooltip" msgid="6685429075790085337">"Buyela esikrinini esigcwele ukusuka kumenyu ye-app"</string>
     <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Bona futhi wenze okuningi"</string>
     <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Hudula kwenye i-app mayelana nokuhlukanisa isikrini"</string>
     <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Thepha kabili ngaphandle kwe-app ukuze uyimise kabusha"</string>
@@ -126,15 +129,16 @@
     <string name="manage_windows_text" msgid="5567366688493093920">"Phatha Amawindi"</string>
     <string name="close_text" msgid="4986518933445178928">"Vala"</string>
     <string name="collapse_menu_text" msgid="7515008122450342029">"Vala Imenyu"</string>
-    <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) -->
-    <skip />
+    <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Vula Imenyu"</string>
     <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Khulisa Isikrini Sifike Ekugcineni"</string>
     <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Thwebula Isikrini"</string>
-    <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"Le app ayikwazi ukushintshwa usayizi"</string>
-    <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) -->
-    <skip />
-    <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) -->
-    <skip />
-    <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) -->
-    <skip />
+    <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"I-app ayikwazi ukuhanjiswa lapha"</string>
+    <string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"Khulisa"</string>
+    <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Chofoza kwesobunxele"</string>
+    <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"Chofoza kwesokudla"</string>
+    <string name="open_by_default_settings_text" msgid="2526548548598185500">"Vula amasethingi ngokuzenzakalela"</string>
+    <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Khetha indlela yokuvula amalinki ewebhu ale app"</string>
+    <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"Ku-app"</string>
+    <string name="open_by_default_dialog_in_browser_text" msgid="8042769465958497081">"Kubhrawuza yakho"</string>
+    <string name="open_by_default_dialog_dismiss_button_text" msgid="3487238795534582291">"KULUNGILE"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values/strings.xml b/libs/WindowManager/Shell/res/values/strings.xml
index 5ef8432..621e2aa 100644
--- a/libs/WindowManager/Shell/res/values/strings.xml
+++ b/libs/WindowManager/Shell/res/values/strings.xml
@@ -220,13 +220,13 @@
     <string name="camera_compat_dismiss_button_description">No camera issues? Tap to dismiss.</string>
 
     <!-- App handle education tooltip text for tooltip pointing to app handle -->
-    <string name="windowing_app_handle_education_tooltip">Tap to open the app menu</string>
+    <string name="windowing_app_handle_education_tooltip">The app menu can be found here</string>
 
     <!-- App handle education tooltip text for tooltip pointing to windowing image button -->
-    <string name="windowing_desktop_mode_image_button_education_tooltip">Tap to show multiple apps together</string>
+    <string name="windowing_desktop_mode_image_button_education_tooltip">Enter desktop view to open multiple apps together</string>
 
     <!-- App handle education tooltip text for tooltip pointing to app chip -->
-    <string name="windowing_desktop_mode_exit_education_tooltip">Return to fullscreen from the app menu</string>
+    <string name="windowing_desktop_mode_exit_education_tooltip">Return to full screen anytime from the app menu</string>
 
     <!-- The title of the letterbox education dialog. [CHAR LIMIT=NONE] -->
     <string name="letterbox_education_dialog_title">See and do more</string>
diff --git a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/FocusTransitionListener.java b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/FocusTransitionListener.java
index 26aae2d..02a7991 100644
--- a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/FocusTransitionListener.java
+++ b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/FocusTransitionListener.java
@@ -26,5 +26,11 @@
     /**
      * Called when a transition changes the top, focused display.
      */
-    void onFocusedDisplayChanged(int displayId);
+    default void onFocusedDisplayChanged(int displayId) {}
+
+    /**
+     * Called when the per-app or system-wide focus state has changed for a task.
+     */
+    default void onFocusedTaskChanged(int taskId, boolean isFocusedOnDisplay,
+            boolean isFocusedGlobally) {}
 }
diff --git a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/bubbles/BubbleInfo.java b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/bubbles/BubbleInfo.java
index 5876682..85dabce 100644
--- a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/bubbles/BubbleInfo.java
+++ b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/bubbles/BubbleInfo.java
@@ -30,29 +30,32 @@
  */
 public class BubbleInfo implements Parcelable {
 
-    private String mKey; // Same key as the Notification
+    private final String mKey; // Same key as the Notification
     private int mFlags;  // Flags from BubbleMetadata
     @Nullable
-    private String mShortcutId;
-    private int mUserId;
-    private String mPackageName;
+    private final String mShortcutId;
+    private final int mUserId;
+    private final String mPackageName;
     /**
      * All notification bubbles require a shortcut to be set on the notification, however, the
      * app could still specify an Icon and PendingIntent to use for the bubble. In that case
      * this icon will be populated. If the bubble is entirely shortcut based, this will be null.
      */
     @Nullable
-    private Icon mIcon;
+    private final Icon mIcon;
     @Nullable
-    private String mTitle;
+    private final String mTitle;
     @Nullable
-    private String mAppName;
-    private boolean mIsImportantConversation;
-    private boolean mShowAppBadge;
+    private final String mAppName;
+    private final boolean mIsImportantConversation;
+    private final boolean mShowAppBadge;
+    @Nullable
+    private final ParcelableFlyoutMessage mParcelableFlyoutMessage;
 
     public BubbleInfo(String key, int flags, @Nullable String shortcutId, @Nullable Icon icon,
             int userId, String packageName, @Nullable String title, @Nullable String appName,
-            boolean isImportantConversation, boolean showAppBadge) {
+            boolean isImportantConversation, boolean showAppBadge,
+            @Nullable ParcelableFlyoutMessage flyoutMessage) {
         mKey = key;
         mFlags = flags;
         mShortcutId = shortcutId;
@@ -63,6 +66,7 @@
         mAppName = appName;
         mIsImportantConversation = isImportantConversation;
         mShowAppBadge = showAppBadge;
+        mParcelableFlyoutMessage = flyoutMessage;
     }
 
     private BubbleInfo(Parcel source) {
@@ -76,6 +80,8 @@
         mAppName = source.readString();
         mIsImportantConversation = source.readBoolean();
         mShowAppBadge = source.readBoolean();
+        mParcelableFlyoutMessage = source.readParcelable(
+                ParcelableFlyoutMessage.class.getClassLoader(), ParcelableFlyoutMessage.class);
     }
 
     public String getKey() {
@@ -122,6 +128,11 @@
         return mShowAppBadge;
     }
 
+    @Nullable
+    public ParcelableFlyoutMessage getParcelableFlyoutMessage() {
+        return mParcelableFlyoutMessage;
+    }
+
     /**
      * Whether this bubble is currently being hidden from the stack.
      */
@@ -180,6 +191,7 @@
         parcel.writeString(mAppName);
         parcel.writeBoolean(mIsImportantConversation);
         parcel.writeBoolean(mShowAppBadge);
+        parcel.writeParcelable(mParcelableFlyoutMessage, flags);
     }
 
     @NonNull
diff --git a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/bubbles/FlyoutDrawableLoader.kt b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/bubbles/FlyoutDrawableLoader.kt
new file mode 100644
index 0000000..5a17330
--- /dev/null
+++ b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/bubbles/FlyoutDrawableLoader.kt
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.shared.bubbles
+
+import android.content.Context
+import android.content.Intent
+import android.graphics.drawable.Drawable
+import android.graphics.drawable.Icon
+import android.util.Log
+
+object FlyoutDrawableLoader {
+
+    private const val TAG = "FlyoutDrawableLoader"
+
+    /** Loads the flyout icon as a [Drawable]. */
+    @JvmStatic
+    fun Icon?.loadFlyoutDrawable(context: Context): Drawable? {
+        if (this == null) return null
+        try {
+            if (this.type == Icon.TYPE_URI || this.type == Icon.TYPE_URI_ADAPTIVE_BITMAP) {
+                context.grantUriPermission(
+                    context.packageName,
+                    this.uri,
+                    Intent.FLAG_GRANT_READ_URI_PERMISSION
+                )
+            }
+            return loadDrawable(context)
+        } catch (e: Exception) {
+            Log.w(TAG, "loadFlyoutDrawable failed: ${e.message}")
+            return null
+        }
+    }
+}
diff --git a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/bubbles/ParcelableFlyoutMessage.kt b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/bubbles/ParcelableFlyoutMessage.kt
new file mode 100644
index 0000000..294d5e5
--- /dev/null
+++ b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/bubbles/ParcelableFlyoutMessage.kt
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.shared.bubbles
+
+import android.graphics.drawable.Icon
+import android.os.Parcel
+import android.os.Parcelable
+
+/** The contents of the flyout message to be passed to launcher for rendering in the bubble bar. */
+class ParcelableFlyoutMessage(
+    val icon: Icon?,
+    val title: String?,
+    val message: String?,
+) : Parcelable {
+
+    constructor(
+        parcel: Parcel
+    ) : this(
+        icon = parcel.readParcelable(Icon::class.java.classLoader),
+        title = parcel.readString(),
+        message = parcel.readString(),
+    )
+
+    override fun writeToParcel(parcel: Parcel, flags: Int) {
+        parcel.writeParcelable(icon, flags)
+        parcel.writeString(title)
+        parcel.writeString(message)
+    }
+
+    override fun describeContents() = 0
+
+    companion object {
+        @JvmField
+        val CREATOR =
+            object : Parcelable.Creator<ParcelableFlyoutMessage> {
+                override fun createFromParcel(parcel: Parcel) = ParcelableFlyoutMessage(parcel)
+
+                override fun newArray(size: Int) = arrayOfNulls<ParcelableFlyoutMessage>(size)
+            }
+    }
+}
diff --git a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/DesktopModeStatus.java b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/DesktopModeStatus.java
index 647a555a..0150bcd 100644
--- a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/DesktopModeStatus.java
+++ b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/DesktopModeStatus.java
@@ -19,7 +19,7 @@
 import android.annotation.NonNull;
 import android.content.Context;
 import android.os.SystemProperties;
-import android.window.flags.DesktopModeFlags;
+import android.window.DesktopModeFlags;
 
 import com.android.internal.R;
 import com.android.internal.annotations.VisibleForTesting;
diff --git a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/split/SplitScreenConstants.java b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/split/SplitScreenConstants.java
index 7f1e4a8..61cd1c3 100644
--- a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/split/SplitScreenConstants.java
+++ b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/split/SplitScreenConstants.java
@@ -170,7 +170,7 @@
             SNAP_TO_NONE,
             SNAP_TO_START_AND_DISMISS,
             SNAP_TO_END_AND_DISMISS,
-            SNAP_TO_MINIMIZE
+            SNAP_TO_MINIMIZE,
     })
     public @interface SnapPosition {}
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/apptoweb/AppToWebUtils.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/apptoweb/AppToWebUtils.kt
index 71bcb59..65132fe 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/apptoweb/AppToWebUtils.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/apptoweb/AppToWebUtils.kt
@@ -22,7 +22,13 @@
 import android.content.Intent
 import android.content.Intent.FLAG_ACTIVITY_NEW_TASK
 import android.content.pm.PackageManager
+import android.content.pm.verify.domain.DomainVerificationManager
+import android.content.pm.verify.domain.DomainVerificationUserState
 import android.net.Uri
+import com.android.internal.protolog.ProtoLog
+import com.android.wm.shell.protolog.ShellProtoLogGroup
+
+private const val TAG = "AppToWebUtils"
 
 private val GenericBrowserIntent = Intent()
     .setAction(Intent.ACTION_VIEW)
@@ -58,4 +64,25 @@
     val component = intent.resolveActivity(packageManager) ?: return null
     intent.setComponent(component)
     return intent
-}
\ No newline at end of file
+}
+
+/**
+ * Returns the [DomainVerificationUserState] of the user associated with the given
+ * [DomainVerificationManager] and the given package.
+ */
+fun getDomainVerificationUserState(
+    manager: DomainVerificationManager,
+    packageName: String
+): DomainVerificationUserState? {
+    try {
+        return manager.getDomainVerificationUserState(packageName)
+    } catch (e: PackageManager.NameNotFoundException) {
+        ProtoLog.w(
+            ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE,
+            "%s: Failed to get domain verification user state: %s",
+            TAG,
+            e.message!!
+        )
+        return null
+    }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/apptoweb/OpenByDefaultDialog.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/apptoweb/OpenByDefaultDialog.kt
index 4926cbd..a727b54 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/apptoweb/OpenByDefaultDialog.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/apptoweb/OpenByDefaultDialog.kt
@@ -19,6 +19,7 @@
 import android.app.ActivityManager.RunningTaskInfo
 import android.app.TaskInfo
 import android.content.Context
+import android.content.pm.verify.domain.DomainVerificationManager
 import android.graphics.Bitmap
 import android.graphics.PixelFormat
 import android.view.LayoutInflater
@@ -30,6 +31,7 @@
 import android.view.WindowManager.LayoutParams.TYPE_APPLICATION_PANEL
 import android.view.WindowlessWindowManager
 import android.widget.ImageView
+import android.widget.RadioButton
 import android.widget.TextView
 import android.window.TaskConstants
 import com.android.wm.shell.R
@@ -58,8 +60,17 @@
     private lateinit var appIconView: ImageView
     private lateinit var appNameView: TextView
 
+    private lateinit var openInAppButton: RadioButton
+    private lateinit var openInBrowserButton: RadioButton
+
+    private val domainVerificationManager =
+        context.getSystemService(DomainVerificationManager::class.java)!!
+    private val packageName = taskInfo.baseActivity?.packageName!!
+
+
     init {
         createDialog()
+        initializeRadioButtons()
         bindAppInfo(appIconBitmap, appName)
     }
 
@@ -111,9 +122,30 @@
             closeMenu()
         }
 
+        dialog.setConfirmButtonClickListener {
+            setDefaultLinkHandlingSetting()
+            closeMenu()
+        }
+
         listener.onDialogCreated()
     }
 
+    private fun initializeRadioButtons() {
+        openInAppButton = dialog.requireViewById(R.id.open_in_app_button)
+        openInBrowserButton = dialog.requireViewById(R.id.open_in_browser_button)
+
+        val userState =
+            getDomainVerificationUserState(domainVerificationManager, packageName) ?: return
+        val openInApp = userState.isLinkHandlingAllowed
+        openInAppButton.isChecked = openInApp
+        openInBrowserButton.isChecked = !openInApp
+    }
+
+    private fun setDefaultLinkHandlingSetting() {
+        domainVerificationManager.setDomainVerificationLinkHandlingAllowed(
+            packageName, openInAppButton.isChecked)
+    }
+
     private fun closeMenu() {
         dialogContainer?.releaseView()
         dialogContainer = null
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/apptoweb/OpenByDefaultDialogView.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/apptoweb/OpenByDefaultDialogView.kt
index d03a38e..1b914f4 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/apptoweb/OpenByDefaultDialogView.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/apptoweb/OpenByDefaultDialogView.kt
@@ -36,9 +36,6 @@
     private lateinit var backgroundDim: Drawable
 
     fun setDismissOnClickListener(callback: (View) -> Unit) {
-        val dismissButton = dialogContainer.requireViewById<Button>(
-            R.id.open_by_default_settings_dialog_dismiss_button)
-        dismissButton.setOnClickListener(callback)
         // Clicks on the background dim should also dismiss the dialog.
         setOnClickListener(callback)
         // We add a no-op on-click listener to the dialog container so that clicks on it won't
@@ -46,6 +43,13 @@
         dialogContainer.setOnClickListener { }
     }
 
+    fun setConfirmButtonClickListener(callback: (View) -> Unit) {
+        val dismissButton = dialogContainer.requireViewById<Button>(
+            R.id.open_by_default_settings_dialog_confirm_button
+        )
+        dismissButton.setOnClickListener(callback)
+    }
+
     override fun onFinishInflate() {
         super.onFinishInflate()
         dialogContainer = requireViewById(R.id.open_by_default_dialog_container)
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimation.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimation.java
index df80946..7c5f716 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimation.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimation.java
@@ -33,8 +33,6 @@
      *
      * @param touchX the X touch position of the {@link MotionEvent}.
      * @param touchY the Y touch position of the {@link MotionEvent}.
-     * @param velocityX the X velocity computed from the {@link MotionEvent}.
-     * @param velocityY the Y velocity computed from the {@link MotionEvent}.
      * @param keyAction the original {@link KeyEvent#getAction()} when the event was dispatched to
      *               the process. This is forwarded separately because the input pipeline may mutate
      *               the {#event} action state later.
@@ -43,8 +41,6 @@
     void onBackMotion(
             float touchX,
             float touchY,
-            float velocityX,
-            float velocityY,
             int keyAction,
             @BackEvent.SwipeEdge int swipeEdge);
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
index 5836085..b90e6e2 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
@@ -352,16 +352,12 @@
         public void onBackMotion(
                 float touchX,
                 float touchY,
-                float velocityX,
-                float velocityY,
                 int keyAction,
                 @BackEvent.SwipeEdge int swipeEdge
         ) {
             mShellExecutor.execute(() -> onMotionEvent(
                     /* touchX = */ touchX,
                     /* touchY = */ touchY,
-                    /* velocityX = */ velocityX,
-                    /* velocityY = */ velocityY,
                     /* keyAction = */ keyAction,
                     /* swipeEdge = */ swipeEdge));
         }
@@ -500,14 +496,12 @@
     public void onMotionEvent(
             float touchX,
             float touchY,
-            float velocityX,
-            float velocityY,
             int keyAction,
             @BackEvent.SwipeEdge int swipeEdge) {
 
         BackTouchTracker activeTouchTracker = getActiveTracker();
         if (activeTouchTracker != null) {
-            activeTouchTracker.update(touchX, touchY, velocityX, velocityY);
+            activeTouchTracker.update(touchX, touchY);
         }
 
         // two gestures are waiting to be processed at the moment, skip any further user touches
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java
index 169361a..e3fc5c2 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java
@@ -56,6 +56,7 @@
 import com.android.wm.shell.shared.annotations.ShellBackgroundThread;
 import com.android.wm.shell.shared.annotations.ShellMainThread;
 import com.android.wm.shell.shared.bubbles.BubbleInfo;
+import com.android.wm.shell.shared.bubbles.ParcelableFlyoutMessage;
 
 import java.io.PrintWriter;
 import java.util.List;
@@ -350,7 +351,22 @@
                 getTitle(),
                 getAppName(),
                 isImportantConversation(),
-                !isAppLaunchIntent());
+                !isAppLaunchIntent(),
+                getParcelableFlyoutMessage());
+    }
+
+    /** Creates a parcelable flyout message to send to launcher. */
+    @Nullable
+    private ParcelableFlyoutMessage getParcelableFlyoutMessage() {
+        if (mFlyoutMessage == null) {
+            return null;
+        }
+        // the icon is only used in group chats
+        Icon icon = mFlyoutMessage.isGroupChat ? mFlyoutMessage.senderIcon : null;
+        String title =
+                mFlyoutMessage.senderName == null ? null : mFlyoutMessage.senderName.toString();
+        String message = mFlyoutMessage.message == null ? null : mFlyoutMessage.message.toString();
+        return new ParcelableFlyoutMessage(icon, title, message);
     }
 
     @Override
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleLogger.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleLogger.java
index c88a58b..1abe119 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleLogger.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleLogger.java
@@ -36,6 +36,8 @@
     @VisibleForTesting
     public enum Event implements UiEventLogger.UiEventEnum {
 
+        // region bubble events
+
         @UiEvent(doc = "User dismissed the bubble via gesture, add bubble to overflow.")
         BUBBLE_OVERFLOW_ADD_USER_GESTURE(483),
 
@@ -64,7 +66,89 @@
         BUBBLE_OVERFLOW_SELECTED(600),
 
         @UiEvent(doc = "Restore bubble to overflow after phone reboot.")
-        BUBBLE_OVERFLOW_RECOVER(691);
+        BUBBLE_OVERFLOW_RECOVER(691),
+
+        // endregion
+
+        // region bubble bar events
+
+        @UiEvent(doc = "new bubble posted")
+        BUBBLE_BAR_BUBBLE_POSTED(1927),
+
+        @UiEvent(doc = "existing bubble updated")
+        BUBBLE_BAR_BUBBLE_UPDATED(1928),
+
+        @UiEvent(doc = "expanded a bubble from bubble bar")
+        BUBBLE_BAR_EXPANDED(1929),
+
+        @UiEvent(doc = "bubble bar collapsed")
+        BUBBLE_BAR_COLLAPSED(1930),
+
+        @UiEvent(doc = "dismissed single bubble from bubble bar by dragging it to dismiss target")
+        BUBBLE_BAR_BUBBLE_DISMISSED_DRAG_BUBBLE(1931),
+
+        @UiEvent(doc = "dismissed single bubble from bubble bar by dragging the expanded view to "
+                + "dismiss target")
+        BUBBLE_BAR_BUBBLE_DISMISSED_DRAG_EXP_VIEW(1932),
+
+        @UiEvent(doc = "dismiss bubble from app handle menu")
+        BUBBLE_BAR_BUBBLE_DISMISSED_APP_MENU(1933),
+
+        @UiEvent(doc = "bubble is dismissed due to app finishing the bubble activity")
+        BUBBLE_BAR_BUBBLE_ACTIVITY_FINISH(1934),
+
+        @UiEvent(doc = "dismissed the bubble bar by dragging it to dismiss target")
+        BUBBLE_BAR_DISMISSED_DRAG_BAR(1935),
+
+        @UiEvent(doc = "bubble bar moved to the left edge of the screen by dragging from the "
+                + "expanded view")
+        BUBBLE_BAR_MOVED_LEFT_DRAG_EXP_VIEW(1936),
+
+        @UiEvent(doc = "bubble bar moved to the left edge of the screen by dragging from a single"
+                + " bubble")
+        BUBBLE_BAR_MOVED_LEFT_DRAG_BUBBLE(1937),
+
+        @UiEvent(doc = "bubble bar moved to the left edge of the screen by dragging the bubble bar")
+        BUBBLE_BAR_MOVED_LEFT_DRAG_BAR(1938),
+
+        @UiEvent(doc = "bubble bar moved to the right edge of the screen by dragging from the "
+                + "expanded view")
+        BUBBLE_BAR_MOVED_RIGHT_DRAG_EXP_VIEW(1939),
+
+        @UiEvent(doc = "bubble bar moved to the right edge of the screen by dragging from a "
+                + "single bubble")
+        BUBBLE_BAR_MOVED_RIGHT_DRAG_BUBBLE(1940),
+
+        @UiEvent(doc = "bubble bar moved to the right edge of the screen by dragging the bubble "
+                + "bar")
+        BUBBLE_BAR_MOVED_RIGHT_DRAG_BAR(1941),
+
+        @UiEvent(doc = "stop bubbling conversation from app handle menu")
+        BUBBLE_BAR_APP_MENU_OPT_OUT(1942),
+
+        @UiEvent(doc = "open app settings from app handle menu")
+        BUBBLE_BAR_APP_MENU_GO_TO_SETTINGS(1943),
+
+        @UiEvent(doc = "flyout shown for a bubble")
+        BUBBLE_BAR_FLYOUT(1944),
+
+        @UiEvent(doc = "notification for the bubble was canceled")
+        BUBBLE_BAR_BUBBLE_REMOVED_CANCELED(1945),
+
+        @UiEvent(doc = "user turned off bubbles from settings")
+        BUBBLE_BAR_BUBBLE_REMOVED_BLOCKED(1946),
+
+        @UiEvent(doc = "bubble bar overflow opened")
+        BUBBLE_BAR_OVERFLOW_SELECTED(1947),
+
+        @UiEvent(doc = "max number of bubbles was reached in bubble bar, move bubble to overflow")
+        BUBBLE_BAR_OVERFLOW_ADD_AGED(1948),
+
+        @UiEvent(doc = "bubble promoted from overflow back to bubble bar")
+        BUBBLE_BAR_OVERFLOW_REMOVE_BACK_TO_BAR(1949),
+
+        // endregion
+        ;
 
         private final int mId;
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleViewInfoTask.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleViewInfoTask.java
index 3982a23..39fb2f49 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleViewInfoTask.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleViewInfoTask.java
@@ -21,11 +21,10 @@
 import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_BUBBLES;
 import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_BUBBLES;
+import static com.android.wm.shell.shared.bubbles.FlyoutDrawableLoader.loadFlyoutDrawable;
 
-import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.Context;
-import android.content.Intent;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.ShortcutInfo;
@@ -34,7 +33,6 @@
 import android.graphics.Matrix;
 import android.graphics.Path;
 import android.graphics.drawable.Drawable;
-import android.graphics.drawable.Icon;
 import android.util.Log;
 import android.util.PathParser;
 import android.view.LayoutInflater;
@@ -51,7 +49,6 @@
 import com.android.wm.shell.shared.handles.RegionSamplingHelper;
 
 import java.lang.ref.WeakReference;
-import java.util.Objects;
 import java.util.concurrent.Executor;
 import java.util.concurrent.atomic.AtomicBoolean;
 
@@ -274,7 +271,7 @@
         @Nullable BubbleExpandedView expandedView;
         int dotColor;
         Path dotPath;
-        @Nullable Bubble.FlyoutMessage flyoutMessage;
+        Bubble.FlyoutMessage flyoutMessage;
         Bitmap bubbleBitmap;
         Bitmap badgeBitmap;
 
@@ -300,6 +297,10 @@
                 return null;
             }
 
+            // set the flyout message but don't load the avatar because we can't pass it on the
+            // binder to launcher
+            info.flyoutMessage = b.getFlyoutMessage();
+
             return info;
         }
 
@@ -336,7 +337,7 @@
             info.flyoutMessage = b.getFlyoutMessage();
             if (info.flyoutMessage != null) {
                 info.flyoutMessage.senderAvatar =
-                        loadSenderAvatar(c, info.flyoutMessage.senderIcon);
+                        loadFlyoutDrawable(info.flyoutMessage.senderIcon, c);
             }
             return info;
         }
@@ -418,21 +419,4 @@
                 Color.WHITE, WHITE_SCRIM_ALPHA);
         return true;
     }
-
-    @Nullable
-    static Drawable loadSenderAvatar(@NonNull final Context context, @Nullable final Icon icon) {
-        Objects.requireNonNull(context);
-        if (icon == null) return null;
-        try {
-            if (icon.getType() == Icon.TYPE_URI
-                    || icon.getType() == Icon.TYPE_URI_ADAPTIVE_BITMAP) {
-                context.grantUriPermission(context.getPackageName(),
-                        icon.getUri(), Intent.FLAG_GRANT_READ_URI_PERMISSION);
-            }
-            return icon.loadDrawable(context);
-        } catch (Exception e) {
-            Log.w(TAG, "loadSenderAvatar failed: " + e.getMessage());
-            return null;
-        }
-    }
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleViewInfoTaskLegacy.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleViewInfoTaskLegacy.java
index 1b7bb0d..e9a5933 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleViewInfoTaskLegacy.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleViewInfoTaskLegacy.java
@@ -20,11 +20,10 @@
 import static com.android.wm.shell.bubbles.BadgedImageView.WHITE_SCRIM_ALPHA;
 import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_BUBBLES;
 import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME;
+import static com.android.wm.shell.shared.bubbles.FlyoutDrawableLoader.loadFlyoutDrawable;
 
-import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.Context;
-import android.content.Intent;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.ShortcutInfo;
@@ -33,7 +32,6 @@
 import android.graphics.Matrix;
 import android.graphics.Path;
 import android.graphics.drawable.Drawable;
-import android.graphics.drawable.Icon;
 import android.os.AsyncTask;
 import android.util.Log;
 import android.util.PathParser;
@@ -50,7 +48,6 @@
 import com.android.wm.shell.shared.handles.RegionSamplingHelper;
 
 import java.lang.ref.WeakReference;
-import java.util.Objects;
 import java.util.concurrent.Executor;
 
 /**
@@ -181,7 +178,7 @@
         @Nullable BubbleExpandedView expandedView;
         int dotColor;
         Path dotPath;
-        @Nullable Bubble.FlyoutMessage flyoutMessage;
+        Bubble.FlyoutMessage flyoutMessage;
         Bitmap bubbleBitmap;
         Bitmap badgeBitmap;
 
@@ -221,6 +218,10 @@
                 return null;
             }
 
+            // set the flyout message but don't load the avatar because we can't pass it on the
+            // binder to launcher
+            info.flyoutMessage = b.getFlyoutMessage();
+
             return info;
         }
 
@@ -260,7 +261,7 @@
             info.flyoutMessage = b.getFlyoutMessage();
             if (info.flyoutMessage != null) {
                 info.flyoutMessage.senderAvatar =
-                        loadSenderAvatar(c, info.flyoutMessage.senderIcon);
+                        loadFlyoutDrawable(info.flyoutMessage.senderIcon, c);
             }
             return info;
         }
@@ -342,21 +343,4 @@
                 Color.WHITE, WHITE_SCRIM_ALPHA);
         return true;
     }
-
-    @Nullable
-    static Drawable loadSenderAvatar(@NonNull final Context context, @Nullable final Icon icon) {
-        Objects.requireNonNull(context);
-        if (icon == null) return null;
-        try {
-            if (icon.getType() == Icon.TYPE_URI
-                    || icon.getType() == Icon.TYPE_URI_ADAPTIVE_BITMAP) {
-                context.grantUriPermission(context.getPackageName(),
-                        icon.getUri(), Intent.FLAG_GRANT_READ_URI_PERMISSION);
-            }
-            return icon.loadDrawable(context);
-        } catch (Exception e) {
-            Log.w(TAG, "loadSenderAvatar failed: " + e.getMessage());
-            return null;
-        }
-    }
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipUtils.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipUtils.kt
index b3491ba..b83b5f3 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipUtils.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipUtils.kt
@@ -177,26 +177,84 @@
     }
 
     /**
+     * Calculates the transform to apply on a UNTRANSFORMED (config-at-end) Activity surface in
+     * order for it's hint-rect to occupy the same task-relative position/dimensions as it would
+     * have at the end of the transition (post-configuration).
+     *
+     * This is intended to be used in tandem with [calcStartTransform] below applied to the parent
+     * task. Applying both transforms simultaneously should result in the appearance of nothing
+     * having happened yet.
+     *
+     * Only the task should be animated (into it's identity state) and then WMCore will reset the
+     * activity transform in sync with its new configuration upon finish.
+     *
+     * Usage example:
+     *     calcEndTransform(pipActivity, pipTask, scale, pos);
+     *     t.setScale(pipActivity.getLeash(), scale.x, scale.y);
+     *     t.setPosition(pipActivity.getLeash(), pos.x, pos.y);
+     *
+     * @see calcStartTransform
+     */
+    @JvmStatic
+    fun calcEndTransform(pipActivity: TransitionInfo.Change, pipTask: TransitionInfo.Change,
+        outScale: PointF, outPos: PointF) {
+        val actStartBounds = pipActivity.startAbsBounds
+        val actEndBounds = pipActivity.endAbsBounds
+        val taskEndBounds = pipTask.endAbsBounds
+
+        var hintRect = pipTask.taskInfo?.pictureInPictureParams?.sourceRectHint
+        if (hintRect == null) {
+            hintRect = Rect(actStartBounds)
+            hintRect.offsetTo(0, 0)
+        }
+
+        // FA = final activity bounds (absolute)
+        // FT = final task bounds (absolute)
+        // SA = start activity bounds (absolute)
+        // H = source hint (relative to start activity bounds)
+        // We want to transform the activity so that when the task is at FT, H overlaps with FA
+
+        // This scales the activity such that the hint rect has the same dimensions
+        // as the final activity bounds.
+        val hintToEndScaleX = (actEndBounds.width().toFloat()) / (hintRect.width().toFloat())
+        val hintToEndScaleY = (actEndBounds.height().toFloat()) / (hintRect.height().toFloat())
+        // top-left needs to be (FA.tl - FT.tl) - H.tl * hintToEnd . H is relative to the
+        // activity; so, for example, if shrinking H to FA (hintToEnd < 1), then the tl of the
+        // shrunk SA is closer to H than expected, so we need to reduce how much we offset SA
+        // to get H.tl to match.
+        val startActPosInTaskEndX =
+            (actEndBounds.left - taskEndBounds.left) - hintRect.left * hintToEndScaleX
+        val startActPosInTaskEndY =
+            (actEndBounds.top - taskEndBounds.top) - hintRect.top * hintToEndScaleY
+        outScale.set(hintToEndScaleX, hintToEndScaleY)
+        outPos.set(startActPosInTaskEndX, startActPosInTaskEndY)
+    }
+
+    /**
      * Calculates the transform and crop to apply on a Task surface in order for the config-at-end
      * activity inside it (original-size activity transformed to match it's hint rect to the final
      * Task bounds) to occupy the same world-space position/dimensions as it had before the
      * transition.
      *
+     * Intended to be used in tandem with [calcEndTransform].
+     *
      * Usage example:
-     *     calcStartTransform(pipChange, scale, pos, crop);
-     *     t.setScale(pipChange.getLeash(), scale.x, scale.y);
-     *     t.setPosition(pipChange.getLeash(), pos.x, pos.y);
-     *     t.setCrop(pipChange.getLeash(), crop);
+     *     calcStartTransform(pipTask, scale, pos, crop);
+     *     t.setScale(pipTask.getLeash(), scale.x, scale.y);
+     *     t.setPosition(pipTask.getLeash(), pos.x, pos.y);
+     *     t.setCrop(pipTask.getLeash(), crop);
+     *
+     * @see calcEndTransform
      */
     @JvmStatic
-    fun calcStartTransform(pipChange: TransitionInfo.Change, outScale: PointF,
+    fun calcStartTransform(pipTask: TransitionInfo.Change, outScale: PointF,
         outPos: PointF, outCrop: Rect) {
-        val startBounds = pipChange.startAbsBounds
-        val taskEndBounds = pipChange.endAbsBounds
+        val startBounds = pipTask.startAbsBounds
+        val taskEndBounds = pipTask.endAbsBounds
         // For now, pip activity bounds always matches task bounds. If this ever changes, we'll
         // need to get the activity offset.
         val endBounds = taskEndBounds
-        var hintRect = pipChange.taskInfo?.pictureInPictureParams?.sourceRectHint
+        var hintRect = pipTask.taskInfo?.pictureInPictureParams?.sourceRectHint
         if (hintRect == null) {
             hintRect = Rect(startBounds)
             hintRect.offsetTo(0, 0)
@@ -226,8 +284,8 @@
                 + startBounds.left + hintRect.left)
         val endTaskPosForStartY = (-(endBounds.top - taskEndBounds.top) * endToHintScaleY
                 + startBounds.top + hintRect.top)
-        outScale[endToHintScaleX] = endToHintScaleY
-        outPos[endTaskPosForStartX] = endTaskPosForStartY
+        outScale.set(endToHintScaleX, endToHintScaleY)
+        outPos.set(endTaskPosForStartX, endTaskPosForStartY)
 
         // now need to set crop to reveal the non-hint stuff. Again, hintrect is relative, so
         // we must apply outsets to reveal the *activity* content which is *inside* the task
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIWindowManager.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIWindowManager.java
index 4d15605c..2128cbc 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIWindowManager.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIWindowManager.java
@@ -27,7 +27,7 @@
 import android.util.Pair;
 import android.view.LayoutInflater;
 import android.view.View;
-import android.window.flags.DesktopModeFlags;
+import android.window.DesktopModeFlags;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.window.flags.Flags;
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 e80b95b..52262e6 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
@@ -16,8 +16,8 @@
 
 package com.android.wm.shell.dagger;
 
-import static android.window.flags.DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_EXIT_TRANSITIONS;
-import static android.window.flags.DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_TASK_LIMIT;
+import static android.window.DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_EXIT_TRANSITIONS;
+import static android.window.DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_TASK_LIMIT;
 
 import android.annotation.Nullable;
 import android.app.KeyguardManager;
@@ -71,10 +71,10 @@
 import com.android.wm.shell.desktopmode.DesktopModeEventLogger;
 import com.android.wm.shell.desktopmode.DesktopModeLoggerTransitionObserver;
 import com.android.wm.shell.desktopmode.DesktopRepository;
+import com.android.wm.shell.desktopmode.DesktopTaskChangeListener;
 import com.android.wm.shell.desktopmode.DesktopTasksController;
 import com.android.wm.shell.desktopmode.DesktopTasksLimiter;
 import com.android.wm.shell.desktopmode.DesktopTasksTransitionObserver;
-import com.android.wm.shell.desktopmode.DesktopTaskChangeListener;
 import com.android.wm.shell.desktopmode.DragToDesktopTransitionHandler;
 import com.android.wm.shell.desktopmode.EnterDesktopTaskTransitionHandler;
 import com.android.wm.shell.desktopmode.ExitDesktopTaskTransitionHandler;
@@ -92,9 +92,9 @@
 import com.android.wm.shell.freeform.FreeformTaskListener;
 import com.android.wm.shell.freeform.FreeformTaskTransitionHandler;
 import com.android.wm.shell.freeform.FreeformTaskTransitionObserver;
-import com.android.wm.shell.freeform.TaskChangeListener;
 import com.android.wm.shell.freeform.FreeformTaskTransitionStarter;
 import com.android.wm.shell.freeform.FreeformTaskTransitionStarterInitializer;
+import com.android.wm.shell.freeform.TaskChangeListener;
 import com.android.wm.shell.keyguard.KeyguardTransitionHandler;
 import com.android.wm.shell.onehanded.OneHandedController;
 import com.android.wm.shell.pip.PipTransitionController;
@@ -111,6 +111,7 @@
 import com.android.wm.shell.sysui.ShellInit;
 import com.android.wm.shell.taskview.TaskViewTransitions;
 import com.android.wm.shell.transition.DefaultMixedHandler;
+import com.android.wm.shell.transition.FocusTransitionObserver;
 import com.android.wm.shell.transition.HomeTransitionObserver;
 import com.android.wm.shell.transition.MixedTransitionHandler;
 import com.android.wm.shell.transition.Transitions;
@@ -263,7 +264,8 @@
             Optional<DesktopTasksLimiter> desktopTasksLimiter,
             AppHandleEducationController appHandleEducationController,
             WindowDecorCaptionHandleRepository windowDecorCaptionHandleRepository,
-            Optional<DesktopActivityOrientationChangeHandler> desktopActivityOrientationHandler) {
+            Optional<DesktopActivityOrientationChangeHandler> desktopActivityOrientationHandler,
+            FocusTransitionObserver focusTransitionObserver) {
         if (DesktopModeStatus.canEnterDesktopMode(context)) {
             return new DesktopModeWindowDecorViewModel(
                     context,
@@ -290,7 +292,8 @@
                     desktopTasksLimiter,
                     appHandleEducationController,
                     windowDecorCaptionHandleRepository,
-                    desktopActivityOrientationHandler);
+                    desktopActivityOrientationHandler,
+                    focusTransitionObserver);
         }
         return new CaptionWindowDecorViewModel(
                 context,
@@ -304,7 +307,8 @@
                 displayController,
                 rootTaskDisplayAreaOrganizer,
                 syncQueue,
-                transitions);
+                transitions,
+                focusTransitionObserver);
     }
 
     @WMSingleton
@@ -356,6 +360,7 @@
             ShellInit shellInit,
             ShellTaskOrganizer shellTaskOrganizer,
             Optional<DesktopRepository> desktopRepository,
+            Optional<DesktopTasksController> desktopTasksController,
             LaunchAdjacentController launchAdjacentController,
             WindowDecorViewModel windowDecorViewModel) {
         // TODO(b/238217847): Temporarily add this check here until we can remove the dynamic
@@ -364,7 +369,8 @@
                 ? shellInit
                 : null;
         return new FreeformTaskListener(context, init, shellTaskOrganizer,
-                desktopRepository, launchAdjacentController, windowDecorViewModel);
+                desktopRepository, desktopTasksController, launchAdjacentController,
+                windowDecorViewModel);
     }
 
     @WMSingleton
@@ -389,10 +395,11 @@
             Transitions transitions,
             Optional<DesktopFullImmersiveTransitionHandler> desktopImmersiveTransitionHandler,
             WindowDecorViewModel windowDecorViewModel,
-            Optional<TaskChangeListener> taskChangeListener) {
+            Optional<TaskChangeListener> taskChangeListener,
+            FocusTransitionObserver focusTransitionObserver) {
         return new FreeformTaskTransitionObserver(
                 context, shellInit, transitions, desktopImmersiveTransitionHandler,
-                windowDecorViewModel, taskChangeListener);
+                windowDecorViewModel, taskChangeListener, focusTransitionObserver);
     }
 
     @WMSingleton
@@ -652,7 +659,8 @@
     @WMSingleton
     @Provides
     static Optional<TaskChangeListener> provideDesktopTaskChangeListener(Context context) {
-        if (DesktopModeStatus.canEnterDesktopMode(context)) {
+        if (Flags.enableWindowingTransitionHandlersObservers() &&
+                DesktopModeStatus.canEnterDesktopMode(context)) {
             return Optional.of(new DesktopTaskChangeListener());
         }
         return Optional.empty();
@@ -690,10 +698,16 @@
     static Optional<DesktopFullImmersiveTransitionHandler> provideDesktopImmersiveHandler(
             Context context,
             Transitions transitions,
-            @DynamicOverride DesktopRepository desktopRepository) {
+            @DynamicOverride DesktopRepository desktopRepository,
+            DisplayController displayController,
+            ShellTaskOrganizer shellTaskOrganizer) {
         if (DesktopModeStatus.canEnterDesktopMode(context)) {
             return Optional.of(
-                    new DesktopFullImmersiveTransitionHandler(transitions, desktopRepository));
+                    new DesktopFullImmersiveTransitionHandler(
+                            transitions,
+                            desktopRepository,
+                            displayController,
+                            shellTaskOrganizer));
         }
         return Optional.empty();
     }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip2Module.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip2Module.java
index 702552e..3508ece 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip2Module.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip2Module.java
@@ -127,11 +127,9 @@
     @Provides
     static PipScheduler providePipScheduler(Context context,
             PipBoundsState pipBoundsState,
-            PhonePipMenuController pipMenuController,
             @ShellMainThread ShellExecutor mainExecutor,
             PipTransitionState pipTransitionState) {
-        return new PipScheduler(context, pipBoundsState, pipMenuController,
-                mainExecutor, pipTransitionState);
+        return new PipScheduler(context, pipBoundsState, mainExecutor, pipTransitionState);
     }
 
     @WMSingleton
@@ -140,10 +138,13 @@
             PipBoundsState pipBoundsState, PipMediaController pipMediaController,
             SystemWindows systemWindows,
             PipUiEventLogger pipUiEventLogger,
+            PipTaskListener pipTaskListener,
+            @NonNull PipTransitionState pipTransitionState,
             @ShellMainThread ShellExecutor mainExecutor,
             @ShellMainThread Handler mainHandler) {
         return new PhonePipMenuController(context, pipBoundsState, pipMediaController,
-                systemWindows, pipUiEventLogger, mainExecutor, mainHandler);
+                systemWindows, pipUiEventLogger, pipTaskListener, pipTransitionState, mainExecutor,
+                mainHandler);
     }
 
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopFullImmersiveTransitionHandler.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopFullImmersiveTransitionHandler.kt
index f749aa1..679179a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopFullImmersiveTransitionHandler.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopFullImmersiveTransitionHandler.kt
@@ -27,8 +27,12 @@
 import android.window.TransitionRequestInfo
 import android.window.WindowContainerTransaction
 import androidx.core.animation.addListener
+import com.android.internal.annotations.VisibleForTesting
 import com.android.internal.protolog.ProtoLog
-import com.android.wm.shell.protolog.ShellProtoLogGroup
+import com.android.window.flags.Flags
+import com.android.wm.shell.ShellTaskOrganizer
+import com.android.wm.shell.common.DisplayController
+import com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE
 import com.android.wm.shell.transition.Transitions
 import com.android.wm.shell.transition.Transitions.TransitionHandler
 import com.android.wm.shell.windowdecor.OnTaskResizeAnimationListener
@@ -41,16 +45,29 @@
 class DesktopFullImmersiveTransitionHandler(
     private val transitions: Transitions,
     private val desktopRepository: DesktopRepository,
+    private val displayController: DisplayController,
+    private val shellTaskOrganizer: ShellTaskOrganizer,
     private val transactionSupplier: () -> SurfaceControl.Transaction,
 ) : TransitionHandler {
 
     constructor(
         transitions: Transitions,
         desktopRepository: DesktopRepository,
-    ) : this(transitions, desktopRepository, { SurfaceControl.Transaction() })
+        displayController: DisplayController,
+        shellTaskOrganizer: ShellTaskOrganizer,
+    ) : this(
+        transitions,
+        desktopRepository,
+        displayController,
+        shellTaskOrganizer,
+        { SurfaceControl.Transaction() }
+    )
 
     private var state: TransitionState? = null
 
+    @VisibleForTesting
+    val pendingExternalExitTransitions = mutableSetOf<ExternalPendingExit>()
+
     /** Whether there is an immersive transition that hasn't completed yet. */
     private val inProgress: Boolean
         get() = state != null
@@ -61,15 +78,15 @@
     var onTaskResizeAnimationListener: OnTaskResizeAnimationListener? = null
 
     /** Starts a transition to enter full immersive state inside the desktop. */
-    fun enterImmersive(taskInfo: RunningTaskInfo, wct: WindowContainerTransaction) {
+    fun moveTaskToImmersive(taskInfo: RunningTaskInfo) {
         if (inProgress) {
-            ProtoLog.v(
-                ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE,
-                "FullImmersive: cannot start entry because transition already in progress."
-            )
+            logV("Cannot start entry because transition already in progress.")
             return
         }
-
+        val wct = WindowContainerTransaction().apply {
+            setBounds(taskInfo.token, Rect())
+        }
+        logV("Moving task ${taskInfo.taskId} into immersive mode")
         val transition = transitions.startTransition(TRANSIT_CHANGE, wct, /* handler= */ this)
         state = TransitionState(
             transition = transition,
@@ -79,15 +96,18 @@
         )
     }
 
-    fun exitImmersive(taskInfo: RunningTaskInfo, wct: WindowContainerTransaction) {
+    fun moveTaskToNonImmersive(taskInfo: RunningTaskInfo) {
         if (inProgress) {
-            ProtoLog.v(
-                ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE,
-                "$TAG: cannot start exit because transition already in progress."
-            )
+            logV("Cannot start exit because transition already in progress.")
             return
         }
 
+        val displayLayout = displayController.getDisplayLayout(taskInfo.displayId) ?: return
+        val destinationBounds = calculateMaximizeBounds(displayLayout, taskInfo)
+        val wct = WindowContainerTransaction().apply {
+            setBounds(taskInfo.token, destinationBounds)
+        }
+        logV("Moving task ${taskInfo.taskId} out of immersive mode")
         val transition = transitions.startTransition(TRANSIT_CHANGE, wct, /* handler= */ this)
         state = TransitionState(
             transition = transition,
@@ -97,6 +117,82 @@
         )
     }
 
+    /**
+     * Bring the immersive app of the given [displayId] out of immersive mode, if applicable.
+     *
+     * @param transition that will apply this transaction
+     * @param wct that will apply these changes
+     * @param displayId of the display that should exit immersive mode
+     */
+    fun exitImmersiveIfApplicable(
+        transition: IBinder,
+        wct: WindowContainerTransaction,
+        displayId: Int
+    ) {
+        if (!Flags.enableFullyImmersiveInDesktop()) return
+        exitImmersiveIfApplicable(wct, displayId)?.invoke(transition)
+    }
+
+    /**
+     * Bring the immersive app of the given [displayId] out of immersive mode, if applicable.
+     *
+     * @param wct that will apply these changes
+     * @param displayId of the display that should exit immersive mode
+     * @return a function to apply once the transition that will apply these changes is started
+     */
+    fun exitImmersiveIfApplicable(
+        wct: WindowContainerTransaction,
+        displayId: Int
+    ): ((IBinder) -> Unit)? {
+        if (!Flags.enableFullyImmersiveInDesktop()) return null
+        val displayLayout = displayController.getDisplayLayout(displayId) ?: return null
+        val immersiveTask = desktopRepository.getTaskInFullImmersiveState(displayId) ?: return null
+        val taskInfo = shellTaskOrganizer.getRunningTaskInfo(immersiveTask) ?: return null
+        logV("Appending immersive exit for task: $immersiveTask in display: $displayId")
+        wct.setBounds(taskInfo.token, calculateMaximizeBounds(displayLayout, taskInfo))
+        return { transition -> addPendingImmersiveExit(immersiveTask, displayId, transition) }
+    }
+
+    /**
+     * Bring the given [taskInfo] out of immersive mode, if applicable.
+     *
+     * @param wct that will apply these changes
+     * @param taskInfo of the task that should exit immersive mode
+     * @return a function to apply once the transition that will apply these changes is started
+     */
+    fun exitImmersiveIfApplicable(
+        wct: WindowContainerTransaction,
+        taskInfo: RunningTaskInfo
+    ): ((IBinder) -> Unit)? {
+        if (!Flags.enableFullyImmersiveInDesktop()) return null
+        if (desktopRepository.isTaskInFullImmersiveState(taskInfo.taskId)) {
+            // A full immersive task is being minimized, make sure the immersive state is broken
+            // (i.e. resize back to max bounds).
+            displayController.getDisplayLayout(taskInfo.displayId)?.let { displayLayout ->
+                wct.setBounds(taskInfo.token, calculateMaximizeBounds(displayLayout, taskInfo))
+                logV("Appending immersive exit for task: ${taskInfo.taskId}")
+                return { transition ->
+                    addPendingImmersiveExit(
+                        taskId = taskInfo.taskId,
+                        displayId = taskInfo.displayId,
+                        transition = transition
+                    )
+                }
+            }
+        }
+        return null
+    }
+
+    private fun addPendingImmersiveExit(taskId: Int, displayId: Int, transition: IBinder) {
+        pendingExternalExitTransitions.add(
+            ExternalPendingExit(
+                taskId = taskId,
+                displayId = displayId,
+                transition = transition
+            )
+        )
+    }
+
     override fun startAnimation(
         transition: IBinder,
         info: TransitionInfo,
@@ -190,15 +286,31 @@
      * Called when any transition in the system is ready to play. This is needed to update the
      * repository state before window decorations are drawn (which happens immediately after
      * |onTransitionReady|, before this transition actually animates) because drawing decorations
-     * depends in whether the task is in full immersive state or not.
+     * depends on whether the task is in full immersive state or not.
      */
-    fun onTransitionReady(transition: IBinder) {
+    fun onTransitionReady(transition: IBinder, info: TransitionInfo) {
+        // Check if this is a pending external exit transition.
+        val pendingExit = pendingExternalExitTransitions
+            .firstOrNull { pendingExit -> pendingExit.transition == transition }
+        if (pendingExit != null) {
+            pendingExternalExitTransitions.remove(pendingExit)
+            if (info.hasTaskChange(taskId = pendingExit.taskId)) {
+                if (desktopRepository.isTaskInFullImmersiveState(pendingExit.taskId)) {
+                    logV("Pending external exit for task ${pendingExit.taskId} verified")
+                    desktopRepository.setTaskInFullImmersiveState(
+                        displayId = pendingExit.displayId,
+                        taskId = pendingExit.taskId,
+                        immersive = false
+                    )
+                }
+            }
+            return
+        }
+
+        // Check if this is a direct immersive enter/exit transition.
         val state = this.state ?: return
-        // TODO: b/369443668 - this assumes invoking the exit transition is the only way to exit
-        //  immersive, which isn't realistic. The app could crash, the user could dismiss it from
-        //  overview, etc. This (or its caller) should search all transitions to look for any
-        //  immersive task exiting that state to keep the repository properly updated.
         if (transition == state.transition) {
+            logV("Direct move for task ${state.taskId} in ${state.direction} direction verified")
             when (state.direction) {
                 Direction.ENTER -> {
                     desktopRepository.setTaskInFullImmersiveState(
@@ -225,6 +337,9 @@
     private fun requireState(): TransitionState =
         state ?: error("Expected non-null transition state")
 
+    private fun TransitionInfo.hasTaskChange(taskId: Int): Boolean =
+        changes.any { c -> c.taskInfo?.taskId == taskId }
+
     /** The state of the currently running transition. */
     private data class TransitionState(
         val transition: IBinder,
@@ -233,12 +348,28 @@
         val direction: Direction
     )
 
+    /**
+     * Tracks state of a transition involving an immersive exit that is external to this class' own
+     * transitions. This usually means transitions that exit immersive mode as a side-effect and
+     * not the primary action (for example, minimizing the immersive task or launching a new task
+     * on top of the immersive task).
+     */
+    data class ExternalPendingExit(
+        val taskId: Int,
+        val displayId: Int,
+        val transition: IBinder,
+    )
+
     private enum class Direction {
         ENTER, EXIT
     }
 
+    private fun logV(msg: String, vararg arguments: Any?) {
+        ProtoLog.v(WM_SHELL_DESKTOP_MODE, "%s: $msg", TAG, *arguments)
+    }
+
     private companion object {
-        private const val TAG = "FullImmersiveHandler"
+        private const val TAG = "DesktopImmersive"
 
         private const val FULL_IMMERSIVE_ANIM_DURATION_MS = 336L
     }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeEventLogger.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeEventLogger.kt
index 5a277316f..379e052 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeEventLogger.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeEventLogger.kt
@@ -156,6 +156,21 @@
         )
     }
 
+    fun logTaskInfoStateInit() {
+        logTaskUpdate(
+            FrameworkStatsLog.DESKTOP_MODE_SESSION_TASK_UPDATE__TASK_EVENT__TASK_INIT_STATSD,
+            /* session_id */ 0,
+            TaskUpdate(
+                visibleTaskCount = 0,
+                instanceId = 0,
+                uid = 0,
+                taskHeight = 0,
+                taskWidth = 0,
+                taskX = 0,
+                taskY = 0)
+        )
+    }
+
     private fun logTaskUpdate(taskEvent: Int, sessionId: Int, taskUpdate: TaskUpdate) {
         FrameworkStatsLog.write(
             DESKTOP_MODE_TASK_UPDATE_ATOM_ID,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeLoggerTransitionObserver.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeLoggerTransitionObserver.kt
index 0637474..f847aa89 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeLoggerTransitionObserver.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeLoggerTransitionObserver.kt
@@ -68,9 +68,7 @@
     private val idSequence: InstanceIdSequence by lazy { InstanceIdSequence(Int.MAX_VALUE) }
 
     init {
-        if (
-            Transitions.ENABLE_SHELL_TRANSITIONS && DesktopModeStatus.canEnterDesktopMode(context)
-        ) {
+        if (DesktopModeStatus.canEnterDesktopMode(context)) {
             shellInit.addInitCallback(this::onInit, this)
         }
     }
@@ -101,6 +99,10 @@
 
     fun onInit() {
         transitions.registerObserver(this)
+        SystemProperties.set(
+            VISIBLE_TASKS_COUNTER_SYSTEM_PROPERTY,
+            VISIBLE_TASKS_COUNTER_SYSTEM_PROPERTY_DEFAULT_VALUE)
+        desktopModeEventLogger.logTaskInfoStateInit()
     }
 
     override fun onTransitionReady(
@@ -441,5 +443,6 @@
         @VisibleForTesting
         const val VISIBLE_TASKS_COUNTER_SYSTEM_PROPERTY =
             "debug.tracing." + VISIBLE_TASKS_COUNTER_NAME
+        const val VISIBLE_TASKS_COUNTER_SYSTEM_PROPERTY_DEFAULT_VALUE = "0"
     }
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeUtils.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeUtils.kt
index bd61722..6d47922 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeUtils.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeUtils.kt
@@ -123,6 +123,29 @@
 }
 
 /**
+ * Calculates the maximized bounds of a task given in the given [DisplayLayout], taking
+ * resizability into consideration.
+ */
+fun calculateMaximizeBounds(
+    displayLayout: DisplayLayout,
+    taskInfo: RunningTaskInfo,
+): Rect {
+    val stableBounds = Rect()
+    displayLayout.getStableBounds(stableBounds)
+    if (taskInfo.isResizeable) {
+        // if resizable then expand to entire stable bounds (full display minus insets)
+        return Rect(stableBounds)
+    } else {
+        // if non-resizable then calculate max bounds according to aspect ratio
+        val activityAspectRatio = calculateAspectRatio(taskInfo)
+        val newSize = maximizeSizeGivenAspectRatio(taskInfo,
+            Size(stableBounds.width(), stableBounds.height()), activityAspectRatio)
+        return centerInArea(
+            newSize, stableBounds, stableBounds.left, stableBounds.top)
+    }
+}
+
+/**
  * Calculates the largest size that can fit in a given area while maintaining a specific aspect
  * ratio.
  */
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopRepository.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopRepository.kt
index 7b2a5d3..5ac4ef5 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopRepository.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopRepository.kt
@@ -80,6 +80,14 @@
             freeformTasksInZOrder = ArrayList(freeformTasksInZOrder),
             fullImmersiveTaskId = fullImmersiveTaskId
         )
+        fun clear() {
+            activeTasks.clear()
+            visibleTasks.clear()
+            minimizedTasks.clear()
+            closingTasks.clear()
+            freeformTasksInZOrder.clear()
+            fullImmersiveTaskId = null
+        }
     }
 
     /* Current wallpaper activity token to remove wallpaper activity when last task is removed. */
@@ -320,6 +328,10 @@
         return desktopTaskDataSequence().any { taskId == it.fullImmersiveTaskId }
     }
 
+    /** Returns the task that is currently in immersive mode in this display, or null. */
+    fun getTaskInFullImmersiveState(displayId: Int): Int? =
+        desktopTaskDataByDisplayId.getOrCreate(displayId).fullImmersiveTaskId
+
     private fun notifyVisibleTaskListeners(displayId: Int, visibleTasksCount: Int) {
         visibleTasksListeners.forEach { (listener, executor) ->
             executor.execute { listener.onTasksVisibilityChanged(displayId, visibleTasksCount) }
@@ -414,6 +426,19 @@
     }
 
     /**
+     * Removes the desktop for the given [displayId] and returns the active tasks on that desktop.
+     */
+    fun removeDesktop(displayId: Int): ArraySet<Int> {
+        if (!desktopTaskDataByDisplayId.contains(displayId)) {
+            logW("Could not find desktop to remove: displayId=%d", displayId)
+            return ArraySet()
+        }
+        val activeTasks = ArraySet(desktopTaskDataByDisplayId[displayId].activeTasks)
+        desktopTaskDataByDisplayId[displayId].clear()
+        return activeTasks
+    }
+
+    /**
      * Updates active desktop gesture exclusion regions.
      *
      * If [desktopExclusionRegions] is accepted by [desktopGestureExclusionListener], updates it in
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
index 4e548a6..57a59c9 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
@@ -16,8 +16,8 @@
 
 package com.android.wm.shell.desktopmode
 
-import android.app.ActivityManager.RunningTaskInfo
 import android.app.ActivityManager
+import android.app.ActivityManager.RunningTaskInfo
 import android.app.ActivityOptions
 import android.app.KeyguardManager
 import android.app.PendingIntent
@@ -44,9 +44,14 @@
 import android.view.DragEvent
 import android.view.SurfaceControl
 import android.view.WindowManager.TRANSIT_CHANGE
+import android.view.WindowManager.TRANSIT_CLOSE
 import android.view.WindowManager.TRANSIT_NONE
 import android.view.WindowManager.TRANSIT_OPEN
 import android.view.WindowManager.TRANSIT_TO_FRONT
+import android.window.DesktopModeFlags
+import android.window.DesktopModeFlags.DISABLE_NON_RESIZABLE_APP_SNAP_RESIZE
+import android.window.DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY
+import android.window.DesktopModeFlags.ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS
 import android.window.RemoteTransition
 import android.window.TransitionInfo
 import android.window.TransitionRequestInfo
@@ -86,10 +91,7 @@
 import com.android.wm.shell.shared.TransitionUtil
 import com.android.wm.shell.shared.annotations.ExternalThread
 import com.android.wm.shell.shared.annotations.ShellMainThread
-import android.window.flags.DesktopModeFlags
-import android.window.flags.DesktopModeFlags.DISABLE_NON_RESIZABLE_APP_SNAP_RESIZE
-import android.window.flags.DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY
-import android.window.flags.DesktopModeFlags.ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS
+import com.android.wm.shell.freeform.FreeformTaskTransitionStarter
 import com.android.wm.shell.shared.desktopmode.DesktopModeStatus
 import com.android.wm.shell.shared.desktopmode.DesktopModeStatus.DESKTOP_DENSITY_OVERRIDE
 import com.android.wm.shell.shared.desktopmode.DesktopModeStatus.useDesktopOverrideDensity
@@ -110,6 +112,7 @@
 import com.android.wm.shell.windowdecor.OnTaskResizeAnimationListener
 import com.android.wm.shell.windowdecor.extension.isFullscreen
 import com.android.wm.shell.windowdecor.extension.isMultiWindow
+import com.android.wm.shell.windowdecor.extension.requestingImmersive
 import java.io.PrintWriter
 import java.util.Optional
 import java.util.concurrent.Executor
@@ -188,6 +191,7 @@
 
     private var recentsAnimationRunning = false
     private lateinit var splitScreenController: SplitScreenController
+    lateinit var freeformTaskTransitionStarter: FreeformTaskTransitionStarter
     // Launch cookie used to identify a drag and drop transition to fullscreen after it has begun.
     // Used to prevent handleRequest from moving the new fullscreen task to freeform.
     private var dragAndDropFullscreenCookie: Binder? = null
@@ -260,17 +264,12 @@
         val wct = WindowContainerTransaction()
         bringDesktopAppsToFront(displayId, wct)
 
-        if (Transitions.ENABLE_SHELL_TRANSITIONS) {
-            val transitionType = transitionType(remoteTransition)
-            val handler =
-                remoteTransition?.let {
-                    OneShotRemoteHandler(transitions.mainExecutor, remoteTransition)
-                }
-            transitions.startTransition(transitionType, wct, handler).also { t ->
-                handler?.setTransition(t)
-            }
-        } else {
-            shellTaskOrganizer.applyTransaction(wct)
+        val transitionType = transitionType(remoteTransition)
+        val handler = remoteTransition?.let {
+            OneShotRemoteHandler(transitions.mainExecutor, remoteTransition)
+        }
+        transitions.startTransition(transitionType, wct, handler).also { t ->
+            handler?.setTransition(t)
         }
     }
 
@@ -357,6 +356,8 @@
         // TODO(342378842): Instead of using default display, support multiple displays
         val taskToMinimize = bringDesktopAppsToFrontBeforeShowingNewTask(
             DEFAULT_DISPLAY, wct, taskId)
+        val runOnTransit = immersiveTransitionHandler
+            .exitImmersiveIfApplicable(wct, DEFAULT_DISPLAY)
         wct.startTask(
             taskId,
             ActivityOptions.makeBasic().apply {
@@ -366,6 +367,7 @@
         // TODO(343149901): Add DPI changes for task launch
         val transition = enterDesktopTaskTransitionHandler.moveToDesktop(wct, transitionSource)
         addPendingMinimizeTransition(transition, taskToMinimize)
+        runOnTransit?.invoke(transition)
         return true
     }
 
@@ -382,17 +384,15 @@
         }
         logV("moveRunningTaskToDesktop taskId=%d", task.taskId)
         exitSplitIfApplicable(wct, task)
+        val runOnTransit = immersiveTransitionHandler.exitImmersiveIfApplicable(wct, task.displayId)
         // Bring other apps to front first
         val taskToMinimize =
             bringDesktopAppsToFrontBeforeShowingNewTask(task.displayId, wct, task.taskId)
         addMoveToDesktopChanges(wct, task)
 
-        if (Transitions.ENABLE_SHELL_TRANSITIONS) {
-            val transition = enterDesktopTaskTransitionHandler.moveToDesktop(wct, transitionSource)
-            addPendingMinimizeTransition(transition, taskToMinimize)
-        } else {
-            shellTaskOrganizer.applyTransaction(wct)
-        }
+        val transition = enterDesktopTaskTransitionHandler.moveToDesktop(wct, transitionSource)
+        addPendingMinimizeTransition(transition, taskToMinimize)
+        runOnTransit?.invoke(transition)
     }
 
     /**
@@ -429,8 +429,13 @@
         val taskToMinimize =
             bringDesktopAppsToFrontBeforeShowingNewTask(taskInfo.displayId, wct, taskInfo.taskId)
         addMoveToDesktopChanges(wct, taskInfo)
+        val runOnTransit = immersiveTransitionHandler.exitImmersiveIfApplicable(
+            wct, taskInfo.displayId)
         val transition = dragToDesktopTransitionHandler.finishDragToDesktopTransition(wct)
-        transition?.let { addPendingMinimizeTransition(it, taskToMinimize) }
+        transition?.let {
+            addPendingMinimizeTransition(it, taskToMinimize)
+            runOnTransit?.invoke(transition)
+        }
     }
 
     /**
@@ -460,20 +465,36 @@
             removeWallpaperActivity(wct)
         }
         taskRepository.addClosingTask(displayId, taskId)
+        taskbarDesktopTaskListener?.onTaskbarCornerRoundingUpdate(
+            doesAnyTaskRequireTaskbarRounding(
+                displayId,
+                taskId
+            )
+        )
     }
 
-    /**
-     * Perform clean up of the desktop wallpaper activity if the minimized window task is the last
-     * active task.
-     *
-     * @param wct transaction to modify if the last active task is minimized
-     * @param taskId task id of the window that's being minimized
-     */
-    fun onDesktopWindowMinimize(wct: WindowContainerTransaction, taskId: Int) {
+    fun minimizeTask(taskInfo: RunningTaskInfo) {
+        val taskId = taskInfo.taskId
+        val displayId = taskInfo.displayId
+        val wct = WindowContainerTransaction()
         if (taskRepository.isOnlyVisibleNonClosingTask(taskId)) {
+            // Perform clean up of the desktop wallpaper activity if the minimized window task is
+            // the last active task.
             removeWallpaperActivity(wct)
         }
-        // Do not call taskRepository.minimizeTask because it will be called by DekstopTasksLimiter.
+        // Notify immersive handler as it might need to exit immersive state.
+        val runOnTransit = immersiveTransitionHandler.exitImmersiveIfApplicable(wct, taskInfo)
+
+        wct.reorder(taskInfo.token, false)
+        val transition = freeformTaskTransitionStarter.startMinimizedModeTransition(wct)
+        desktopTasksLimiter.ifPresent {
+            it.addPendingMinimizeChange(
+                transition = transition,
+                displayId = displayId,
+                taskId = taskId
+            )
+        }
+        runOnTransit?.invoke(transition)
     }
 
     /** Move a task with given `taskId` to fullscreen */
@@ -498,11 +519,8 @@
         // Rather than set windowing mode to multi-window at task level, set it to
         // undefined and inherit from split stage.
         wct.setWindowingMode(task.token, WINDOWING_MODE_UNDEFINED)
-        if (Transitions.ENABLE_SHELL_TRANSITIONS) {
-            transitions.startTransition(TRANSIT_CHANGE, wct, null /* handler */)
-        } else {
-            shellTaskOrganizer.applyTransaction(wct)
-        }
+
+        transitions.startTransition(TRANSIT_CHANGE, wct, null /* handler */)
     }
 
     private fun exitSplitIfApplicable(wct: WindowContainerTransaction, taskInfo: RunningTaskInfo) {
@@ -536,17 +554,12 @@
         val wct = WindowContainerTransaction()
         addMoveToFullscreenChanges(wct, task)
 
-        if (Transitions.ENABLE_SHELL_TRANSITIONS) {
-            exitDesktopTaskTransitionHandler.startTransition(
+        exitDesktopTaskTransitionHandler.startTransition(
                 transitionSource,
                 wct,
                 position,
                 mOnAnimationFinishedCallback
             )
-        } else {
-            shellTaskOrganizer.applyTransaction(wct)
-            releaseVisualIndicator()
-        }
     }
 
     /** Move a task to the front */
@@ -566,6 +579,8 @@
         // TODO: b/342378842 - Instead of using default display, support multiple displays
         val taskToMinimize: RunningTaskInfo? =
             addAndGetMinimizeChangesIfNeeded(DEFAULT_DISPLAY, wct, taskId)
+        val runOnTransit = immersiveTransitionHandler
+            .exitImmersiveIfApplicable(wct, DEFAULT_DISPLAY)
         wct.startTask(
             taskId,
             ActivityOptions.makeBasic().apply {
@@ -574,21 +589,22 @@
         )
         val transition = transitions.startTransition(TRANSIT_OPEN, wct, null /* handler */)
         addPendingMinimizeTransition(transition, taskToMinimize)
+        runOnTransit?.invoke(transition)
     }
 
     /** Move a task to the front */
     fun moveTaskToFront(taskInfo: RunningTaskInfo) {
         logV("moveTaskToFront taskId=%s", taskInfo.taskId)
         val wct = WindowContainerTransaction()
-        wct.reorder(taskInfo.token, true)
+        wct.reorder(taskInfo.token, true /* onTop */, true /* includingParents */)
+        val runOnTransit = immersiveTransitionHandler.exitImmersiveIfApplicable(
+            wct, taskInfo.displayId)
         val taskToMinimize =
             addAndGetMinimizeChangesIfNeeded(taskInfo.displayId, wct, taskInfo.taskId)
-        if (Transitions.ENABLE_SHELL_TRANSITIONS) {
-            val transition = transitions.startTransition(TRANSIT_TO_FRONT, wct, null /* handler */)
-            addPendingMinimizeTransition(transition, taskToMinimize)
-        } else {
-            shellTaskOrganizer.applyTransaction(wct)
-        }
+
+        val transition = transitions.startTransition(TRANSIT_TO_FRONT, wct, null /* handler */)
+        addPendingMinimizeTransition(transition, taskToMinimize)
+        runOnTransit?.invoke(transition)
     }
 
     /**
@@ -644,11 +660,8 @@
 
         val wct = WindowContainerTransaction()
         wct.reparent(task.token, displayAreaInfo.token, true /* onTop */)
-        if (Transitions.ENABLE_SHELL_TRANSITIONS) {
-            transitions.startTransition(TRANSIT_CHANGE, wct, null /* handler */)
-        } else {
-            shellTaskOrganizer.applyTransaction(wct)
-        }
+
+        transitions.startTransition(TRANSIT_CHANGE, wct, null /* handler */)
     }
 
     /** Moves a task in/out of full immersive state within the desktop. */
@@ -662,22 +675,12 @@
 
     private fun moveDesktopTaskToFullImmersive(taskInfo: RunningTaskInfo) {
         check(taskInfo.isFreeform) { "Task must already be in freeform" }
-        val wct = WindowContainerTransaction().apply {
-            setBounds(taskInfo.token, Rect())
-        }
-        immersiveTransitionHandler.enterImmersive(taskInfo, wct)
+        immersiveTransitionHandler.moveTaskToImmersive(taskInfo)
     }
 
     private fun exitDesktopTaskFromFullImmersive(taskInfo: RunningTaskInfo) {
         check(taskInfo.isFreeform) { "Task must already be in freeform" }
-        val displayLayout = displayController.getDisplayLayout(taskInfo.displayId) ?: return
-        val stableBounds = Rect().apply { displayLayout.getStableBounds(this) }
-        val destinationBounds = getMaximizeBounds(taskInfo, stableBounds)
-
-        val wct = WindowContainerTransaction().apply {
-            setBounds(taskInfo.token, destinationBounds)
-        }
-        immersiveTransitionHandler.exitImmersive(taskInfo, wct)
+        immersiveTransitionHandler.moveTaskToNonImmersive(taskInfo)
     }
 
     /**
@@ -716,7 +719,7 @@
             // and toggle to the stable bounds.
             taskRepository.saveBoundsBeforeMaximize(taskInfo.taskId, currentTaskBounds)
 
-            destinationBounds.set(getMaximizeBounds(taskInfo, stableBounds))
+            destinationBounds.set(calculateMaximizeBounds(displayLayout, taskInfo))
         }
 
 
@@ -732,11 +735,8 @@
 
         taskbarDesktopTaskListener?.onTaskbarCornerRoundingUpdate(doesAnyTaskRequireTaskbarRounding)
         val wct = WindowContainerTransaction().setBounds(taskInfo.token, destinationBounds)
-        if (Transitions.ENABLE_SHELL_TRANSITIONS) {
-            toggleResizeDesktopTaskTransitionHandler.startTransition(wct)
-        } else {
-            shellTaskOrganizer.applyTransaction(wct)
-        }
+
+        toggleResizeDesktopTaskTransitionHandler.startTransition(wct)
     }
 
     private fun getMaximizeBounds(taskInfo: RunningTaskInfo, stableBounds: Rect): Rect {
@@ -846,11 +846,8 @@
 
         taskbarDesktopTaskListener?.onTaskbarCornerRoundingUpdate(true)
         val wct = WindowContainerTransaction().setBounds(taskInfo.token, destinationBounds)
-        if (Transitions.ENABLE_SHELL_TRANSITIONS) {
-            toggleResizeDesktopTaskTransitionHandler.startTransition(wct, currentDragBounds)
-        } else {
-            shellTaskOrganizer.applyTransaction(wct)
-        }
+
+        toggleResizeDesktopTaskTransitionHandler.startTransition(wct, currentDragBounds)
     }
 
     @VisibleForTesting
@@ -1245,10 +1242,23 @@
                 error("Invalid windowing mode: ${callingTask.windowingMode}")
             }
         }
+        val bounds = when (newTaskWindowingMode) {
+            WINDOWING_MODE_FREEFORM -> {
+                displayController.getDisplayLayout(callingTask.displayId)
+                    ?.let { getInitialBounds(it, callingTask) }
+            }
+            WINDOWING_MODE_MULTI_WINDOW -> {
+                Rect()
+            }
+            else -> {
+                error("Invalid windowing mode: $newTaskWindowingMode")
+            }
+        }
         return ActivityOptions.makeBasic().apply {
             launchWindowingMode = newTaskWindowingMode
             pendingIntentBackgroundActivityStartMode =
                 ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOW_ALWAYS
+            launchBounds = bounds
         }
     }
 
@@ -1308,8 +1318,10 @@
         if (useDesktopOverrideDensity()) {
             wct.setDensityDpi(task.token, DESKTOP_DENSITY_OVERRIDE)
         }
-        // Desktop Mode is showing and we're launching a new Task - we might need to minimize
-        // a Task.
+        // Desktop Mode is showing and we're launching a new Task:
+        // 1) Exit immersive if needed.
+        immersiveTransitionHandler.exitImmersiveIfApplicable(transition, wct, task.displayId)
+        // 2) minimize a Task if needed.
         val taskToMinimize = addAndGetMinimizeChangesIfNeeded(task.displayId, wct, task.taskId)
         if (taskToMinimize != null) {
             addPendingMinimizeTransition(transition, taskToMinimize)
@@ -1339,6 +1351,9 @@
                 val taskToMinimize =
                     addAndGetMinimizeChangesIfNeeded(task.displayId, wct, task.taskId)
                 addPendingMinimizeTransition(transition, taskToMinimize)
+                immersiveTransitionHandler.exitImmersiveIfApplicable(
+                    transition, wct, task.displayId
+                )
             }
         }
         return null
@@ -1399,15 +1414,7 @@
             } else {
                 WINDOWING_MODE_FREEFORM
             }
-        val initialBounds = if (ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS.isTrue()) {
-            calculateInitialBounds(displayLayout, taskInfo)
-        } else {
-            getDefaultDesktopTaskBounds(displayLayout)
-        }
-
-        if (DesktopModeFlags.ENABLE_CASCADING_WINDOWS.isTrue()) {
-            cascadeWindow(taskInfo, initialBounds, displayLayout)
-        }
+        val initialBounds = getInitialBounds(displayLayout, taskInfo)
 
         if (canChangeTaskPosition(taskInfo)) {
             wct.setBounds(taskInfo.token, initialBounds)
@@ -1419,6 +1426,22 @@
         }
     }
 
+    private fun getInitialBounds(
+        displayLayout: DisplayLayout,
+        taskInfo: RunningTaskInfo
+    ): Rect {
+        val bounds = if (ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS.isTrue) {
+            calculateInitialBounds(displayLayout, taskInfo)
+        } else {
+            getDefaultDesktopTaskBounds(displayLayout)
+        }
+
+        if (DesktopModeFlags.ENABLE_CASCADING_WINDOWS.isTrue) {
+            cascadeWindow(taskInfo, bounds, displayLayout)
+        }
+        return bounds
+    }
+
     private fun addMoveToFullscreenChanges(
         wct: WindowContainerTransaction,
         taskInfo: RunningTaskInfo
@@ -1497,6 +1520,22 @@
         }
     }
 
+    fun removeDesktop(displayId: Int) {
+        if (!DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_BACK_NAVIGATION.isTrue()) return
+
+        val tasksToRemove = taskRepository.removeDesktop(displayId)
+        val wct = WindowContainerTransaction()
+        tasksToRemove.forEach {
+            val task = shellTaskOrganizer.getRunningTaskInfo(it)
+            if (task != null) {
+                wct.removeTask(task.token)
+            } else {
+                recentTasksController?.removeBackgroundTask(it)
+            }
+        }
+        if (!wct.isEmpty) transitions.startTransition(TRANSIT_CLOSE, wct, null)
+    }
+
     /** Enter split by using the focused desktop task in given `displayId`. */
     fun enterSplit(displayId: Int, leftOrTop: Boolean) {
         getFocusedFreeformTask(displayId)?.let { requestSplit(it, leftOrTop) }
@@ -1844,6 +1883,17 @@
         userId = newUserId
     }
 
+    /** Called when a task's info changes. */
+    fun onTaskInfoChanged(taskInfo: RunningTaskInfo) {
+        if (!Flags.enableFullyImmersiveInDesktop()) return
+        val inImmersive = taskRepository.isTaskInFullImmersiveState(taskInfo.taskId)
+        val requestingImmersive = taskInfo.requestingImmersive
+        if (inImmersive && !requestingImmersive) {
+            // Exit immersive if the app is no longer requesting it.
+            exitDesktopTaskFromFullImmersive(taskInfo)
+        }
+    }
+
     private fun dump(pw: PrintWriter, prefix: String) {
         val innerPrefix = "$prefix  "
         pw.println("${prefix}DesktopTasksController")
@@ -2013,6 +2063,12 @@
                 c.moveTaskToDesktop(taskId, transitionSource = transitionSource)
             }
         }
+
+        override fun removeDesktop(displayId: Int) {
+            executeRemoteCallWithTaskPermission(controller, "removeDesktop") { c ->
+                c.removeDesktop(displayId)
+            }
+        }
     }
 
     private fun logV(msg: String, vararg arguments: Any?) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksLimiter.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksLimiter.kt
index 37bec21..d6b7212 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksLimiter.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksLimiter.kt
@@ -24,7 +24,7 @@
 import android.view.WindowManager.TRANSIT_TO_BACK
 import android.window.TransitionInfo
 import android.window.WindowContainerTransaction
-import android.window.flags.DesktopModeFlags
+import android.window.DesktopModeFlags
 import androidx.annotation.VisibleForTesting
 import com.android.internal.jank.Cuj.CUJ_DESKTOP_MODE_MINIMIZE_WINDOW
 import com.android.internal.jank.InteractionJankMonitor
@@ -39,7 +39,7 @@
  * Limits the number of tasks shown in Desktop Mode.
  *
  * This class should only be used if
- * [android.window.flags.DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_TASK_LIMIT]
+ * [android.window.DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_TASK_LIMIT]
  * is enabled and [maxTasksLimit] is strictly greater than 0.
  */
 class DesktopTasksLimiter (
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksTransitionObserver.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksTransitionObserver.kt
index e086e40..0b1bb8f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksTransitionObserver.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksTransitionObserver.kt
@@ -21,11 +21,12 @@
 import android.os.IBinder
 import android.view.SurfaceControl
 import android.view.WindowManager
+import android.view.WindowManager.TRANSIT_CLOSE
 import android.view.WindowManager.TRANSIT_TO_BACK
 import android.window.TransitionInfo
 import android.window.WindowContainerTransaction
-import android.window.flags.DesktopModeFlags
-import android.window.flags.DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY
+import android.window.DesktopModeFlags
+import android.window.DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY
 import com.android.internal.protolog.ProtoLog
 import com.android.wm.shell.ShellTaskOrganizer
 import com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE
@@ -36,8 +37,8 @@
 
 /**
  * A [Transitions.TransitionObserver] that observes shell transitions and updates the
- * [DesktopRepository] state TODO: b/332682201 This observes transitions related to desktop
- * mode and other transitions that originate both within and outside shell.
+ * [DesktopRepository] state TODO: b/332682201 This observes transitions related to desktop mode and
+ * other transitions that originate both within and outside shell.
  */
 class DesktopTasksTransitionObserver(
     private val context: Context,
@@ -47,10 +48,10 @@
     shellInit: ShellInit
 ) : Transitions.TransitionObserver {
 
+    private var transitionToCloseWallpaper: IBinder? = null
+
     init {
-        if (
-            Transitions.ENABLE_SHELL_TRANSITIONS && DesktopModeStatus.canEnterDesktopMode(context)
-        ) {
+        if (DesktopModeStatus.canEnterDesktopMode(context)) {
             shellInit.addInitCallback(::onInit, this)
         }
     }
@@ -72,6 +73,7 @@
             handleBackNavigation(info)
             removeTaskIfNeeded(info)
         }
+        removeWallpaperOnLastTaskClosingIfNeeded(transition, info)
     }
 
     private fun removeTaskIfNeeded(info: TransitionInfo) {
@@ -83,13 +85,9 @@
             val taskInfo = change.taskInfo
             if (taskInfo == null || taskInfo.taskId == -1) continue
 
-            if (desktopRepository.isActiveTask(taskInfo.taskId)
-                && taskInfo.windowingMode != WINDOWING_MODE_FREEFORM
-            ) {
-                desktopRepository.removeFreeformTask(
-                    taskInfo.displayId,
-                    taskInfo.taskId
-                )
+            if (desktopRepository.isActiveTask(taskInfo.taskId) &&
+                taskInfo.windowingMode != WINDOWING_MODE_FREEFORM) {
+                desktopRepository.removeFreeformTask(taskInfo.displayId, taskInfo.taskId)
             }
         }
     }
@@ -106,14 +104,32 @@
 
                 if (desktopRepository.getVisibleTaskCount(taskInfo.displayId) > 0 &&
                     change.mode == TRANSIT_TO_BACK &&
-                    taskInfo.windowingMode == WINDOWING_MODE_FREEFORM
-                ) {
+                    taskInfo.windowingMode == WINDOWING_MODE_FREEFORM) {
                     desktopRepository.minimizeTask(taskInfo.displayId, taskInfo.taskId)
                 }
             }
         }
     }
 
+    private fun removeWallpaperOnLastTaskClosingIfNeeded(
+        transition: IBinder,
+        info: TransitionInfo
+    ) {
+        for (change in info.changes) {
+            val taskInfo = change.taskInfo
+            if (taskInfo == null || taskInfo.taskId == -1) {
+                continue
+            }
+
+            if (desktopRepository.getVisibleTaskCount(taskInfo.displayId) == 1 &&
+                change.mode == TRANSIT_CLOSE &&
+                taskInfo.windowingMode == WINDOWING_MODE_FREEFORM &&
+                desktopRepository.wallpaperActivityToken != null) {
+                transitionToCloseWallpaper = transition
+            }
+        }
+    }
+
     override fun onTransitionStarting(transition: IBinder) {
         // TODO: b/332682201 Update repository state
     }
@@ -124,6 +140,16 @@
 
     override fun onTransitionFinished(transition: IBinder, aborted: Boolean) {
         // TODO: b/332682201 Update repository state
+        if (transitionToCloseWallpaper == transition) {
+            // TODO: b/362469671 - Handle merging the animation when desktop is also closing.
+            desktopRepository.wallpaperActivityToken?.let { wallpaperActivityToken ->
+                transitions.startTransition(
+                    TRANSIT_CLOSE,
+                    WindowContainerTransaction().removeTask(wallpaperActivityToken),
+                    null)
+            }
+            transitionToCloseWallpaper = null
+        }
     }
 
     private fun updateWallpaperToken(info: TransitionInfo) {
@@ -141,10 +167,9 @@
                             // task.
                             shellTaskOrganizer.applyTransaction(
                                 WindowContainerTransaction()
-                                    .setTaskTrimmableFromRecents(taskInfo.token, false)
-                            )
+                                    .setTaskTrimmableFromRecents(taskInfo.token, false))
                         }
-                        WindowManager.TRANSIT_CLOSE ->
+                        TRANSIT_CLOSE ->
                             desktopRepository.wallpaperActivityToken = null
                         else -> {}
                     }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/IDesktopMode.aidl b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/IDesktopMode.aidl
index b036e40e..86351e3 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/IDesktopMode.aidl
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/IDesktopMode.aidl
@@ -49,4 +49,7 @@
 
     /** Move a task with given `taskId` to desktop */
     void moveToDesktop(int taskId, in DesktopModeTransitionSource transitionSource);
+
+    /** Remove desktop on the given display */
+    oneway void removeDesktop(int displayId);
 }
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java
index dfa2437..5c72cb7 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java
@@ -23,6 +23,7 @@
 import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
 import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION;
 
+import static com.android.wm.shell.Flags.enableFlexibleSplit;
 import static com.android.wm.shell.draganddrop.SplitDragPolicy.Target.TYPE_SPLIT_BOTTOM;
 import static com.android.wm.shell.draganddrop.SplitDragPolicy.Target.TYPE_SPLIT_LEFT;
 import static com.android.wm.shell.draganddrop.SplitDragPolicy.Target.TYPE_SPLIT_RIGHT;
@@ -43,14 +44,18 @@
 import android.graphics.Insets;
 import android.graphics.Point;
 import android.graphics.Rect;
+import android.graphics.RectF;
 import android.graphics.Region;
 import android.graphics.drawable.Drawable;
+import android.util.Log;
 import android.view.DragEvent;
 import android.view.SurfaceControl;
+import android.view.View;
 import android.view.ViewGroup;
 import android.view.ViewTreeObserver;
 import android.view.WindowInsets;
 import android.view.WindowInsets.Type;
+import android.widget.FrameLayout;
 import android.widget.LinearLayout;
 import android.window.WindowContainerToken;
 
@@ -67,14 +72,22 @@
 import com.android.wm.shell.splitscreen.SplitScreenController;
 
 import java.io.PrintWriter;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.function.BiConsumer;
 
 /**
  * Coordinates the visible drop targets for the current drag within a single display.
  */
 public class DragLayout extends LinearLayout
-        implements ViewTreeObserver.OnComputeInternalInsetsListener, DragLayoutProvider {
+        implements ViewTreeObserver.OnComputeInternalInsetsListener, DragLayoutProvider,
+        DragZoneAnimator{
 
+    static final boolean DEBUG_LAYOUT = false;
     // While dragging the status bar is hidden.
     private static final int HIDE_STATUS_BAR_FLAGS = StatusBarManager.DISABLE_NOTIFICATION_ICONS
             | StatusBarManager.DISABLE_NOTIFICATION_ALERTS
@@ -108,13 +121,19 @@
     // The last position that was handled by the drag layout
     private final Point mLastPosition = new Point();
 
+    // Used with enableFlexibleSplit() flag
+    private List<SplitDragPolicy.Target> mTargets;
+    private Map<SplitDragPolicy.Target, DropZoneView> mTargetDropMap = new HashMap<>();
+    private FrameLayout mAnimatingRootLayout;
+    // Used with enableFlexibleSplit() flag
+
     @SuppressLint("WrongConstant")
     public DragLayout(Context context, SplitScreenController splitScreenController,
             IconProvider iconProvider) {
         super(context);
         mSplitScreenController = splitScreenController;
         mIconProvider = iconProvider;
-        mPolicy = new SplitDragPolicy(context, splitScreenController);
+        mPolicy = new SplitDragPolicy(context, splitScreenController, this);
         mStatusBarManager = context.getSystemService(StatusBarManager.class);
         mLastConfiguration.setTo(context.getResources().getConfiguration());
 
@@ -211,11 +230,26 @@
         boolean isLeftRightSplit = mSplitScreenController != null
                 && mSplitScreenController.isLeftRightSplit();
         if (isLeftRightSplit) {
-            mDropZoneView1.setBottomInset(mInsets.bottom);
-            mDropZoneView2.setBottomInset(mInsets.bottom);
+            if (enableFlexibleSplit()) {
+                mTargetDropMap.values().forEach(dzv -> dzv.setBottomInset(mInsets.bottom));
+            } else {
+                mDropZoneView1.setBottomInset(mInsets.bottom);
+                mDropZoneView2.setBottomInset(mInsets.bottom);
+            }
         } else {
-            mDropZoneView1.setBottomInset(0);
-            mDropZoneView2.setBottomInset(mInsets.bottom);
+            if (enableFlexibleSplit()) {
+                Collection<DropZoneView> dropViews = mTargetDropMap.values();
+                final DropZoneView[] bottomView = {null};
+                dropViews.forEach(dropZoneView -> {
+                    bottomView[0] = dropZoneView;
+                    dropZoneView.setBottomInset(0);
+                });
+                // TODO(b/349828130): necessary? maybe with UI polish
+                //  bottomView[0].setBottomInset(mInsets.bottom);
+            } else {
+                mDropZoneView1.setBottomInset(0);
+                mDropZoneView2.setBottomInset(mInsets.bottom);
+            }
         }
         return super.onApplyWindowInsets(insets);
     }
@@ -233,17 +267,31 @@
         final boolean themeChanged = (diff & CONFIG_ASSETS_PATHS) != 0
                 || (diff & CONFIG_UI_MODE) != 0;
         if (themeChanged) {
-            mDropZoneView1.onThemeChange();
-            mDropZoneView2.onThemeChange();
+            if (enableFlexibleSplit()) {
+                mTargetDropMap.values().forEach(DropZoneView::onThemeChange);
+            } else {
+                mDropZoneView1.onThemeChange();
+                mDropZoneView2.onThemeChange();
+            }
         }
         mLastConfiguration.setTo(newConfig);
         requestLayout();
     }
 
     private void updateContainerMarginsForSingleTask() {
-        mDropZoneView1.setContainerMargin(
-                mDisplayMargin, mDisplayMargin, mDisplayMargin, mDisplayMargin);
-        mDropZoneView2.setContainerMargin(0, 0, 0, 0);
+        if (enableFlexibleSplit()) {
+            DropZoneView firstDropZone = mTargetDropMap.values().stream().findFirst().get();
+            mTargetDropMap.values().stream()
+                    .filter(dropZoneView -> dropZoneView != firstDropZone)
+                    .forEach(dropZoneView -> dropZoneView.setContainerMargin(0, 0, 0, 0));
+            firstDropZone.setContainerMargin(
+                    mDisplayMargin, mDisplayMargin, mDisplayMargin, mDisplayMargin
+            );
+        } else {
+            mDropZoneView1.setContainerMargin(
+                    mDisplayMargin, mDisplayMargin, mDisplayMargin, mDisplayMargin);
+            mDropZoneView2.setContainerMargin(0, 0, 0, 0);
+        }
     }
 
     private void updateContainerMargins(boolean isLeftRightSplit) {
@@ -306,19 +354,35 @@
                 }
             }
         } else {
-            // We're already in split so get taskInfo from the controller to populate icon / color.
-            ActivityManager.RunningTaskInfo topOrLeftTask =
-                    mSplitScreenController.getTaskInfo(SPLIT_POSITION_TOP_OR_LEFT);
-            ActivityManager.RunningTaskInfo bottomOrRightTask =
-                    mSplitScreenController.getTaskInfo(SPLIT_POSITION_BOTTOM_OR_RIGHT);
-            if (topOrLeftTask != null && bottomOrRightTask != null) {
-                Drawable topOrLeftIcon = mIconProvider.getIcon(topOrLeftTask.topActivityInfo);
-                int topOrLeftColor = getResizingBackgroundColor(topOrLeftTask);
-                Drawable bottomOrRightIcon = mIconProvider.getIcon(
-                        bottomOrRightTask.topActivityInfo);
-                int bottomOrRightColor = getResizingBackgroundColor(bottomOrRightTask);
-                mDropZoneView1.setAppInfo(topOrLeftColor, topOrLeftIcon);
-                mDropZoneView2.setAppInfo(bottomOrRightColor, bottomOrRightIcon);
+            ActivityManager.RunningTaskInfo[] taskInfos = mSplitScreenController.getAllTaskInfos();
+            boolean anyTasksNull = Arrays.stream(taskInfos).anyMatch(Objects::isNull);
+            if (enableFlexibleSplit() && taskInfos != null && !anyTasksNull) {
+                int i = 0;
+                for (DropZoneView v : mTargetDropMap.values()) {
+                    if (i >= taskInfos.length) {
+                        // TODO(b/349828130) Support once we add 3 StageRoots
+                        continue;
+                    }
+                    ActivityManager.RunningTaskInfo task = taskInfos[i];
+                    v.setAppInfo(getResizingBackgroundColor(task),
+                            mIconProvider.getIcon(task.topActivityInfo));
+                    i++;
+                }
+            } else {
+                // We're already in split so get taskInfo from the controller to populate icon / color.
+                ActivityManager.RunningTaskInfo topOrLeftTask =
+                        mSplitScreenController.getTaskInfo(SPLIT_POSITION_TOP_OR_LEFT);
+                ActivityManager.RunningTaskInfo bottomOrRightTask =
+                        mSplitScreenController.getTaskInfo(SPLIT_POSITION_BOTTOM_OR_RIGHT);
+                if (topOrLeftTask != null && bottomOrRightTask != null) {
+                    Drawable topOrLeftIcon = mIconProvider.getIcon(topOrLeftTask.topActivityInfo);
+                    int topOrLeftColor = getResizingBackgroundColor(topOrLeftTask);
+                    Drawable bottomOrRightIcon = mIconProvider.getIcon(
+                            bottomOrRightTask.topActivityInfo);
+                    int bottomOrRightColor = getResizingBackgroundColor(bottomOrRightTask);
+                    mDropZoneView1.setAppInfo(topOrLeftColor, topOrLeftIcon);
+                    mDropZoneView2.setAppInfo(bottomOrRightColor, bottomOrRightIcon);
+                }
             }
 
             // Update the dropzones to match existing split sizes
@@ -391,7 +455,14 @@
     @NonNull
     @Override
     public void addDraggingView(ViewGroup rootView) {
-        // TODO(b/349828130) We need to separate out view + logic here
+        if (enableFlexibleSplit()) {
+            removeAllViews();
+            mAnimatingRootLayout = new FrameLayout(getContext());
+            addView(mAnimatingRootLayout,
+                    new LinearLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT));
+            ((LayoutParams) mAnimatingRootLayout.getLayoutParams()).weight = 1;
+        }
+
         rootView.addView(this, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
     }
 
@@ -409,6 +480,24 @@
             // Inset the draw region by a little bit
             target.drawRegion.inset(mDisplayMargin, mDisplayMargin);
         }
+
+        if (enableFlexibleSplit()) {
+            mTargets = targets;
+            mTargetDropMap.clear();
+            for (int i = 0; i < mTargets.size(); i++) {
+                DropZoneView v = new DropZoneView(getContext());
+                SplitDragPolicy.Target t = mTargets.get(i);
+                FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(t.drawRegion.width(),
+                        t.drawRegion.height());
+                mAnimatingRootLayout.addView(v, params);
+                v.setTranslationX(t.drawRegion.left);
+                v.setTranslationY(t.drawRegion.top);
+                mTargetDropMap.put(t, v);
+                if (DEBUG_LAYOUT) {
+                    v.setDebugIndex(t.index);
+                }
+            }
+        }
     }
 
     /**
@@ -433,6 +522,9 @@
             if (target == null) {
                 // Animating to no target
                 animateSplitContainers(false, null /* animCompleteCallback */);
+                if (enableFlexibleSplit()) {
+                    animateHighlight(target);
+                }
             } else if (mCurrentTarget == null) {
                 if (mPolicy.getNumTargets() == 1) {
                     animateFullscreenContainer(true);
@@ -440,10 +532,14 @@
                     animateSplitContainers(true, null /* animCompleteCallback */);
                     animateHighlight(target);
                 }
-            } else if (mCurrentTarget.type != target.type) {
+            } else if (mCurrentTarget.type != target.type || enableFlexibleSplit()) {
                 // Switching between targets
-                mDropZoneView1.animateSwitch();
-                mDropZoneView2.animateSwitch();
+                if (enableFlexibleSplit()) {
+                    animateHighlight(target);
+                } else {
+                    mDropZoneView1.animateSwitch();
+                    mDropZoneView2.animateSwitch();
+                }
                 // Announce for accessibility.
                 switch (target.type) {
                     case TYPE_SPLIT_LEFT:
@@ -490,6 +586,9 @@
         mDropZoneView2.setForceIgnoreBottomMargin(false);
         updateContainerMargins(mIsLeftRightSplit);
         mCurrentTarget = null;
+        if (enableFlexibleSplit()) {
+            mAnimatingRootLayout.removeAllViews();
+        }
     }
 
     /**
@@ -566,9 +665,20 @@
         mStatusBarManager.disable(visible
                 ? HIDE_STATUS_BAR_FLAGS
                 : DISABLE_NONE);
-        mDropZoneView1.setShowingMargin(visible);
-        mDropZoneView2.setShowingMargin(visible);
-        Animator animator = mDropZoneView1.getAnimator();
+        Animator animator;
+        if (enableFlexibleSplit()) {
+            DropZoneView anyDropZoneView = null;
+            for (DropZoneView dz : mTargetDropMap.values()) {
+                dz.setShowingMargin(visible);
+                anyDropZoneView = dz;
+            }
+            animator = anyDropZoneView != null ? anyDropZoneView.getAnimator() : null;
+        } else {
+            mDropZoneView1.setShowingMargin(visible);
+            mDropZoneView2.setShowingMargin(visible);
+            animator = mDropZoneView1.getAnimator();
+        }
+
         if (animCompleteCallback != null) {
             if (animator != null) {
                 animator.addListener(new AnimatorListenerAdapter() {
@@ -584,7 +694,24 @@
         }
     }
 
+    @Override
+    public void animateDragTargets(
+            @NonNull List<? extends BiConsumer<SplitDragPolicy.Target, View>> viewsToAnimate) {
+        for (Map.Entry<SplitDragPolicy.Target, DropZoneView> entry : mTargetDropMap.entrySet()) {
+            viewsToAnimate.get(0).accept(entry.getKey(), entry.getValue());
+        }
+    }
+
     private void animateHighlight(SplitDragPolicy.Target target) {
+        if (enableFlexibleSplit()) {
+            for (Map.Entry<SplitDragPolicy.Target, DropZoneView> dzv : mTargetDropMap.entrySet()) {
+                // Highlight the view w/ the matching target, unhighlight the rest
+                dzv.getValue().setShowingHighlight(dzv.getKey() == target);
+            }
+            mPolicy.onHoveringOver(target);
+            return;
+        }
+
         if (target.type == TYPE_SPLIT_LEFT || target.type == TYPE_SPLIT_TOP) {
             mDropZoneView1.setShowingHighlight(true);
             mDropZoneView2.setShowingHighlight(false);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragZoneAnimator.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragZoneAnimator.kt
new file mode 100644
index 0000000..240465d
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragZoneAnimator.kt
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.draganddrop
+
+import android.view.View
+import java.util.function.BiConsumer
+
+interface DragZoneAnimator {
+    /**
+     * Each consumer will be called for the corresponding DropZoneView.
+     * This must match the number of targets in [.mTargets] otherwise will
+     * throw an [IllegalStateException]
+     */
+    fun animateDragTargets(viewsToAnimate: List<BiConsumer<SplitDragPolicy.Target, View>>)
+}
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DropTarget.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DropTarget.kt
index 122a105..2bbca48 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DropTarget.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DropTarget.kt
@@ -47,7 +47,7 @@
     /**
      * Called when user is hovering Drag object over the given Target
      */
-    fun onHoveringOver(target: SplitDragPolicy.Target) {}
+    fun onHoveringOver(target: SplitDragPolicy.Target?) {}
     /**
      * Called when the user has dropped the provided target (need not be the same target as
      * [onHoveringOver])
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DropZoneView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DropZoneView.java
index f9749ec..e503b8c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DropZoneView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DropZoneView.java
@@ -20,12 +20,14 @@
 
 import android.animation.Animator;
 import android.animation.ObjectAnimator;
+import android.annotation.SuppressLint;
 import android.content.Context;
 import android.graphics.Canvas;
 import android.graphics.Color;
 import android.graphics.Path;
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
+import android.graphics.drawable.GradientDrawable;
 import android.util.AttributeSet;
 import android.util.FloatProperty;
 import android.view.Gravity;
@@ -33,6 +35,7 @@
 import android.view.ViewGroup;
 import android.widget.FrameLayout;
 import android.widget.ImageView;
+import android.widget.TextView;
 
 import androidx.annotation.Nullable;
 
@@ -83,6 +86,7 @@
     private int mTargetBackgroundColor;
     private ObjectAnimator mMarginAnimator;
     private float mMarginPercent;
+    private TextView mDebugIndex;
 
     // Renders a highlight or neutral transparent color
     private ColorDrawable mColorDrawable;
@@ -125,6 +129,22 @@
         mMarginView = new MarginView(context);
         addView(mMarginView, new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
                 ViewGroup.LayoutParams.MATCH_PARENT));
+
+        if (DEBUG_LAYOUT) {
+            mDebugIndex = new TextView(context);
+            mDebugIndex.setVisibility(GONE);
+            mDebugIndex.setTextColor(Color.YELLOW);
+            addView(mDebugIndex, new FrameLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
+                    ViewGroup.LayoutParams.WRAP_CONTENT, Gravity.START | Gravity.TOP));
+
+            View borderView = new View(context);
+            addView(borderView, new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
+                    ViewGroup.LayoutParams.MATCH_PARENT));
+            GradientDrawable border = new GradientDrawable();
+            border.setShape(GradientDrawable.RECTANGLE);
+            border.setStroke(5, Color.RED);
+            borderView.setBackground(border);
+        }
     }
 
     public void onThemeChange() {
@@ -236,6 +256,16 @@
         }
     }
 
+    @SuppressLint("SetTextI18n")
+    public void setDebugIndex(int index) {
+        if (!DEBUG_LAYOUT) {
+            return;
+        }
+
+        mDebugIndex.setText("Index:\n" + index);
+        mDebugIndex.setVisibility(VISIBLE);
+    }
+
     private void animateBackground(int startColor, int endColor) {
         if (DEBUG_LAYOUT) {
             ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DRAG_AND_DROP,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/SplitDragPolicy.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/SplitDragPolicy.java
index 2a19d65..5d22c1e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/SplitDragPolicy.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/SplitDragPolicy.java
@@ -32,16 +32,22 @@
 import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
 import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
 
+import static com.android.wm.shell.Flags.enableFlexibleSplit;
+import static com.android.wm.shell.draganddrop.DragLayout.DEBUG_LAYOUT;
 import static com.android.wm.shell.draganddrop.SplitDragPolicy.Target.TYPE_FULLSCREEN;
 import static com.android.wm.shell.draganddrop.SplitDragPolicy.Target.TYPE_SPLIT_BOTTOM;
 import static com.android.wm.shell.draganddrop.SplitDragPolicy.Target.TYPE_SPLIT_LEFT;
 import static com.android.wm.shell.draganddrop.SplitDragPolicy.Target.TYPE_SPLIT_RIGHT;
 import static com.android.wm.shell.draganddrop.SplitDragPolicy.Target.TYPE_SPLIT_TOP;
 import static com.android.wm.shell.shared.draganddrop.DragAndDropConstants.EXTRA_DISALLOW_HIT_REGION;
+import static com.android.wm.shell.shared.split.SplitScreenConstants.SNAP_TO_2_50_50;
 import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT;
 import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT;
 import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_UNDEFINED;
 
+import android.animation.Animator;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
 import android.app.ActivityOptions;
 import android.app.ActivityTaskManager;
 import android.app.PendingIntent;
@@ -59,6 +65,7 @@
 import android.os.UserHandle;
 import android.util.Log;
 import android.util.Slog;
+import android.view.View;
 import android.window.WindowContainerToken;
 
 import androidx.annotation.IntDef;
@@ -69,13 +76,23 @@
 import com.android.internal.logging.InstanceId;
 import com.android.internal.protolog.ProtoLog;
 import com.android.wm.shell.R;
+import com.android.wm.shell.draganddrop.anim.DropTargetAnimSupplier;
+import com.android.wm.shell.draganddrop.anim.HoverAnimProps;
+import com.android.wm.shell.draganddrop.anim.TwoFiftyFiftyTargetAnimator;
 import com.android.wm.shell.protolog.ShellProtoLogGroup;
+import com.android.wm.shell.shared.split.SplitScreenConstants;
 import com.android.wm.shell.shared.split.SplitScreenConstants.SplitPosition;
 import com.android.wm.shell.splitscreen.SplitScreenController;
 
 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.function.BiConsumer;
+
+import kotlin.Pair;
 
 /**
  * The policy for handling drag and drop operations to shell.
@@ -89,24 +106,42 @@
     private final Starter mFullscreenStarter;
     // Used for launching tasks into splitscreen
     private final Starter mSplitscreenStarter;
+    private final DragZoneAnimator mDragZoneAnimator;
     private final SplitScreenController mSplitScreen;
-    private final ArrayList<SplitDragPolicy.Target> mTargets = new ArrayList<>();
+    private ArrayList<SplitDragPolicy.Target> mTargets = new ArrayList<>();
     private final RectF mDisallowHitRegion = new RectF();
+    /**
+     * Maps a given SnapPosition to an array where each index of the array represents one
+     * of the targets that are being hovered over, in order (Left to Right, Top to Bottom).
+     * Ex: 4 drop targets when we're in 50/50 split
+     * 2_50_50 => [ [AnimPropsTarget1, AnimPropsTarget2, AnimPropsTarget3, AnimPropsTarget4],
+     *              ... // hovering over target 2,
+     *              ... // hovering over target 3,
+     *              ... // hovering over target 4
+     *            ]
+     */
+    private final Map<Integer, List<List<HoverAnimProps>>> mHoverAnimProps = new HashMap();
 
     private InstanceId mLoggerSessionId;
     private DragSession mSession;
+    @Nullable
+    private Target mCurrentHoverTarget;
+    /** This variable is a temporary placeholder, will be queried on drag start. */
+    private int mCurrentSnapPosition = -1;
 
-    public SplitDragPolicy(Context context, SplitScreenController splitScreen) {
-        this(context, splitScreen, new DefaultStarter(context));
+    public SplitDragPolicy(Context context, SplitScreenController splitScreen,
+            DragZoneAnimator dragZoneAnimator) {
+        this(context, splitScreen, new DefaultStarter(context), dragZoneAnimator);
     }
 
     @VisibleForTesting
     SplitDragPolicy(Context context, SplitScreenController splitScreen,
-            Starter fullscreenStarter) {
+            Starter fullscreenStarter, DragZoneAnimator dragZoneAnimator) {
         mContext = context;
         mSplitScreen = splitScreen;
         mFullscreenStarter = fullscreenStarter;
         mSplitscreenStarter = splitScreen;
+        mDragZoneAnimator = dragZoneAnimator;
     }
 
     /**
@@ -164,58 +199,123 @@
                 || (mSession.runningTaskActType == ACTIVITY_TYPE_STANDARD
                         && mSession.runningTaskWinMode == WINDOWING_MODE_FULLSCREEN);
         if (allowSplit) {
-            // Already split, allow replacing existing split task
-            final Rect topOrLeftBounds = new Rect();
-            final Rect bottomOrRightBounds = new Rect();
-            mSplitScreen.getStageBounds(topOrLeftBounds, bottomOrRightBounds);
-            topOrLeftBounds.intersect(displayRegion);
-            bottomOrRightBounds.intersect(displayRegion);
+            if (enableFlexibleSplit()) {
+                // TODO(b/349828130) get this from split screen controller, expose the SnapTarget object
+                //  entirely and then pull out the SnapPosition
+                @SplitScreenConstants.SnapPosition int snapPosition = SNAP_TO_2_50_50;
+                final Rect startHitRegion = new Rect();
+                final Rect endHitRegion = new Rect();
+                if (!inSplitScreen) {
+                    // Currently in fullscreen, split in half
+                    final Rect startBounds = new Rect();
+                    final Rect endBounds = new Rect();
+                    mSplitScreen.getStageBounds(startBounds, endBounds);
+                    startBounds.intersect(displayRegion);
+                    endBounds.intersect(displayRegion);
 
-            if (isLeftRightSplit) {
-                final Rect leftHitRegion = new Rect();
-                final Rect rightHitRegion = new Rect();
+                    if (isLeftRightSplit) {
+                        displayRegion.splitVertically(startHitRegion, endHitRegion);
+                    } else {
+                        displayRegion.splitHorizontally(startHitRegion, endHitRegion);
+                    }
 
-                // If we have existing split regions use those bounds, otherwise split it 50/50
-                if (inSplitScreen) {
-                    // The bounds of the existing split will have a divider bar, the hit region
-                    // should include that space. Find the center of the divider bar:
-                    float centerX = topOrLeftBounds.right + (dividerWidth / 2);
-                    // Now set the hit regions using that center.
-                    leftHitRegion.set(displayRegion);
-                    leftHitRegion.right = (int) centerX;
-                    rightHitRegion.set(displayRegion);
-                    rightHitRegion.left = (int) centerX;
+                    mTargets.add(new Target(TYPE_SPLIT_LEFT, startHitRegion, startBounds, -1));
+                    mTargets.add(new Target(TYPE_SPLIT_RIGHT, endHitRegion, endBounds, -1));
                 } else {
-                    displayRegion.splitVertically(leftHitRegion, rightHitRegion);
+                    // TODO(b/349828130), move this into init function and/or the insets updating
+                    //  callback
+                    DropTargetAnimSupplier supplier = null;
+                    switch (snapPosition) {
+                        case SNAP_TO_2_50_50:
+                            supplier = new TwoFiftyFiftyTargetAnimator();
+                        break;
+                        case SplitScreenConstants.SNAP_TO_2_33_66:
+                            break;
+                        case SplitScreenConstants.SNAP_TO_2_66_33:
+                            break;
+                        case SplitScreenConstants.SNAP_TO_END_AND_DISMISS:
+                            break;
+                        case SplitScreenConstants.SNAP_TO_MINIMIZE:
+                            break;
+                        case SplitScreenConstants.SNAP_TO_NONE:
+                            break;
+                        case SplitScreenConstants.SNAP_TO_START_AND_DISMISS:
+                            break;
+                        default:
+                    }
+
+                    Pair<List<Target>, List<List<HoverAnimProps>>> targetsAnims =
+                            supplier.getTargets(mSession.displayLayout,
+                                    insets, isLeftRightSplit, mContext.getResources());
+                    mTargets = new ArrayList<>(targetsAnims.getFirst());
+                    mHoverAnimProps.put(SNAP_TO_2_50_50, targetsAnims.getSecond());
+                    assert(mTargets.size() == targetsAnims.getSecond().size());
+                    if (DEBUG_LAYOUT) {
+                        for (List<HoverAnimProps> props : targetsAnims.getSecond()) {
+                            StringBuilder sb = new StringBuilder();
+                            for (HoverAnimProps hap : props) {
+                                sb.append(hap).append("\n");
+                            }
+                            sb.append("\n");
+                            Log.d(TAG, sb.toString());
+                        }
+                    }
                 }
-
-                mTargets.add(new Target(TYPE_SPLIT_LEFT, leftHitRegion, topOrLeftBounds));
-                mTargets.add(new Target(TYPE_SPLIT_RIGHT, rightHitRegion, bottomOrRightBounds));
-
             } else {
-                final Rect topHitRegion = new Rect();
-                final Rect bottomHitRegion = new Rect();
+                // Already split, allow replacing existing split task
+                final Rect topOrLeftBounds = new Rect();
+                final Rect bottomOrRightBounds = new Rect();
+                mSplitScreen.getStageBounds(topOrLeftBounds, bottomOrRightBounds);
+                topOrLeftBounds.intersect(displayRegion);
+                bottomOrRightBounds.intersect(displayRegion);
 
-                // If we have existing split regions use those bounds, otherwise split it 50/50
-                if (inSplitScreen) {
-                    // The bounds of the existing split will have a divider bar, the hit region
-                    // should include that space. Find the center of the divider bar:
-                    float centerX = topOrLeftBounds.bottom + (dividerWidth / 2);
-                    // Now set the hit regions using that center.
-                    topHitRegion.set(displayRegion);
-                    topHitRegion.bottom = (int) centerX;
-                    bottomHitRegion.set(displayRegion);
-                    bottomHitRegion.top = (int) centerX;
+                if (isLeftRightSplit) {
+                    final Rect leftHitRegion = new Rect();
+                    final Rect rightHitRegion = new Rect();
+
+                    // If we have existing split regions use those bounds, otherwise split it 50/50
+                    if (inSplitScreen) {
+                        // The bounds of the existing split will have a divider bar, the hit region
+                        // should include that space. Find the center of the divider bar:
+                        float centerX = topOrLeftBounds.right + (dividerWidth / 2);
+                        // Now set the hit regions using that center.
+                        leftHitRegion.set(displayRegion);
+                        leftHitRegion.right = (int) centerX;
+                        rightHitRegion.set(displayRegion);
+                        rightHitRegion.left = (int) centerX;
+                    } else {
+                        displayRegion.splitVertically(leftHitRegion, rightHitRegion);
+                    }
+
+                    mTargets.add(new Target(TYPE_SPLIT_LEFT, leftHitRegion, topOrLeftBounds, -1));
+                    mTargets.add(new Target(TYPE_SPLIT_RIGHT, rightHitRegion, bottomOrRightBounds,
+                            -1));
                 } else {
-                    displayRegion.splitHorizontally(topHitRegion, bottomHitRegion);
-                }
+                    final Rect topHitRegion = new Rect();
+                    final Rect bottomHitRegion = new Rect();
 
-                mTargets.add(new Target(TYPE_SPLIT_TOP, topHitRegion, topOrLeftBounds));
-                mTargets.add(new Target(TYPE_SPLIT_BOTTOM, bottomHitRegion, bottomOrRightBounds));
+                    // If we have existing split regions use those bounds, otherwise split it 50/50
+                    if (inSplitScreen) {
+                        // The bounds of the existing split will have a divider bar, the hit region
+                        // should include that space. Find the center of the divider bar:
+                        float centerX = topOrLeftBounds.bottom + (dividerWidth / 2);
+                        // Now set the hit regions using that center.
+                        topHitRegion.set(displayRegion);
+                        topHitRegion.bottom = (int) centerX;
+                        bottomHitRegion.set(displayRegion);
+                        bottomHitRegion.top = (int) centerX;
+                    } else {
+                        displayRegion.splitHorizontally(topHitRegion, bottomHitRegion);
+                    }
+
+                    mTargets.add(new Target(TYPE_SPLIT_TOP, topHitRegion, topOrLeftBounds, -1));
+                    mTargets.add(new Target(TYPE_SPLIT_BOTTOM, bottomHitRegion, bottomOrRightBounds,
+                            -1));
+                }
             }
         } else {
             // Split-screen not allowed, so only show the fullscreen target
-            mTargets.add(new Target(TYPE_FULLSCREEN, fullscreenHitRegion, fullscreenDrawRegion));
+            mTargets.add(new Target(TYPE_FULLSCREEN, fullscreenHitRegion, fullscreenDrawRegion, -1));
         }
         return mTargets;
     }
@@ -230,6 +330,22 @@
         }
         for (int i = mTargets.size() - 1; i >= 0; i--) {
             SplitDragPolicy.Target t = mTargets.get(i);
+            if (enableFlexibleSplit() && mCurrentHoverTarget != null) {
+                // If we're in flexible split, the targets themselves animate, so we have to rely
+                // on the view's animated position for subsequent drag coordinates which we also
+                // cache in HoverAnimProps.
+                List<List<HoverAnimProps>> hoverAnimPropTargets =
+                        mHoverAnimProps.get(mCurrentSnapPosition);
+                for (HoverAnimProps animProps :
+                        hoverAnimPropTargets.get(mCurrentHoverTarget.index)) {
+                    if (animProps.getHoverRect() != null &&
+                            animProps.getHoverRect().contains(x, y)) {
+                        return animProps.getTarget();
+                    }
+                }
+
+            }
+
             if (t.hitRegion.contains(x, y)) {
                 return t;
             }
@@ -266,6 +382,10 @@
         } else {
             launchIntent(mSession, starter, position, hideTaskToken);
         }
+
+        if (enableFlexibleSplit()) {
+            reset();
+        }
     }
 
     /**
@@ -335,6 +455,82 @@
                 null /* fillIntent */, position, opts, hideTaskToken);
     }
 
+    @Override
+    public void onHoveringOver(Target hoverTarget) {
+        final boolean isLeftRightSplit = mSplitScreen != null && mSplitScreen.isLeftRightSplit();
+        final boolean inSplitScreen = mSplitScreen != null && mSplitScreen.isSplitScreenVisible();
+        if (!inSplitScreen) {
+            // no need to animate for entering 50/50 split
+            return;
+        }
+
+        mCurrentHoverTarget = hoverTarget;
+        if (hoverTarget == null) {
+            // Reset to default state
+            BiConsumer<Target, View> biConsumer = new BiConsumer<Target, View>() {
+                @Override
+                public void accept(Target target, View view) {
+                    // take into account left/right split
+                    Animator transX = ObjectAnimator.ofFloat(view, View.TRANSLATION_X,
+                            target.drawRegion.left);
+                    Animator transY = ObjectAnimator.ofFloat(view, View.TRANSLATION_Y,
+                            target.drawRegion.top);
+                    Animator scaleX = ObjectAnimator.ofFloat(view, View.SCALE_X, 1);
+                    Animator scaleY = ObjectAnimator.ofFloat(view, View.SCALE_Y, 1);
+                    AnimatorSet as = new AnimatorSet();
+                    as.play(transX);
+                    as.play(transY);
+                    as.play(scaleX);
+                    as.play(scaleY);
+
+                    as.start();
+                }
+            };
+            mDragZoneAnimator.animateDragTargets(List.of(biConsumer));
+            return;
+        }
+
+        // TODO(b/349828130) get this from split controller
+        @SplitScreenConstants.SnapPosition int snapPosition = SNAP_TO_2_50_50;
+        mCurrentSnapPosition = SNAP_TO_2_50_50;
+        List<BiConsumer<Target, View>> animatingConsumers = new ArrayList<>();
+        final List<List<HoverAnimProps>> hoverAnimProps = mHoverAnimProps.get(snapPosition);
+        List<HoverAnimProps> animProps = hoverAnimProps.get(hoverTarget.index);
+        // Expand start and push out the rest to the end
+        BiConsumer<Target, View> biConsumer = new BiConsumer<>() {
+            @Override
+            public void accept(Target target, View view) {
+                if (animProps.isEmpty() || animProps.size() < (target.index + 1)) {
+                    return;
+                }
+                HoverAnimProps singleAnimProp = animProps.get(target.index);
+                Animator transX = ObjectAnimator.ofFloat(view, View.TRANSLATION_X,
+                        singleAnimProp.getTransX());
+                Animator transY = ObjectAnimator.ofFloat(view, View.TRANSLATION_Y,
+                        singleAnimProp.getTransY());
+                Animator scaleX = ObjectAnimator.ofFloat(view, View.SCALE_X,
+                        singleAnimProp.getScaleX());
+                Animator scaleY = ObjectAnimator.ofFloat(view, View.SCALE_Y,
+                        singleAnimProp.getScaleY());
+                AnimatorSet as = new AnimatorSet();
+                as.play(transX);
+                as.play(transY);
+                as.play(scaleX);
+                as.play(scaleY);
+                as.start();
+            }
+        };
+        animatingConsumers.add(biConsumer);
+        mDragZoneAnimator.animateDragTargets(animatingConsumers);
+    }
+
+    private void reset() {
+        mCurrentHoverTarget = null;
+        mCurrentSnapPosition = -1;
+    }
+
+
+
     /**
      * Interface for actually committing the task launches.
      */
@@ -425,7 +621,7 @@
      */
     public static class Target {
         static final int TYPE_FULLSCREEN = 0;
-        static final int TYPE_SPLIT_LEFT = 1;
+        public static final int TYPE_SPLIT_LEFT = 1;
         static final int TYPE_SPLIT_TOP = 2;
         static final int TYPE_SPLIT_RIGHT = 3;
         static final int TYPE_SPLIT_BOTTOM = 4;
@@ -445,16 +641,23 @@
         final Rect hitRegion;
         // The approximate visual region for where the task will start
         final Rect drawRegion;
+        int index;
 
-        public Target(@Type int t, Rect hit, Rect draw) {
+        /**
+         * @param index 0-indexed, represents which position of drop target this object represents,
+         *              0 to N for left to right, top to bottom
+         */
+        public Target(@Type int t, Rect hit, Rect draw, int index) {
             type = t;
             hitRegion = hit;
             drawRegion = draw;
+            this.index = index;
         }
 
         @Override
         public String toString() {
-            return "Target {type=" + type + " hit=" + hitRegion + " draw=" + drawRegion + "}";
+            return "Target {type=" + type + " hit=" + hitRegion + " draw=" + drawRegion
+                    + " index=" + index + "}";
         }
     }
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/anim/DropTargetAnimSupplier.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/anim/DropTargetAnimSupplier.kt
new file mode 100644
index 0000000..bb34613
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/anim/DropTargetAnimSupplier.kt
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.draganddrop.anim
+
+import android.content.res.Resources
+import android.graphics.Insets
+import com.android.wm.shell.common.DisplayLayout
+import com.android.wm.shell.draganddrop.SplitDragPolicy
+
+/**
+ * When the user is dragging an icon from Taskbar to add an app into split
+ * screen, we have a set of rules by which we draw and move colored drop
+ * targets around the screen. The rules are provided through this interface.
+ *
+ * Each possible screen layout should have an implementation of this interface.
+ * E.g.
+ * - 50:50 two-app split
+ * - 10:45:45 three-app split
+ * - single app, no split
+ *     = three implementations of this interface.
+ */
+interface DropTargetAnimSupplier {
+    /**
+     * Returns a Pair of lists.
+     * First list (length n): Where to draw the n colored drop zones.
+     * Second list (length n): How to animate the drop zones as user hovers around.
+     *
+     * Ex: First list => [A, B, C] // 3 views will be created representing these 3 targets
+     * Second list => [
+     *      [A (scaleX=4), B (translateX=20), C (translateX=20)], // hovering over A
+     *      [A (translateX=20), B (scaleX=4), C (translateX=20)], // hovering over B
+     *      [A (translateX=20), B (translateX=20), C (scaleX=4)], // hovering over C
+     *  ]
+     *
+     *  All indexes assume 0 to N => left to right when [isLeftRightSplit] is true and top to bottom
+     *  when [isLeftRightSplit] is false. Indexing is left to right even in RtL mode.
+     *
+     *  All lists should have the SAME number of elements, even if no animations are to be run for
+     *  a given target while in a hover state.
+     *  It's not that we don't trust you, but we _really_ don't trust you, so this will throw an
+     *  exception if lengths are different. Don't ruin it for everyone else...
+     *  or do. Idk, you're an adult.
+     */
+    fun getTargets(displayLayout: DisplayLayout, insets: Insets, isLeftRightSplit: Boolean,
+                   resources: Resources) :
+            Pair<List<SplitDragPolicy.Target>, List<List<HoverAnimProps>>>
+}
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/anim/HoverAnimProps.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/anim/HoverAnimProps.kt
new file mode 100644
index 0000000..d61caeb
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/anim/HoverAnimProps.kt
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.draganddrop.anim
+
+import android.graphics.Rect
+import com.android.wm.shell.draganddrop.SplitDragPolicy
+
+/**
+ * Contains the animation props to represent a single state of drop targets.
+ * When the user is dragging, we'd be going between different HoverAnimProps
+ */
+data class HoverAnimProps(
+    var target: SplitDragPolicy.Target,
+    val transX: Float,
+    val transY: Float,
+    val scaleX: Float,
+    val scaleY: Float,
+    /**
+     * Pass in null to indicate this target cannot be hovered over for this given animation/
+     * state
+     *
+     * TODO: There's some way we can probably use the existing translation/scaling values
+     * to take [.target]'s hitRect and scale that so we don't have to take in a separate
+     * hoverRect in the CTOR. Have to make sure the pivots match since view's pivot in the
+     * center of the view and rect's pivot at 0, 0 if unspecified.
+     * The two may also not be correlated, but worth investigating
+     *
+     */
+    var hoverRect: Rect?
+) {
+
+    override fun toString(): String {
+        return ("targetId: " + target
+                + " translationX: " + transX
+                + " translationY: " + transY
+                + " scaleX: " + scaleX
+                + " scaleY: " + scaleY
+                + " hoverRect: " + hoverRect)
+    }
+}
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/anim/TwoFiftyFiftyTargetAnimator.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/anim/TwoFiftyFiftyTargetAnimator.kt
new file mode 100644
index 0000000..9f532f5
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/anim/TwoFiftyFiftyTargetAnimator.kt
@@ -0,0 +1,376 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.draganddrop.anim
+
+import android.content.res.Resources
+import android.graphics.Insets
+import android.graphics.Rect
+import com.android.wm.shell.R
+import com.android.wm.shell.common.DisplayLayout
+import com.android.wm.shell.draganddrop.SplitDragPolicy.Target
+
+/**
+ * Represents Drop Zone targets and animations for when the system is currently in a 2 app 50/50
+ * split.
+ * SnapPosition = 2_50_50
+ *
+ * NOTE: Naming convention for many variables is done as "hXtYZ"
+ * This means that variable is a transformation on the Z property for target index Y while the user
+ * is hovering over target index X
+ * Ex: h1t2scaleX=2 => User is hovering over target index 1, target index 2 should scaleX by 2
+ *
+ * TODO(b/349828130): Everything in this class is temporary, none of this is up to spec.
+ */
+class TwoFiftyFiftyTargetAnimator : DropTargetAnimSupplier {
+    /**
+     * TODO: Could we transpose all the horizontal rects by 90 degrees and have that suffice for
+     *  top bottom split?? Hmmm... Doubt it.
+     */
+    override fun getTargets(
+        displayLayout: DisplayLayout,
+        insets: Insets,
+        isLeftRightSplit: Boolean,
+        resources: Resources
+    ): Pair<List<Target>, List<List<HoverAnimProps>>> {
+        val targets : ArrayList<Target> = ArrayList()
+        val w: Int = displayLayout.width()
+        val h: Int = displayLayout.height()
+        val iw = w - insets.left - insets.right
+        val ih = h - insets.top - insets.bottom
+        val l = insets.left
+        val t = insets.top
+        val displayRegion = Rect(l, t, l + iw, t + ih)
+        val fullscreenDrawRegion = Rect(displayRegion)
+        val dividerWidth: Float = resources.getDimensionPixelSize(
+            R.dimen.split_divider_bar_width
+        ).toFloat()
+
+        val farStartBounds = Rect()
+        farStartBounds.set(displayRegion)
+        val startBounds = Rect()
+        startBounds.set(displayRegion)
+        val endBounds = Rect()
+        endBounds.set(displayRegion)
+        val farEndBounds = Rect()
+        farEndBounds.set(displayRegion)
+        val endsPercent = 0.10f
+        val visibleStagePercent = 0.45f
+        val halfDividerWidth = dividerWidth.toInt() / 2
+        val endsWidth = Math.round(displayRegion.width() * endsPercent)
+        val stageWidth = Math.round(displayRegion.width() * visibleStagePercent)
+
+
+        // Place the farStart and farEnds outside of the display, and then
+        // animate them in once the hover starts
+        // | = divider; || = display boundary
+        // farStart || start | end || farEnd
+        farStartBounds.left = -endsWidth
+        farStartBounds.right = 0
+        startBounds.left = farStartBounds.right + dividerWidth.toInt()
+        startBounds.right = startBounds.left + stageWidth
+        endBounds.left = startBounds.right + dividerWidth.toInt()
+        endBounds.right = endBounds.left + stageWidth
+        farEndBounds.left = fullscreenDrawRegion.right
+        farEndBounds.right = farEndBounds.left + endsWidth
+
+
+        // For the hit rect, trim the divider space we've added between the
+        // rects
+        targets.add(
+            Target(
+                Target.TYPE_SPLIT_LEFT,
+                Rect(
+                    farStartBounds.left, farStartBounds.top,
+                    farStartBounds.right + halfDividerWidth,
+                    farStartBounds.bottom
+                ),
+                farStartBounds, 0
+            )
+        )
+        targets.add(
+            Target(
+                Target.TYPE_SPLIT_LEFT,
+                Rect(
+                    startBounds.left - halfDividerWidth,
+                    startBounds.top,
+                    startBounds.right + halfDividerWidth,
+                    startBounds.bottom
+                ),
+                startBounds, 1
+            )
+        )
+        targets.add(
+            Target(
+                Target.TYPE_SPLIT_LEFT,
+                Rect(
+                    endBounds.left - halfDividerWidth,
+                    endBounds.top, endBounds.right, endBounds.bottom
+                ),
+                endBounds, 2
+            )
+        )
+        targets.add(
+            Target(
+                Target.TYPE_SPLIT_LEFT,
+                Rect(
+                    farEndBounds.left - halfDividerWidth,
+                    farEndBounds.top, farEndBounds.right, farEndBounds.bottom
+                ),
+                farEndBounds, 3
+            )
+        )
+
+
+        // Hovering over target 0,
+        // * increase scaleX of target 0
+        // * decrease scaleX of target 1, 2
+        // * ensure target 3 offscreen
+
+        // bring target 0 in from offscreen and expand
+        val h0t0ScaleX = stageWidth.toFloat() / endsWidth
+        val h0t0TransX: Float = stageWidth / h0t0ScaleX + dividerWidth
+        val h0t0HoverProps = HoverAnimProps(
+            targets.get(0),
+            h0t0TransX, farStartBounds.top.toFloat(), h0t0ScaleX, 1f,
+            Rect(
+                0, 0, (stageWidth + dividerWidth).toInt(),
+                farStartBounds.bottom
+            )
+        )
+
+
+        // move target 1 over to the middle/end
+        val h0t1TransX = stageWidth.toFloat()
+        val h0t1ScaleX = 1f
+        val h0t1HoverProps = HoverAnimProps(
+            targets.get(1),
+            h0t1TransX, startBounds.top.toFloat(), h0t1ScaleX, 1f,
+            Rect(
+                stageWidth, 0, (stageWidth + h0t1TransX).toInt(),
+                farStartBounds.bottom
+            )
+        )
+
+
+        // move target 2 to the very end
+        val h0t2TransX = endBounds.left + stageWidth / 2f
+        val h0t2ScaleX = endsWidth.toFloat() / stageWidth
+        val h0t2HoverProps = HoverAnimProps(
+            targets.get(2),
+            h0t2TransX, endBounds.top.toFloat(), h0t2ScaleX, 1f,
+            Rect(
+                displayRegion.right as Int - endsWidth, 0,
+                displayRegion.right as Int,
+                farStartBounds.bottom
+            )
+        )
+
+
+        // move target 3 off-screen
+        val h0t3TransX = farEndBounds.right.toFloat()
+        val h0t3ScaleX = 1f
+        val h0t3HoverProps = HoverAnimProps(
+            targets.get(3),
+            h0t3TransX, farEndBounds.top.toFloat(), h0t3ScaleX, 1f,
+            null
+        )
+        val animPropsForHoverTarget0 =
+            listOf(h0t0HoverProps, h0t1HoverProps, h0t2HoverProps, h0t3HoverProps)
+
+
+        // Hovering over target 1,
+        // * Bring in target 0 from offscreen start
+        // * Shift over target 1
+        // * Slightly lower scale of target 2
+        // * Ensure target 4 offscreen
+        // bring target 0 in from offscreen
+        val h1t0TransX = 0f
+        val h1t0ScaleX = 1f
+        val h1t0HoverProps = HoverAnimProps(
+            targets.get(0),
+            h1t0TransX, farStartBounds.top.toFloat(), h1t0ScaleX, 1f,
+            Rect(
+                0, 0, (farStartBounds.width() + dividerWidth).toInt(),
+                farStartBounds.bottom
+            )
+        )
+
+
+        // move target 1 over a tiny bit by same amount and make it smaller
+        val h1t1TransX: Float = endsWidth + dividerWidth
+        val h1t1ScaleX = 1f
+        val h1t1HoverProps = HoverAnimProps(
+            targets.get(1),
+            h1t1TransX, startBounds.top.toFloat(), h1t1ScaleX, 1f,
+            Rect(
+                h1t1TransX.toInt(), 0, (h1t1TransX + stageWidth).toInt(),
+                farStartBounds.bottom
+            )
+        )
+
+
+        // move target 2 to the very end
+        val h1t2TransX = (endBounds.left + farStartBounds.width()).toFloat()
+        val h1t2ScaleX = h1t1ScaleX
+        val h1t2HoverProps = HoverAnimProps(
+            targets.get(2),
+            h1t2TransX, endBounds.top.toFloat(), h1t2ScaleX, 1f,
+            Rect(
+                endBounds.left + farStartBounds.width(),
+                0,
+                (endBounds.left + farStartBounds.width() + stageWidth),
+                farStartBounds.bottom
+            )
+        )
+
+
+        // move target 3 off-screen, default laid out is off-screen
+        val h1t3TransX = farEndBounds.right.toFloat()
+        val h1t3ScaleX = 1f
+        val h1t3HoverProps = HoverAnimProps(
+            targets.get(3),
+            h1t3TransX, farEndBounds.top.toFloat(), h1t3ScaleX, 1f,
+            null
+        )
+        val animPropsForHoverTarget1 =
+            listOf(h1t0HoverProps, h1t1HoverProps, h1t2HoverProps, h1t3HoverProps)
+
+
+        // Hovering over target 2,
+        // * Ensure Target 0 offscreen
+        // * Ensure target 1 back to start, slightly smaller scale
+        // * Slightly lower scale of target 2
+        // * Bring target 4 on screen
+        // reset target 0
+        val h2t0TransX = farStartBounds.left.toFloat()
+        val h2t0ScaleX = 1f
+        val h2t0HoverProps = HoverAnimProps(
+            targets.get(0),
+            h2t0TransX, farStartBounds.top.toFloat(), h2t0ScaleX, 1f,
+            null
+        )
+
+
+        // move target 1 over a tiny bit by same amount and make it smaller
+        val h2t1TransX = startBounds.left.toFloat()
+        val h2t1ScaleX = 1f
+        val h2t1HoverProps = HoverAnimProps(
+            targets.get(1),
+            h2t1TransX, startBounds.top.toFloat(), h2t1ScaleX, 1f,
+            Rect(
+                startBounds.left, 0,
+                (startBounds.left + stageWidth),
+                farStartBounds.bottom
+            )
+        )
+
+
+        // move target 2 to the very end
+        val h2t2TransX = endBounds.left.toFloat()
+        val h2t2ScaleX = h2t1ScaleX
+        val h2t2HoverProps = HoverAnimProps(
+            targets.get(2),
+            h2t2TransX, endBounds.top.toFloat(), h2t2ScaleX, 1f,
+            Rect(
+                (startBounds.right + dividerWidth).toInt(),
+                0,
+                endBounds.left + stageWidth,
+                farStartBounds.bottom
+            )
+        )
+
+
+        // bring target 3 on-screen
+        val h2t3TransX = (farEndBounds.left - farEndBounds.width()).toFloat()
+        val h2t3ScaleX = 1f
+        val h2t3HoverProps = HoverAnimProps(
+            targets.get(3),
+            h2t3TransX, farEndBounds.top.toFloat(), h2t3ScaleX, 1f,
+            Rect(
+                endBounds.right,
+                0,
+                displayRegion.right,
+                farStartBounds.bottom
+            )
+        )
+        val animPropsForHoverTarget2 =
+            listOf(h2t0HoverProps, h2t1HoverProps, h2t2HoverProps, h2t3HoverProps)
+
+
+        // Hovering over target 3,
+        // * Ensure Target 0 offscreen
+        // * Ensure target 1 back to start, slightly smaller scale
+        // * Slightly lower scale of target 2
+        // * Bring target 4 on screen and scale up
+        // reset target 0
+        val h3t0TransX = farStartBounds.left.toFloat()
+        val h3t0ScaleX = 1f
+        val h3t0HoverProps = HoverAnimProps(
+            targets.get(0),
+            h3t0TransX, farStartBounds.top.toFloat(), h3t0ScaleX, 1f,
+            null
+        )
+
+
+        // move target 1 over a tiny bit by same amount and make it smaller
+        val h3t1ScaleX = endsWidth.toFloat() / stageWidth
+        val h3t1TransX = 0 - (stageWidth / (1 / h3t1ScaleX))
+        val h3t1HoverProps = HoverAnimProps(
+            targets.get(1),
+            h3t1TransX, startBounds.top.toFloat(), h3t1ScaleX, 1f,
+            Rect(
+                0, 0,
+                endsWidth,
+                farStartBounds.bottom
+            )
+        )
+
+
+        // move target 2 towards the start
+        val h3t2TransX: Float = endsWidth + dividerWidth
+        val h3t2ScaleX = 1f
+        val h3t2HoverProps = HoverAnimProps(
+            targets.get(2),
+            h3t2TransX, endBounds.top.toFloat(), h3t2ScaleX, 1f,
+            Rect(
+                endsWidth, 0,
+                (endsWidth + stageWidth + dividerWidth).toInt(),
+                farStartBounds.bottom
+            )
+        )
+
+
+        // bring target 3 on-screen and expand
+        val h3t3ScaleX = stageWidth.toFloat() / endsWidth
+        val h3t3TransX = endBounds.right - stageWidth / 2f
+        val h3t3HoverProps = HoverAnimProps(
+            targets.get(3),
+            h3t3TransX, farEndBounds.top.toFloat(), h3t3ScaleX, 1f,
+            Rect(
+                displayRegion.right - stageWidth, 0,
+                displayRegion.right,
+                farStartBounds.bottom
+            )
+        )
+        val animPropsForHoverTarget3 =
+            listOf(h3t0HoverProps, h3t1HoverProps, h3t2HoverProps, h3t3HoverProps)
+
+        return Pair(targets, listOf(animPropsForHoverTarget0, animPropsForHoverTarget1,
+            animPropsForHoverTarget2, animPropsForHoverTarget3))
+
+    }
+}
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskListener.java
index 73f7011..a16446ff 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskListener.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskListener.java
@@ -24,12 +24,13 @@
 import android.content.Context;
 import android.util.SparseArray;
 import android.view.SurfaceControl;
-import android.window.flags.DesktopModeFlags;
+import android.window.DesktopModeFlags;
 
 import com.android.internal.protolog.ProtoLog;
 import com.android.wm.shell.ShellTaskOrganizer;
 import com.android.wm.shell.common.LaunchAdjacentController;
 import com.android.wm.shell.desktopmode.DesktopRepository;
+import com.android.wm.shell.desktopmode.DesktopTasksController;
 import com.android.wm.shell.protolog.ShellProtoLogGroup;
 import com.android.wm.shell.shared.desktopmode.DesktopModeStatus;
 import com.android.wm.shell.sysui.ShellInit;
@@ -50,6 +51,7 @@
     private final Context mContext;
     private final ShellTaskOrganizer mShellTaskOrganizer;
     private final Optional<DesktopRepository> mDesktopRepository;
+    private final Optional<DesktopTasksController> mDesktopTasksController;
     private final WindowDecorViewModel mWindowDecorationViewModel;
     private final LaunchAdjacentController mLaunchAdjacentController;
 
@@ -65,12 +67,14 @@
             ShellInit shellInit,
             ShellTaskOrganizer shellTaskOrganizer,
             Optional<DesktopRepository> desktopRepository,
+            Optional<DesktopTasksController> desktopTasksController,
             LaunchAdjacentController launchAdjacentController,
             WindowDecorViewModel windowDecorationViewModel) {
         mContext = context;
         mShellTaskOrganizer = shellTaskOrganizer;
         mWindowDecorationViewModel = windowDecorationViewModel;
         mDesktopRepository = desktopRepository;
+        mDesktopTasksController = desktopTasksController;
         mLaunchAdjacentController = launchAdjacentController;
         if (shellInit != null) {
             shellInit.addInitCallback(this::onInit, this);
@@ -95,11 +99,6 @@
         state.mTaskInfo = taskInfo;
         state.mLeash = leash;
         mTasks.put(taskInfo.taskId, state);
-        if (!Transitions.ENABLE_SHELL_TRANSITIONS) {
-            SurfaceControl.Transaction t = new SurfaceControl.Transaction();
-            mWindowDecorationViewModel.onTaskOpening(taskInfo, leash, t, t);
-            t.apply();
-        }
 
         if (DesktopModeStatus.canEnterDesktopMode(mContext)) {
             mDesktopRepository.ifPresent(repository -> {
@@ -127,6 +126,7 @@
                         || repository.isClosingTask(taskInfo.taskId)) {
                     // A task that's vanishing should be removed:
                     // - If it's closed by the X button which means it's marked as a closing task.
+                    repository.removeClosingTask(taskInfo.taskId);
                     repository.removeFreeformTask(taskInfo.displayId, taskInfo.taskId);
                 } else {
                     repository.updateTaskVisibility(taskInfo.displayId, taskInfo.taskId, false);
@@ -135,9 +135,6 @@
             });
         }
         mWindowDecorationViewModel.onTaskVanished(taskInfo);
-        if (!Transitions.ENABLE_SHELL_TRANSITIONS) {
-            mWindowDecorationViewModel.destroyWindowDecoration(taskInfo);
-        }
         updateLaunchAdjacentController();
     }
 
@@ -147,14 +144,13 @@
 
         ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TASK_ORG, "Freeform Task Info Changed: #%d",
                 taskInfo.taskId);
+        mDesktopTasksController.ifPresent(c -> c.onTaskInfoChanged(taskInfo));
         mWindowDecorationViewModel.onTaskInfoChanged(taskInfo);
         state.mTaskInfo = taskInfo;
         if (DesktopModeStatus.canEnterDesktopMode(mContext)) {
             mDesktopRepository.ifPresent(repository -> {
                 if (taskInfo.isVisible) {
                     repository.addActiveTask(taskInfo.displayId, taskInfo.taskId);
-                } else if (repository.isClosingTask(taskInfo.taskId)) {
-                    repository.removeClosingTask(taskInfo.taskId);
                 }
                 repository.updateTaskVisibility(taskInfo.displayId, taskInfo.taskId,
                         taskInfo.isVisible);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionObserver.java b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionObserver.java
index d6b920e..771573d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionObserver.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionObserver.java
@@ -30,6 +30,7 @@
 import com.android.window.flags.Flags;
 import com.android.wm.shell.desktopmode.DesktopFullImmersiveTransitionHandler;
 import com.android.wm.shell.sysui.ShellInit;
+import com.android.wm.shell.transition.FocusTransitionObserver;
 import com.android.wm.shell.transition.Transitions;
 import com.android.wm.shell.windowdecor.WindowDecorViewModel;
 
@@ -50,6 +51,7 @@
     private final Optional<DesktopFullImmersiveTransitionHandler> mImmersiveTransitionHandler;
     private final WindowDecorViewModel mWindowDecorViewModel;
     private final Optional<TaskChangeListener> mTaskChangeListener;
+    private final FocusTransitionObserver mFocusTransitionObserver;
 
     private final Map<IBinder, List<ActivityManager.RunningTaskInfo>> mTransitionToTaskInfo =
             new HashMap<>();
@@ -60,12 +62,14 @@
             Transitions transitions,
             Optional<DesktopFullImmersiveTransitionHandler> immersiveTransitionHandler,
             WindowDecorViewModel windowDecorViewModel,
-            Optional<TaskChangeListener> taskChangeListener) {
+            Optional<TaskChangeListener> taskChangeListener,
+            FocusTransitionObserver focusTransitionObserver) {
         mTransitions = transitions;
         mImmersiveTransitionHandler = immersiveTransitionHandler;
         mWindowDecorViewModel = windowDecorViewModel;
         mTaskChangeListener = taskChangeListener;
-        if (Transitions.ENABLE_SHELL_TRANSITIONS && FreeformComponents.isFreeformEnabled(context)) {
+        mFocusTransitionObserver = focusTransitionObserver;
+        if (FreeformComponents.isFreeformEnabled(context)) {
             shellInit.addInitCallback(this::onInit, this);
         }
     }
@@ -85,8 +89,11 @@
             // TODO(b/367268953): Remove when DesktopTaskListener is introduced and the repository
             //  is updated from there **before** the |mWindowDecorViewModel| methods are invoked.
             //  Otherwise window decoration relayout won't run with the immersive state up to date.
-            mImmersiveTransitionHandler.ifPresent(h -> h.onTransitionReady(transition));
+            mImmersiveTransitionHandler.ifPresent(h -> h.onTransitionReady(transition, info));
         }
+        // Update focus state first to ensure the correct state can be queried from listeners.
+        // TODO(371503964): Remove this once the unified task repository is ready.
+        mFocusTransitionObserver.updateFocusState(info);
 
         final ArrayList<ActivityManager.RunningTaskInfo> taskInfoList = new ArrayList<>();
         final ArrayList<WindowContainerToken> taskParents = new ArrayList<>();
@@ -119,6 +126,9 @@
                 case WindowManager.TRANSIT_TO_FRONT:
                     onToFrontTransitionReady(change, startT, finishT);
                     break;
+                case WindowManager.TRANSIT_TO_BACK:
+                    onToBackTransitionReady(change, startT, finishT);
+                    break;
                 case WindowManager.TRANSIT_CLOSE: {
                     taskInfoList.add(change.getTaskInfo());
                     onCloseTransitionReady(change, startT, finishT);
@@ -173,6 +183,16 @@
                 change.getTaskInfo(), change.getLeash(), startT, finishT);
     }
 
+    private void onToBackTransitionReady(
+            TransitionInfo.Change change,
+            SurfaceControl.Transaction startT,
+            SurfaceControl.Transaction finishT) {
+        mTaskChangeListener.ifPresent(
+                listener -> listener.onTaskMovingToBack(change.getTaskInfo()));
+        mWindowDecorViewModel.onTaskChanging(
+                change.getTaskInfo(), change.getLeash(), startT, finishT);
+    }
+
     @Override
     public void onTransitionStarting(@NonNull IBinder transition) {}
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/keyguard/KeyguardTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/keyguard/KeyguardTransitionHandler.java
index abec3b9..f8d2011 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/keyguard/KeyguardTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/keyguard/KeyguardTransitionHandler.java
@@ -28,6 +28,8 @@
 import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_OCCLUDING;
 import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_UNOCCLUDING;
 import static android.view.WindowManager.TRANSIT_SLEEP;
+import static android.view.WindowManager.TRANSIT_TO_BACK;
+import static android.view.WindowManager.TRANSIT_TO_FRONT;
 
 import static com.android.wm.shell.shared.TransitionUtil.isOpeningType;
 
@@ -44,6 +46,7 @@
 import android.view.WindowManager;
 import android.window.IRemoteTransition;
 import android.window.IRemoteTransitionFinishedCallback;
+import android.window.KeyguardState;
 import android.window.TransitionInfo;
 import android.window.TransitionRequestInfo;
 import android.window.WindowContainerToken;
@@ -388,5 +391,18 @@
             mMainExecutor.execute(() ->
                     mIsLaunchingActivityOverLockscreen = isLaunchingActivityOverLockscreen);
         }
+
+        @Override
+        public void startKeyguardTransition(boolean keyguardShowing, boolean aodShowing) {
+            final WindowContainerTransaction wct = new WindowContainerTransaction();
+            final KeyguardState keyguardState =
+                    new KeyguardState.Builder(android.view.Display.DEFAULT_DISPLAY)
+                            .setKeyguardShowing(keyguardShowing).setAodShowing(aodShowing).build();
+            wct.addKeyguardState(keyguardState);
+            mMainExecutor.execute(() -> {
+                mTransitions.startTransition(keyguardShowing ? TRANSIT_TO_FRONT : TRANSIT_TO_BACK,
+                        wct, KeyguardTransitionHandler.this);
+            });
+        }
     }
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/keyguard/KeyguardTransitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/keyguard/KeyguardTransitions.java
index b7245b9..1d349e6 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/keyguard/KeyguardTransitions.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/keyguard/KeyguardTransitions.java
@@ -44,4 +44,11 @@
      * Notify whether keyguard has created a remote animation runner for next app launch.
      */
     default void setLaunchingActivityOverLockscreen(boolean isLaunchingActivityOverLockscreen) {}
+
+    /**
+     * Notifies Shell to start a keyguard transition directly.
+     * @param keyguardShowing whether keyguard is showing or not.
+     * @param aodShowing whether aod is showing or not.
+     */
+    default void startKeyguardTransition(boolean keyguardShowing, boolean aodShowing) {}
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/animation/PipEnterAnimator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/animation/PipEnterAnimator.java
new file mode 100644
index 0000000..f40a87c
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/animation/PipEnterAnimator.java
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.pip2.animation;
+
+import android.animation.Animator;
+import android.animation.RectEvaluator;
+import android.animation.ValueAnimator;
+import android.content.Context;
+import android.graphics.PointF;
+import android.graphics.Rect;
+import android.view.Surface;
+import android.view.SurfaceControl;
+import android.window.TransitionInfo;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import com.android.wm.shell.R;
+import com.android.wm.shell.common.pip.PipUtils;
+import com.android.wm.shell.pip2.PipSurfaceTransactionHelper;
+import com.android.wm.shell.shared.animation.Interpolators;
+
+/**
+ * Animator that handles bounds animations for entering PIP.
+ */
+public class PipEnterAnimator extends ValueAnimator
+        implements ValueAnimator.AnimatorUpdateListener, ValueAnimator.AnimatorListener {
+    @NonNull private final SurfaceControl mLeash;
+    private final SurfaceControl.Transaction mStartTransaction;
+    private final SurfaceControl.Transaction mFinishTransaction;
+
+    // Bounds updated by the evaluator as animator is running.
+    private final Rect mAnimatedRect = new Rect();
+
+    private final RectEvaluator mRectEvaluator;
+    private final Rect mEndBounds = new Rect();
+    @Nullable private final Rect mSourceRectHint;
+    private final @Surface.Rotation int mRotation;
+    @Nullable private Runnable mAnimationStartCallback;
+    @Nullable private Runnable mAnimationEndCallback;
+
+    private final PipSurfaceTransactionHelper.SurfaceControlTransactionFactory
+            mSurfaceControlTransactionFactory;
+
+    // Internal state representing initial transform - cached to avoid recalculation.
+    private final PointF mInitScale = new PointF();
+    private final PointF mInitPos = new PointF();
+    private final Rect mInitCrop = new Rect();
+
+    public PipEnterAnimator(Context context,
+            @NonNull SurfaceControl leash,
+            SurfaceControl.Transaction startTransaction,
+            SurfaceControl.Transaction finishTransaction,
+            @NonNull Rect endBounds,
+            @Nullable Rect sourceRectHint,
+            @Surface.Rotation int rotation) {
+        mLeash = leash;
+        mStartTransaction = startTransaction;
+        mFinishTransaction = finishTransaction;
+        mRectEvaluator = new RectEvaluator(mAnimatedRect);
+        mEndBounds.set(endBounds);
+        mSourceRectHint = sourceRectHint != null ? new Rect(sourceRectHint) : null;
+        mRotation = rotation;
+        mSurfaceControlTransactionFactory =
+                new PipSurfaceTransactionHelper.VsyncSurfaceControlTransactionFactory();
+
+        final int enterAnimationDuration = context.getResources()
+                .getInteger(R.integer.config_pipEnterAnimationDuration);
+        setDuration(enterAnimationDuration);
+        setFloatValues(0f, 1f);
+        setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
+        addListener(this);
+        addUpdateListener(this);
+    }
+
+    public void setAnimationStartCallback(@NonNull Runnable runnable) {
+        mAnimationStartCallback = runnable;
+    }
+
+    public void setAnimationEndCallback(@NonNull Runnable runnable) {
+        mAnimationEndCallback = runnable;
+    }
+
+    @Override
+    public void onAnimationStart(@NonNull Animator animation) {
+        if (mAnimationStartCallback != null) {
+            mAnimationStartCallback.run();
+        }
+        if (mStartTransaction != null) {
+            onEnterAnimationUpdate(mInitScale, mInitPos, mInitCrop,
+                    0f /* fraction */, mStartTransaction);
+            mStartTransaction.apply();
+        }
+    }
+
+    @Override
+    public void onAnimationEnd(@NonNull Animator animation) {
+        if (mAnimationEndCallback != null) {
+            mAnimationEndCallback.run();
+        }
+    }
+
+    @Override
+    public void onAnimationUpdate(@NonNull ValueAnimator animation) {
+        final SurfaceControl.Transaction tx = mSurfaceControlTransactionFactory.getTransaction();
+        final float fraction = getAnimatedFraction();
+        onEnterAnimationUpdate(mInitScale, mInitPos, mInitCrop, fraction, tx);
+        tx.apply();
+    }
+
+    private void onEnterAnimationUpdate(PointF initScale, PointF initPos, Rect initCrop,
+            float fraction, SurfaceControl.Transaction tx) {
+        float scaleX = 1 + (initScale.x - 1) * (1 - fraction);
+        float scaleY = 1 + (initScale.y - 1) * (1 - fraction);
+        tx.setScale(mLeash, scaleX, scaleY);
+
+        float posX = initPos.x + (mEndBounds.left - initPos.x) * fraction;
+        float posY = initPos.y + (mEndBounds.top - initPos.y) * fraction;
+        tx.setPosition(mLeash, posX, posY);
+
+        Rect endCrop = new Rect(mEndBounds);
+        endCrop.offsetTo(0, 0);
+        mRectEvaluator.evaluate(fraction, initCrop, endCrop);
+        tx.setCrop(mLeash, mAnimatedRect);
+    }
+
+    // no-ops
+
+    @Override
+    public void onAnimationCancel(@NonNull Animator animation) {}
+
+    @Override
+    public void onAnimationRepeat(@NonNull Animator animation) {}
+
+    /**
+     * Caches the initial transform relevant values for the bounds enter animation.
+     *
+     * Since enter PiP makes use of a config-at-end transition, initial transform needs to be
+     * calculated differently from generic transitions.
+     * @param pipChange PiP change received as a transition target.
+     */
+    public void setEnterStartState(@NonNull TransitionInfo.Change pipChange) {
+        PipUtils.calcStartTransform(pipChange, mInitScale, mInitPos, mInitCrop);
+    }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/animation/PipEnterExitAnimator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/animation/PipExpandAnimator.java
similarity index 77%
rename from libs/WindowManager/Shell/src/com/android/wm/shell/pip2/animation/PipEnterExitAnimator.java
rename to libs/WindowManager/Shell/src/com/android/wm/shell/pip2/animation/PipExpandAnimator.java
index 8ebdc96..8fa5aa9 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/animation/PipEnterExitAnimator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/animation/PipExpandAnimator.java
@@ -19,7 +19,6 @@
 import android.animation.Animator;
 import android.animation.RectEvaluator;
 import android.animation.ValueAnimator;
-import android.annotation.IntDef;
 import android.content.Context;
 import android.graphics.Rect;
 import android.view.Surface;
@@ -30,35 +29,22 @@
 
 import com.android.wm.shell.R;
 import com.android.wm.shell.pip2.PipSurfaceTransactionHelper;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
+import com.android.wm.shell.shared.animation.Interpolators;
 
 /**
- * Animator that handles bounds animations for entering / exiting PIP.
+ * Animator that handles bounds animations for exit-via-expanding PIP.
  */
-public class PipEnterExitAnimator extends ValueAnimator
+public class PipExpandAnimator extends ValueAnimator
         implements ValueAnimator.AnimatorUpdateListener, ValueAnimator.AnimatorListener {
-    @IntDef(prefix = {"BOUNDS_"}, value = {
-            BOUNDS_ENTER,
-            BOUNDS_EXIT
-    })
-
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface BOUNDS {}
-
-    public static final int BOUNDS_ENTER = 0;
-    public static final int BOUNDS_EXIT = 1;
-
-    @NonNull private final SurfaceControl mLeash;
+    @NonNull
+    private final SurfaceControl mLeash;
     private final SurfaceControl.Transaction mStartTransaction;
     private final SurfaceControl.Transaction mFinishTransaction;
-    private final int mEnterExitAnimationDuration;
-    private final @BOUNDS int mDirection;
     private final @Surface.Rotation int mRotation;
 
     // optional callbacks for tracking animation start and end
-    @Nullable private Runnable mAnimationStartCallback;
+    @Nullable
+    private Runnable mAnimationStartCallback;
     @Nullable private Runnable mAnimationEndCallback;
 
     private final Rect mBaseBounds = new Rect();
@@ -78,7 +64,7 @@
     private final RectEvaluator mInsetEvaluator;
     private final PipSurfaceTransactionHelper mPipSurfaceTransactionHelper;
 
-    public PipEnterExitAnimator(Context context,
+    public PipExpandAnimator(Context context,
             @NonNull SurfaceControl leash,
             SurfaceControl.Transaction startTransaction,
             SurfaceControl.Transaction finishTransaction,
@@ -86,7 +72,6 @@
             @NonNull Rect startBounds,
             @NonNull Rect endBounds,
             @Nullable Rect sourceRectHint,
-            @BOUNDS int direction,
             @Surface.Rotation int rotation) {
         mLeash = leash;
         mStartTransaction = startTransaction;
@@ -98,7 +83,6 @@
         mRectEvaluator = new RectEvaluator(mAnimatedRect);
         mInsetEvaluator = new RectEvaluator(new Rect());
         mPipSurfaceTransactionHelper = new PipSurfaceTransactionHelper(context);
-        mDirection = direction;
         mRotation = rotation;
 
         mSourceRectHint = sourceRectHint != null ? new Rect(sourceRectHint) : null;
@@ -113,12 +97,14 @@
 
         mSurfaceControlTransactionFactory =
                 new PipSurfaceTransactionHelper.VsyncSurfaceControlTransactionFactory();
-        mEnterExitAnimationDuration = context.getResources()
+
+        final int enterAnimationDuration = context.getResources()
                 .getInteger(R.integer.config_pipEnterAnimationDuration);
+        setDuration(enterAnimationDuration);
 
         setObjectValues(startBounds, endBounds);
-        setDuration(mEnterExitAnimationDuration);
         setEvaluator(mRectEvaluator);
+        setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
         addListener(this);
         addUpdateListener(this);
     }
@@ -147,9 +133,10 @@
             // finishTransaction might override some state (eg. corner radii) so we want to
             // manually set the state to the end of the animation
             mPipSurfaceTransactionHelper.scaleAndCrop(mFinishTransaction, mLeash, mSourceRectHint,
-                            mBaseBounds, mAnimatedRect, getInsets(1f), isInPipDirection(), 1f)
-                    .round(mFinishTransaction, mLeash, isInPipDirection())
-                    .shadow(mFinishTransaction, mLeash, isInPipDirection());
+                            mBaseBounds, mAnimatedRect, getInsets(1f),
+                            false /* isInPipDirection */, 1f)
+                    .round(mFinishTransaction, mLeash, false /* applyCornerRadius */)
+                    .shadow(mFinishTransaction, mLeash, false /* applyCornerRadius */);
         }
         if (mAnimationEndCallback != null) {
             mAnimationEndCallback.run();
@@ -160,32 +147,22 @@
     public void onAnimationUpdate(@NonNull ValueAnimator animation) {
         final SurfaceControl.Transaction tx = mSurfaceControlTransactionFactory.getTransaction();
         final float fraction = getAnimatedFraction();
-        Rect insets = getInsets(fraction);
 
         // TODO (b/350801661): implement fixed rotation
 
+        Rect insets = getInsets(fraction);
         mPipSurfaceTransactionHelper.scaleAndCrop(tx, mLeash, mSourceRectHint,
-                mBaseBounds, mAnimatedRect, insets, isInPipDirection(), fraction)
-                .round(tx, mLeash, isInPipDirection())
-                .shadow(tx, mLeash, isInPipDirection());
+                        mBaseBounds, mAnimatedRect, insets, false /* isInPipDirection */, fraction)
+                .round(tx, mLeash, false /* applyCornerRadius */)
+                .shadow(tx, mLeash, false /* applyCornerRadius */);
         tx.apply();
     }
-
     private Rect getInsets(float fraction) {
-        Rect startInsets = isInPipDirection() ? mZeroInsets : mSourceRectHintInsets;
-        Rect endInsets = isInPipDirection() ? mSourceRectHintInsets : mZeroInsets;
-
+        final Rect startInsets = mSourceRectHintInsets;
+        final Rect endInsets = mZeroInsets;
         return mInsetEvaluator.evaluate(fraction, startInsets, endInsets);
     }
 
-    private boolean isInPipDirection() {
-        return mDirection == BOUNDS_ENTER;
-    }
-
-    private boolean isOutPipDirection() {
-        return mDirection == BOUNDS_EXIT;
-    }
-
     // no-ops
 
     @Override
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PhonePipMenuController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PhonePipMenuController.java
index 9cfe162..8c1e5e6 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PhonePipMenuController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PhonePipMenuController.java
@@ -18,10 +18,12 @@
 
 import static android.view.WindowManager.SHELL_ROOT_LAYER_PIP;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.RemoteAction;
 import android.content.Context;
 import android.graphics.Rect;
+import android.os.Bundle;
 import android.os.Debug;
 import android.os.Handler;
 import android.os.RemoteException;
@@ -52,7 +54,8 @@
  * The current media session provides actions whenever there are no valid actions provided by the
  * current PiP activity. Otherwise, those actions always take precedence.
  */
-public class PhonePipMenuController implements PipMenuController {
+public class PhonePipMenuController implements PipMenuController,
+        PipTransitionState.PipTransitionStateChangedListener {
 
     private static final String TAG = "PhonePipMenuController";
     private static final boolean DEBUG = false;
@@ -113,6 +116,11 @@
 
     private PipMenuView mPipMenuView;
 
+    private final PipTaskListener mPipTaskListener;
+
+    @NonNull
+    private final PipTransitionState mPipTransitionState;
+
     private SurfaceControl mLeash;
 
     private ActionListener mMediaActionListener = new ActionListener() {
@@ -125,15 +133,27 @@
 
     public PhonePipMenuController(Context context, PipBoundsState pipBoundsState,
             PipMediaController mediaController, SystemWindows systemWindows,
-            PipUiEventLogger pipUiEventLogger,
-            ShellExecutor mainExecutor, Handler mainHandler) {
+            PipUiEventLogger pipUiEventLogger, PipTaskListener pipTaskListener,
+            @NonNull PipTransitionState pipTransitionState, ShellExecutor mainExecutor,
+            Handler mainHandler) {
         mContext = context;
         mPipBoundsState = pipBoundsState;
         mMediaController = mediaController;
         mSystemWindows = systemWindows;
+        mPipTaskListener = pipTaskListener;
+        mPipTransitionState = pipTransitionState;
         mMainExecutor = mainExecutor;
         mMainHandler = mainHandler;
         mPipUiEventLogger = pipUiEventLogger;
+
+        mPipTransitionState.addPipTransitionStateChangedListener(this);
+
+        mPipTaskListener.addParamsChangedListener(new PipTaskListener.PipParamsChangedCallback() {
+            @Override
+            public void onActionsChanged(List<RemoteAction> actions, RemoteAction closeAction) {
+                setAppActions(actions, closeAction);
+            }
+        });
     }
 
     public boolean isMenuVisible() {
@@ -438,8 +458,7 @@
      * Sets the menu actions to the actions provided by the current PiP menu.
      */
     @Override
-    public void setAppActions(List<RemoteAction> appActions,
-            RemoteAction closeAction) {
+    public void setAppActions(List<RemoteAction> appActions, RemoteAction closeAction) {
         mAppActions = appActions;
         mCloseAction = closeAction;
         updateMenuActions();
@@ -468,8 +487,8 @@
      */
     private void updateMenuActions() {
         if (mPipMenuView != null) {
-            mPipMenuView.setActions(mPipBoundsState.getBounds(),
-                    resolveMenuActions(), mCloseAction);
+            mPipMenuView.setActions(mPipBoundsState.getBounds(), resolveMenuActions(),
+                    mCloseAction);
         }
     }
 
@@ -567,6 +586,29 @@
         }
     }
 
+    @Override
+    public void onPipTransitionStateChanged(@PipTransitionState.TransitionState int oldState,
+            @PipTransitionState.TransitionState int newState, Bundle extra) {
+        switch (newState) {
+            case PipTransitionState.ENTERED_PIP:
+                attach(mPipTransitionState.mPinnedTaskLeash);
+                break;
+            case PipTransitionState.EXITED_PIP:
+                detach();
+                break;
+            case PipTransitionState.CHANGED_PIP_BOUNDS:
+                updateMenuLayout(mPipBoundsState.getBounds());
+                hideMenu();
+                break;
+            case PipTransitionState.CHANGING_PIP_BOUNDS:
+                hideMenu();
+                break;
+            case PipTransitionState.SCHEDULED_BOUNDS_CHANGE:
+                hideMenu();
+                break;
+        }
+    }
+
     void dump(PrintWriter pw, String prefix) {
         final String innerPrefix = prefix + "  ";
         pw.println(prefix + TAG);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipMenuView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipMenuView.java
index a29104c..0910919 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipMenuView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipMenuView.java
@@ -447,7 +447,7 @@
                 final LayoutInflater inflater = LayoutInflater.from(mContext);
                 while (mActionsGroup.getChildCount() < mActions.size()) {
                     final PipMenuActionView actionView = (PipMenuActionView) inflater.inflate(
-                            R.layout.pip_menu_action, mActionsGroup, false);
+                            R.layout.pip2_menu_action, mActionsGroup, false);
                     mActionsGroup.addView(actionView);
                 }
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipMotionHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipMotionHelper.java
index 0324fdb..268c3a2 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipMotionHelper.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipMotionHelper.java
@@ -336,7 +336,7 @@
         }
         cancelPhysicsAnimation();
         mMenuController.hideMenu(ANIM_TYPE_NONE, false /* resize */);
-        // mPipTaskOrganizer.exitPip(skipAnimation ? 0 : LEAVE_PIP_DURATION, enterSplit);
+        mPipScheduler.scheduleExitPipViaExpand();
     }
 
     /**
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipScheduler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipScheduler.java
index f4defdc..d4f190e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipScheduler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipScheduler.java
@@ -52,7 +52,6 @@
 
     private final Context mContext;
     private final PipBoundsState mPipBoundsState;
-    private final PhonePipMenuController mPipMenuController;
     private final ShellExecutor mMainExecutor;
     private final PipTransitionState mPipTransitionState;
     private PipSchedulerReceiver mSchedulerReceiver;
@@ -97,12 +96,10 @@
 
     public PipScheduler(Context context,
             PipBoundsState pipBoundsState,
-            PhonePipMenuController pipMenuController,
             ShellExecutor mainExecutor,
             PipTransitionState pipTransitionState) {
         mContext = context;
         mPipBoundsState = pipBoundsState;
-        mPipMenuController = pipMenuController;
         mMainExecutor = mainExecutor;
         mPipTransitionState = pipTransitionState;
 
@@ -263,7 +260,6 @@
             return;
         }
         mPipBoundsState.setBounds(newBounds);
-        mPipMenuController.updateMenuLayout(newBounds);
         maybeUpdateMovementBounds();
     }
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTaskListener.java
index 262c14d..c58de2c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTaskListener.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTaskListener.java
@@ -20,6 +20,7 @@
 
 import android.app.ActivityManager;
 import android.app.PictureInPictureParams;
+import android.app.RemoteAction;
 import android.content.Context;
 import android.graphics.Rect;
 import android.os.Bundle;
@@ -37,6 +38,9 @@
 import com.android.wm.shell.pip2.animation.PipResizeAnimator;
 import com.android.wm.shell.shared.annotations.ShellMainThread;
 
+import java.util.ArrayList;
+import java.util.List;
+
 /**
  * A Task Listener implementation used only for CUJs and trigger paths that cannot be initiated via
  * Transitions framework directly.
@@ -57,6 +61,7 @@
             new PictureInPictureParams.Builder().build();
 
     private boolean mWaitingForAspectRatioChange = false;
+    private final List<PipParamsChangedCallback> mPipParamsChangedListeners = new ArrayList<>();
 
     public PipTaskListener(Context context,
             ShellTaskOrganizer shellTaskOrganizer,
@@ -85,10 +90,25 @@
         if (mPictureInPictureParams.equals(params)) {
             return;
         }
+        if (PipUtils.remoteActionsChanged(params.getActions(), mPictureInPictureParams.getActions())
+                || !PipUtils.remoteActionsMatch(params.getCloseAction(),
+                mPictureInPictureParams.getCloseAction())) {
+            for (PipParamsChangedCallback listener : mPipParamsChangedListeners) {
+                listener.onActionsChanged(params.getActions(), params.getCloseAction());
+            }
+        }
         mPictureInPictureParams.copyOnlySet(params != null ? params
                 : new PictureInPictureParams.Builder().build());
     }
 
+    /** Add a PipParamsChangedCallback listener. */
+    public void addParamsChangedListener(PipParamsChangedCallback listener) {
+        if (mPipParamsChangedListeners.contains(listener)) {
+            return;
+        }
+        mPipParamsChangedListeners.add(listener);
+    }
+
     @NonNull
     public PictureInPictureParams getPictureInPictureParams() {
         return mPictureInPictureParams;
@@ -164,4 +184,12 @@
                 break;
         }
     }
+
+    public interface PipParamsChangedCallback {
+        /**
+         * Called if either the actions or the close action changed.
+         */
+        default void onActionsChanged(List<RemoteAction> actions, RemoteAction closeAction) {
+        }
+    }
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java
index 62a60fa..b57f51a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java
@@ -56,7 +56,8 @@
 import com.android.wm.shell.common.pip.PipUtils;
 import com.android.wm.shell.pip.PipTransitionController;
 import com.android.wm.shell.pip2.animation.PipAlphaAnimator;
-import com.android.wm.shell.pip2.animation.PipEnterExitAnimator;
+import com.android.wm.shell.pip2.animation.PipEnterAnimator;
+import com.android.wm.shell.pip2.animation.PipExpandAnimator;
 import com.android.wm.shell.shared.TransitionUtil;
 import com.android.wm.shell.shared.pip.PipContentOverlay;
 import com.android.wm.shell.sysui.ShellInit;
@@ -218,6 +219,7 @@
             @NonNull SurfaceControl.Transaction startTransaction,
             @NonNull SurfaceControl.Transaction finishTransaction,
             @NonNull Transitions.TransitionFinishCallback finishCallback) {
+        mFinishCallback = finishCallback;
         if (transition == mEnterTransition || info.getType() == TRANSIT_PIP) {
             mEnterTransition = null;
             // If we are in swipe PiP to Home transition we are ENTERING_PIP as a jumpcut transition
@@ -258,6 +260,7 @@
         if (isRemovePipTransition(info)) {
             return removePipImmediately(info, startTransaction, finishTransaction, finishCallback);
         }
+        mFinishCallback = null;
         return false;
     }
 
@@ -297,7 +300,6 @@
             mBoundsChangeDuration = BOUNDS_CHANGE_JUMPCUT_DURATION;
         }
 
-        mFinishCallback = finishCallback;
         mPipTransitionState.setState(PipTransitionState.CHANGING_PIP_BOUNDS, extra);
         return true;
     }
@@ -349,7 +351,6 @@
             startTransaction.setMatrix(pipLeash, transformTensor, matrixTmp);
         }
         startTransaction.apply();
-        finishCallback.onTransitionFinished(null /* finishWct */);
         finishInner();
         return true;
     }
@@ -386,14 +387,6 @@
             return false;
         }
 
-        WindowContainerToken pipTaskToken = pipChange.getContainer();
-        if (pipTaskToken == null) {
-            return false;
-        }
-
-        WindowContainerTransaction finishWct = new WindowContainerTransaction();
-        SurfaceControl.Transaction tx = new SurfaceControl.Transaction();
-
         Rect startBounds = pipChange.getStartAbsBounds();
         Rect endBounds = pipChange.getEndAbsBounds();
         SurfaceControl pipLeash = mPipTransitionState.mPinnedTaskLeash;
@@ -405,29 +398,22 @@
             sourceRectHint = pipChange.getTaskInfo().pictureInPictureParams.getSourceRectHint();
         }
 
-        // For opening type transitions, if there is a non-pip change of mode TO_FRONT/OPEN,
+        // For opening type transitions, if there is a change of mode TO_FRONT/OPEN,
         // make sure that change has alpha of 1f, since it's init state might be set to alpha=0f
         // by the Transitions framework to simplify Task opening transitions.
         if (TransitionUtil.isOpeningType(info.getType())) {
             for (TransitionInfo.Change change : info.getChanges()) {
-                if (change.getLeash() == null || change == pipChange) continue;
+                if (change.getLeash() == null) continue;
                 if (change.getMode() == TRANSIT_OPEN || change.getMode() == TRANSIT_TO_FRONT) {
                     startTransaction.setAlpha(change.getLeash(), 1f);
                 }
             }
         }
 
-        PipEnterExitAnimator animator = new PipEnterExitAnimator(mContext, pipLeash,
-                startTransaction, finishTransaction, startBounds, startBounds, endBounds,
-                sourceRectHint, PipEnterExitAnimator.BOUNDS_ENTER, Surface.ROTATION_0);
-
-        tx.addTransactionCommittedListener(mPipScheduler.getMainExecutor(),
-                this::finishInner);
-        finishWct.setBoundsChangeTransaction(pipTaskToken, tx);
-
-        animator.setAnimationEndCallback(() ->
-                finishCallback.onTransitionFinished(finishWct));
-
+        PipEnterAnimator animator = new PipEnterAnimator(mContext, pipLeash,
+                startTransaction, finishTransaction, endBounds, sourceRectHint, Surface.ROTATION_0);
+        animator.setAnimationStartCallback(() -> animator.setEnterStartState(pipChange));
+        animator.setAnimationEndCallback(this::finishInner);
         animator.start();
         return true;
     }
@@ -452,11 +438,8 @@
 
         PipAlphaAnimator animator = new PipAlphaAnimator(mContext, pipLeash, startTransaction,
                 PipAlphaAnimator.FADE_IN);
-        animator.setAnimationEndCallback(() -> {
-            finishCallback.onTransitionFinished(null);
-            // This should update the pip transition state accordingly after we stop playing.
-            finishInner();
-        });
+        // This should update the pip transition state accordingly after we stop playing.
+        animator.setAnimationEndCallback(this::finishInner);
 
         animator.start();
         return true;
@@ -510,9 +493,9 @@
             sourceRectHint = mPipTaskListener.getPictureInPictureParams().getSourceRectHint();
         }
 
-        PipEnterExitAnimator animator = new PipEnterExitAnimator(mContext, pipLeash,
+        PipExpandAnimator animator = new PipExpandAnimator(mContext, pipLeash,
                 startTransaction, finishTransaction, endBounds, startBounds, endBounds,
-                sourceRectHint, PipEnterExitAnimator.BOUNDS_EXIT, Surface.ROTATION_0);
+                sourceRectHint, Surface.ROTATION_0);
 
         animator.setAnimationEndCallback(() -> {
             mPipTransitionState.setState(PipTransitionState.EXITED_PIP);
@@ -631,6 +614,7 @@
     //
 
     private void finishInner() {
+        finishTransition(null /* tx */);
         if (mPipTransitionState.getSwipePipToHomeOverlay() != null) {
             startOverlayFadeoutAnimation();
         } else if (mPipTransitionState.getState() == PipTransitionState.ENTERING_PIP) {
@@ -652,6 +636,7 @@
         }
         if (mFinishCallback != null) {
             mFinishCallback.onTransitionFinished(wct);
+            mFinishCallback = null;
         }
     }
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java
index 95cb3df..6086801 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java
@@ -38,8 +38,8 @@
 import android.util.Slog;
 import android.util.SparseArray;
 import android.util.SparseIntArray;
+import android.window.DesktopModeFlags;
 import android.window.WindowContainerToken;
-import android.window.flags.DesktopModeFlags;
 
 import androidx.annotation.BinderThread;
 import androidx.annotation.NonNull;
@@ -540,6 +540,14 @@
         return null;
     }
 
+    /**
+     * Remove the background task that match the given taskId. This will remove the task regardless
+     * of whether it's active or recent.
+     */
+    public boolean removeBackgroundTask(int taskId) {
+        return mActivityTaskManager.removeTask(taskId);
+    }
+
     public void dump(@NonNull PrintWriter pw, String prefix) {
         final String innerPrefix = prefix + "  ";
         pw.println(prefix + TAG);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/TaskStackTransitionObserver.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/TaskStackTransitionObserver.kt
index e5bfccf..1af99f9 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/TaskStackTransitionObserver.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/TaskStackTransitionObserver.kt
@@ -17,14 +17,12 @@
 package com.android.wm.shell.recents
 
 import android.app.ActivityManager.RunningTaskInfo
-import android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM
 import android.os.IBinder
 import android.util.ArrayMap
 import android.view.SurfaceControl
-import android.view.WindowManager
 import android.window.TransitionInfo
+import android.window.DesktopModeFlags
 import com.android.wm.shell.shared.TransitionUtil
-import android.window.flags.DesktopModeFlags
 import com.android.wm.shell.sysui.ShellInit
 import com.android.wm.shell.transition.Transitions
 import dagger.Lazy
@@ -40,16 +38,11 @@
     private val transitions: Lazy<Transitions>,
     shellInit: ShellInit
 ) : Transitions.TransitionObserver {
-
-    private val transitionToTransitionChanges: MutableMap<IBinder, TransitionChanges> =
-        mutableMapOf()
     private val taskStackTransitionObserverListeners =
         ArrayMap<TaskStackTransitionObserverListener, Executor>()
 
     init {
-        if (Transitions.ENABLE_SHELL_TRANSITIONS) {
-            shellInit.addInitCallback(::onInit, this)
-        }
+        shellInit.addInitCallback(::onInit, this)
     }
 
     fun onInit() {
@@ -63,9 +56,6 @@
         finishTransaction: SurfaceControl.Transaction
     ) {
         if (DesktopModeFlags.ENABLE_TASK_STACK_OBSERVER_IN_SHELL.isTrue) {
-            val taskInfoList = mutableListOf<RunningTaskInfo>()
-            val transitionTypeList = mutableListOf<Int>()
-
             for (change in info.changes) {
                 if (change.flags and TransitionInfo.FLAG_IS_WALLPAPER != 0) {
                     continue
@@ -76,59 +66,21 @@
                     continue
                 }
 
-                // Filter out changes that we care about
-                if (change.mode == WindowManager.TRANSIT_OPEN) {
-                    change.taskInfo?.let { taskInfoList.add(it) }
-                    transitionTypeList.add(change.mode)
+                // Find the first task that is opening, this should be the one at the front after
+                // the transition
+                if (TransitionUtil.isOpeningType(change.mode)) {
+                    notifyTaskStackTransitionObserverListeners(taskInfo)
+                    break
                 }
             }
-            // Only add the transition to map if it has a change we care about
-            if (taskInfoList.isNotEmpty()) {
-                transitionToTransitionChanges.put(
-                    transition,
-                    TransitionChanges(taskInfoList, transitionTypeList)
-                )
-            }
         }
     }
 
     override fun onTransitionStarting(transition: IBinder) {}
 
-    override fun onTransitionMerged(merged: IBinder, playing: IBinder) {
-        val mergedTransitionChanges =
-            transitionToTransitionChanges.get(merged)
-                ?:
-                // We are adding changes of the merged transition to changes of the playing
-                // transition so if there is no changes nothing to do.
-                return
+    override fun onTransitionMerged(merged: IBinder, playing: IBinder) {}
 
-        transitionToTransitionChanges.remove(merged)
-        val playingTransitionChanges = transitionToTransitionChanges.get(playing)
-        if (playingTransitionChanges != null) {
-            playingTransitionChanges.merge(mergedTransitionChanges)
-        } else {
-            transitionToTransitionChanges.put(playing, mergedTransitionChanges)
-        }
-    }
-
-    override fun onTransitionFinished(transition: IBinder, aborted: Boolean) {
-        val taskInfoList =
-            transitionToTransitionChanges.getOrDefault(transition, TransitionChanges()).taskInfoList
-        val typeList =
-            transitionToTransitionChanges
-                .getOrDefault(transition, TransitionChanges())
-                .transitionTypeList
-        transitionToTransitionChanges.remove(transition)
-
-        for ((index, taskInfo) in taskInfoList.withIndex()) {
-            if (
-                TransitionUtil.isOpeningType(typeList[index]) &&
-                    taskInfo.windowingMode == WINDOWING_MODE_FREEFORM
-            ) {
-                notifyTaskStackTransitionObserverListeners(taskInfo)
-            }
-        }
-    }
+    override fun onTransitionFinished(transition: IBinder, aborted: Boolean) {}
 
     fun addTaskStackTransitionObserverListener(
         taskStackTransitionObserverListener: TaskStackTransitionObserverListener,
@@ -154,14 +106,4 @@
         /** Called when a task is moved to front. */
         fun onTaskMovedToFrontThroughTransition(taskInfo: RunningTaskInfo) {}
     }
-
-    private data class TransitionChanges(
-        val taskInfoList: MutableList<RunningTaskInfo> = ArrayList(),
-        val transitionTypeList: MutableList<Int> = ArrayList(),
-    ) {
-        fun merge(transitionChanges: TransitionChanges) {
-            taskInfoList.addAll(transitionChanges.taskInfoList)
-            transitionTypeList.addAll(transitionChanges.transitionTypeList)
-        }
-    }
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/ISplitScreen.aidl b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/ISplitScreen.aidl
index 59aa792..cf2c3da 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/ISplitScreen.aidl
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/ISplitScreen.aidl
@@ -55,11 +55,6 @@
     oneway void unregisterSplitSelectListener(in ISplitSelectListener listener) = 21;
 
     /**
-     * Removes a task from the side stage.
-     */
-    oneway void removeFromSideStage(int taskId) = 4;
-
-    /**
      * Removes the split-screen stages and leaving indicated task to top. Passing INVALID_TASK_ID
      * to indicate leaving no top task after leaving split-screen.
      */
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
index 87b661d..9e39f44 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
@@ -322,6 +322,22 @@
         return mTaskOrganizer.getRunningTaskInfo(taskId);
     }
 
+    /**
+     * @return an Array of RunningTaskInfo's ordered by leftToRight or topTopBottom
+     */
+    @Nullable
+    public ActivityManager.RunningTaskInfo[] getAllTaskInfos() {
+        // TODO(b/349828130) Add the third stage task info and not rely on positions
+        ActivityManager.RunningTaskInfo topLeftTask = getTaskInfo(SPLIT_POSITION_TOP_OR_LEFT);
+        ActivityManager.RunningTaskInfo bottomRightTask =
+                getTaskInfo(SPLIT_POSITION_BOTTOM_OR_RIGHT);
+        if (topLeftTask != null && bottomRightTask != null) {
+            return new ActivityManager.RunningTaskInfo[]{topLeftTask, bottomRightTask};
+        }
+
+        return null;
+    }
+
     /** Check task is under split or not by taskId. */
     public boolean isTaskInSplitScreen(int taskId) {
         return mStageCoordinator.getStageOfTask(taskId) != STAGE_TYPE_UNDEFINED;
@@ -378,10 +394,6 @@
         return mStageCoordinator.moveToStage(task, stagePosition, wct);
     }
 
-    public boolean removeFromSideStage(int taskId) {
-        return mStageCoordinator.removeFromSideStage(taskId);
-    }
-
     public void setSideStagePosition(@SplitPosition int sideStagePosition) {
         mStageCoordinator.setSideStagePosition(sideStagePosition, null /* wct */);
     }
@@ -1177,12 +1189,6 @@
         }
 
         @Override
-        public void removeFromSideStage(int taskId) {
-            executeRemoteCallWithTaskPermission(mController, "removeFromSideStage",
-                    (controller) -> controller.removeFromSideStage(taskId));
-        }
-
-        @Override
         public void startTask(int taskId, int position, @Nullable Bundle options) {
             executeRemoteCallWithTaskPermission(mController, "startTask",
                     (controller) -> controller.startTask(taskId, position, options,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenShellCommandHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenShellCommandHandler.java
index e1b474d..a016a84 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenShellCommandHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenShellCommandHandler.java
@@ -40,8 +40,6 @@
         switch (args[0]) {
             case "moveToSideStage":
                 return runMoveToSideStage(args, pw);
-            case "removeFromSideStage":
-                return runRemoveFromSideStage(args, pw);
             case "setSideStagePosition":
                 return runSetSideStagePosition(args, pw);
             case "switchSplitPosition":
@@ -67,17 +65,6 @@
         return true;
     }
 
-    private boolean runRemoveFromSideStage(String[] args, PrintWriter pw) {
-        if (args.length < 2) {
-            // First argument is the action name.
-            pw.println("Error: task id should be provided as arguments");
-            return false;
-        }
-        final int taskId = new Integer(args[1]);
-        mController.removeFromSideStage(taskId);
-        return true;
-    }
-
     private boolean runSetSideStagePosition(String[] args, PrintWriter pw) {
         if (args.length < 2) {
             // First argument is the action name.
@@ -109,8 +96,6 @@
     public void printShellCommandHelp(PrintWriter pw, String prefix) {
         pw.println(prefix + "moveToSideStage <taskId> <SideStagePosition>");
         pw.println(prefix + "  Move a task with given id in split-screen mode.");
-        pw.println(prefix + "removeFromSideStage <taskId>");
-        pw.println(prefix + "  Remove a task with given id in split-screen mode.");
         pw.println(prefix + "setSideStagePosition <SideStagePosition>");
         pw.println(prefix + "  Sets the position of the side-stage.");
         pw.println(prefix + "switchSplitPosition");
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 e527c02..47c5eec 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
@@ -499,21 +499,6 @@
         return true;
     }
 
-    boolean removeFromSideStage(int taskId) {
-        ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "removeFromSideStage: task=%d", taskId);
-        final WindowContainerTransaction wct = new WindowContainerTransaction();
-
-
-        // MainStage will be deactivated in onStageHasChildrenChanged() if the other stages
-        // no longer have children.
-
-        final boolean result = mSideStage.removeTask(taskId,
-                isSplitActive() ? mMainStage.mRootTaskInfo.token : null,
-                wct);
-        mTaskOrganizer.applyTransaction(wct);
-        return result;
-    }
-
     SplitscreenEventLogger getLogger() {
         return mLogger;
     }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/FocusTransitionObserver.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/FocusTransitionObserver.java
index 399e39a..6d01e24 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/FocusTransitionObserver.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/FocusTransitionObserver.java
@@ -16,7 +16,8 @@
 
 package com.android.wm.shell.transition;
 
-import static android.view.Display.INVALID_DISPLAY;
+import static android.view.Display.DEFAULT_DISPLAY;
+import static android.view.WindowManager.TRANSIT_OPEN;
 import static android.window.TransitionInfo.FLAG_IS_DISPLAY;
 import static android.window.TransitionInfo.FLAG_MOVED_TO_TOP;
 
@@ -24,10 +25,11 @@
 import static com.android.wm.shell.transition.Transitions.TransitionObserver;
 
 import android.annotation.NonNull;
-import android.os.IBinder;
+import android.app.ActivityManager.RunningTaskInfo;
 import android.os.RemoteException;
+import android.util.ArraySet;
 import android.util.Slog;
-import android.view.SurfaceControl;
+import android.util.SparseArray;
 import android.window.TransitionInfo;
 
 import com.android.wm.shell.shared.FocusTransitionListener;
@@ -43,44 +45,64 @@
  * It reports transitions to callers outside of the process via {@link IFocusTransitionListener},
  * and callers within the process via {@link FocusTransitionListener}.
  */
-public class FocusTransitionObserver implements TransitionObserver {
+public class FocusTransitionObserver {
     private static final String TAG = FocusTransitionObserver.class.getSimpleName();
 
     private IFocusTransitionListener mRemoteListener;
     private final Map<FocusTransitionListener, Executor> mLocalListeners =
             new HashMap<>();
 
-    private int mFocusedDisplayId = INVALID_DISPLAY;
+    private int mFocusedDisplayId = DEFAULT_DISPLAY;
+    private final SparseArray<RunningTaskInfo> mFocusedTaskOnDisplay = new SparseArray<>();
+
+    private final ArraySet<RunningTaskInfo> mTmpTasksToBeNotified = new ArraySet<>();
 
     public FocusTransitionObserver() {}
 
-    @Override
-    public void onTransitionReady(@NonNull IBinder transition,
-            @NonNull TransitionInfo info,
-            @NonNull SurfaceControl.Transaction startTransaction,
-            @NonNull SurfaceControl.Transaction finishTransaction) {
+    /**
+     * Update display/window focus state from the given transition info and notifies changes if any.
+     */
+    public void updateFocusState(@NonNull TransitionInfo info) {
+        if (!enableDisplayFocusInShellTransitions()) {
+            return;
+        }
         final List<TransitionInfo.Change> changes = info.getChanges();
         for (int i = changes.size() - 1; i >= 0; i--) {
             final TransitionInfo.Change change = changes.get(i);
+
+            final RunningTaskInfo task = change.getTaskInfo();
+            if (task != null
+                    && (change.hasFlags(FLAG_MOVED_TO_TOP) || change.getMode() == TRANSIT_OPEN)) {
+                final RunningTaskInfo lastFocusedTaskOnDisplay =
+                        mFocusedTaskOnDisplay.get(task.displayId);
+                if (lastFocusedTaskOnDisplay != null) {
+                    mTmpTasksToBeNotified.add(lastFocusedTaskOnDisplay);
+                }
+                mTmpTasksToBeNotified.add(task);
+                mFocusedTaskOnDisplay.put(task.displayId, task);
+            }
+
             if (change.hasFlags(FLAG_IS_DISPLAY) && change.hasFlags(FLAG_MOVED_TO_TOP)) {
                 if (mFocusedDisplayId != change.getEndDisplayId()) {
+                    final RunningTaskInfo lastGloballyFocusedTask =
+                            mFocusedTaskOnDisplay.get(mFocusedDisplayId);
+                    if (lastGloballyFocusedTask != null) {
+                        mTmpTasksToBeNotified.add(lastGloballyFocusedTask);
+                    }
                     mFocusedDisplayId = change.getEndDisplayId();
                     notifyFocusedDisplayChanged();
+                    final RunningTaskInfo currentGloballyFocusedTask =
+                            mFocusedTaskOnDisplay.get(mFocusedDisplayId);
+                    if (currentGloballyFocusedTask != null) {
+                        mTmpTasksToBeNotified.add(currentGloballyFocusedTask);
+                    }
                 }
-                return;
             }
         }
+        mTmpTasksToBeNotified.forEach(this::notifyTaskFocusChanged);
+        mTmpTasksToBeNotified.clear();
     }
 
-    @Override
-    public void onTransitionStarting(@NonNull IBinder transition) {}
-
-    @Override
-    public void onTransitionMerged(@NonNull IBinder merged, @NonNull IBinder playing) {}
-
-    @Override
-    public void onTransitionFinished(@NonNull IBinder transition, boolean aborted) {}
-
     /**
      * Sets the focus transition listener that receives any transitions resulting in focus switch.
      * This is for calls from outside the Shell, within the host process.
@@ -92,7 +114,10 @@
             return;
         }
         mLocalListeners.put(listener, executor);
-        executor.execute(() -> listener.onFocusedDisplayChanged(mFocusedDisplayId));
+        executor.execute(() -> {
+            listener.onFocusedDisplayChanged(mFocusedDisplayId);
+            mTmpTasksToBeNotified.forEach(this::notifyTaskFocusChanged);
+        });
     }
 
     /**
@@ -120,13 +145,20 @@
         notifyFocusedDisplayChangedToRemote();
     }
 
-    /**
-     * Notifies the listener that display focus has changed.
-     */
-    public void notifyFocusedDisplayChanged() {
+    private void notifyTaskFocusChanged(RunningTaskInfo task) {
+        final boolean isFocusedOnDisplay = isFocusedOnDisplay(task);
+        final boolean isFocusedGlobally = hasGlobalFocus(task);
+        mLocalListeners.forEach((listener, executor) ->
+                executor.execute(() -> listener.onFocusedTaskChanged(task.taskId,
+                        isFocusedOnDisplay, isFocusedGlobally)));
+    }
+
+    private void notifyFocusedDisplayChanged() {
         notifyFocusedDisplayChangedToRemote();
         mLocalListeners.forEach((listener, executor) ->
-                executor.execute(() -> listener.onFocusedDisplayChanged(mFocusedDisplayId)));
+                executor.execute(() -> {
+                    listener.onFocusedDisplayChanged(mFocusedDisplayId);
+                }));
     }
 
     private void notifyFocusedDisplayChangedToRemote() {
@@ -138,4 +170,23 @@
             }
         }
     }
+
+    private boolean isFocusedOnDisplay(@NonNull RunningTaskInfo task) {
+        if (!enableDisplayFocusInShellTransitions()) {
+            return task.isFocused;
+        }
+        final RunningTaskInfo focusedTaskOnDisplay = mFocusedTaskOnDisplay.get(task.displayId);
+        return focusedTaskOnDisplay != null && focusedTaskOnDisplay.taskId == task.taskId;
+    }
+
+    /**
+     * Checks whether the given task has focused globally on the system.
+     * (Note {@link RunningTaskInfo#isFocused} represents per-display focus.)
+     */
+    public boolean hasGlobalFocus(@NonNull RunningTaskInfo task) {
+        if (!enableDisplayFocusInShellTransitions()) {
+            return task.isFocused;
+        }
+        return task.displayId == mFocusedDisplayId && isFocusedOnDisplay(task);
+    }
 }
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 d5e92e6..346f21b 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
@@ -392,8 +392,6 @@
 
         mShellCommandHandler.addCommandCallback("transitions", this, this);
         mShellCommandHandler.addDumpCallback(this::dump, this);
-
-        registerObserver(mFocusTransitionObserver);
     }
 
     public boolean isRegistered() {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java
index f5b2340..be4fd7c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java
@@ -58,9 +58,11 @@
 import com.android.wm.shell.common.ShellExecutor;
 import com.android.wm.shell.common.SyncTransactionQueue;
 import com.android.wm.shell.freeform.FreeformTaskTransitionStarter;
+import com.android.wm.shell.shared.FocusTransitionListener;
 import com.android.wm.shell.shared.annotations.ShellBackgroundThread;
 import com.android.wm.shell.splitscreen.SplitScreenController;
 import com.android.wm.shell.sysui.ShellInit;
+import com.android.wm.shell.transition.FocusTransitionObserver;
 import com.android.wm.shell.transition.Transitions;
 import com.android.wm.shell.windowdecor.extension.TaskInfoKt;
 
@@ -68,7 +70,7 @@
  * View model for the window decoration with a caption and shadows. Works with
  * {@link CaptionWindowDecoration}.
  */
-public class CaptionWindowDecorViewModel implements WindowDecorViewModel {
+public class CaptionWindowDecorViewModel implements WindowDecorViewModel, FocusTransitionListener {
     private static final String TAG = "CaptionWindowDecorViewModel";
 
     private final ShellTaskOrganizer mTaskOrganizer;
@@ -85,6 +87,7 @@
     private final Region mExclusionRegion = Region.obtain();
     private final InputManager mInputManager;
     private TaskOperations mTaskOperations;
+    private FocusTransitionObserver mFocusTransitionObserver;
 
     /**
      * Whether to pilfer the next motion event to send cancellations to the windows below.
@@ -121,7 +124,8 @@
             DisplayController displayController,
             RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer,
             SyncTransactionQueue syncQueue,
-            Transitions transitions) {
+            Transitions transitions,
+            FocusTransitionObserver focusTransitionObserver) {
         mContext = context;
         mMainExecutor = shellExecutor;
         mMainHandler = mainHandler;
@@ -133,6 +137,7 @@
         mRootTaskDisplayAreaOrganizer = rootTaskDisplayAreaOrganizer;
         mSyncQueue = syncQueue;
         mTransitions = transitions;
+        mFocusTransitionObserver = focusTransitionObserver;
         if (!Transitions.ENABLE_SHELL_TRANSITIONS) {
             mTaskOperations = new TaskOperations(null, mContext, mSyncQueue);
         }
@@ -148,6 +153,16 @@
         } catch (RemoteException e) {
             Log.e(TAG, "Failed to register window manager callbacks", e);
         }
+        mFocusTransitionObserver.setLocalFocusTransitionListener(this, mMainExecutor);
+    }
+
+    @Override
+    public void onFocusedTaskChanged(int taskId, boolean isFocusedOnDisplay,
+            boolean isFocusedGlobally) {
+        final WindowDecoration decor = mWindowDecorByTaskId.get(taskId);
+        if (decor != null) {
+            decor.relayout(decor.mTaskInfo, isFocusedGlobally);
+        }
     }
 
     @Override
@@ -180,7 +195,7 @@
             return;
         }
 
-        decoration.relayout(taskInfo);
+        decoration.relayout(taskInfo, decoration.mHasGlobalFocus);
     }
 
     @Override
@@ -217,7 +232,8 @@
             createWindowDecoration(taskInfo, taskSurface, startT, finishT);
         } else {
             decoration.relayout(taskInfo, startT, finishT, false /* applyStartTransactionOnDraw */,
-                    false /* setTaskCropAndPosition */);
+                    false /* setTaskCropAndPosition */,
+                    mFocusTransitionObserver.hasGlobalFocus(taskInfo));
         }
     }
 
@@ -230,7 +246,8 @@
         if (decoration == null) return;
 
         decoration.relayout(taskInfo, startT, finishT, false /* applyStartTransactionOnDraw */,
-                false /* setTaskCropAndPosition */);
+                false /* setTaskCropAndPosition */,
+                mFocusTransitionObserver.hasGlobalFocus(taskInfo));
     }
 
     @Override
@@ -308,7 +325,8 @@
         windowDecoration.setDragPositioningCallback(taskPositioner);
         windowDecoration.setTaskDragResizer(taskPositioner);
         windowDecoration.relayout(taskInfo, startT, finishT,
-                false /* applyStartTransactionOnDraw */, false /* setTaskCropAndPosition */);
+                false /* applyStartTransactionOnDraw */, false /* setTaskCropAndPosition */,
+                mFocusTransitionObserver.hasGlobalFocus(taskInfo));
     }
 
     private class CaptionTouchEventListener implements
@@ -359,9 +377,9 @@
             }
             if (e.getAction() == MotionEvent.ACTION_DOWN) {
                 final RunningTaskInfo taskInfo = mTaskOrganizer.getRunningTaskInfo(mTaskId);
-                if (!taskInfo.isFocused) {
+                if (!mFocusTransitionObserver.hasGlobalFocus(taskInfo)) {
                     final WindowContainerTransaction wct = new WindowContainerTransaction();
-                    wct.reorder(mTaskToken, true /* onTop */);
+                    wct.reorder(mTaskToken, true /* onTop */, true /* includingParents */);
                     mSyncQueue.queue(wct);
                 }
             }
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 839973f..509cb85 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
@@ -16,7 +16,7 @@
 
 package com.android.wm.shell.windowdecor;
 
-import static android.window.flags.DesktopModeFlags.ENABLE_WINDOWING_SCALED_RESIZING;
+import static android.window.DesktopModeFlags.ENABLE_WINDOWING_SCALED_RESIZING;
 
 import static com.android.wm.shell.windowdecor.DragResizeWindowGeometry.getFineResizeCornerSize;
 import static com.android.wm.shell.windowdecor.DragResizeWindowGeometry.getLargeResizeCornerSize;
@@ -174,7 +174,7 @@
     }
 
     @Override
-    void relayout(RunningTaskInfo taskInfo) {
+    void relayout(RunningTaskInfo taskInfo, boolean hasGlobalFocus) {
         final SurfaceControl.Transaction t = new SurfaceControl.Transaction();
         // The crop and position of the task should only be set when a task is fluid resizing. In
         // all other cases, it is expected that the transition handler positions and crops the task
@@ -185,7 +185,7 @@
         // synced with the buffer transaction (that draws the View). Both will be shown on screen
         // at the same, whereas applying them independently causes flickering. See b/270202228.
         relayout(taskInfo, t, t, true /* applyStartTransactionOnDraw */,
-                shouldSetTaskPositionAndCrop);
+                shouldSetTaskPositionAndCrop, hasGlobalFocus);
     }
 
     @VisibleForTesting
@@ -196,12 +196,13 @@
             boolean setTaskCropAndPosition,
             boolean isStatusBarVisible,
             boolean isKeyguardVisibleAndOccluded,
-            InsetsState displayInsetsState) {
+            InsetsState displayInsetsState,
+            boolean hasGlobalFocus) {
         relayoutParams.reset();
         relayoutParams.mRunningTaskInfo = taskInfo;
         relayoutParams.mLayoutResId = R.layout.caption_window_decor;
         relayoutParams.mCaptionHeightId = getCaptionHeightIdStatic(taskInfo.getWindowingMode());
-        relayoutParams.mShadowRadiusId = taskInfo.isFocused
+        relayoutParams.mShadowRadiusId = hasGlobalFocus
                 ? R.dimen.freeform_decor_shadow_focused_thickness
                 : R.dimen.freeform_decor_shadow_unfocused_thickness;
         relayoutParams.mApplyStartTransactionOnDraw = applyStartTransactionOnDraw;
@@ -233,7 +234,8 @@
     @SuppressLint("MissingPermission")
     void relayout(RunningTaskInfo taskInfo,
             SurfaceControl.Transaction startT, SurfaceControl.Transaction finishT,
-            boolean applyStartTransactionOnDraw, boolean setTaskCropAndPosition) {
+            boolean applyStartTransactionOnDraw, boolean setTaskCropAndPosition,
+            boolean hasGlobalFocus) {
         final boolean isFreeform =
                 taskInfo.getWindowingMode() == WindowConfiguration.WINDOWING_MODE_FREEFORM;
         final boolean isDragResizeable = ENABLE_WINDOWING_SCALED_RESIZING.isTrue()
@@ -245,7 +247,7 @@
 
         updateRelayoutParams(mRelayoutParams, taskInfo, applyStartTransactionOnDraw,
                 setTaskCropAndPosition, mIsStatusBarVisible, mIsKeyguardVisibleAndOccluded,
-                mDisplayController.getInsetsState(taskInfo.displayId));
+                mDisplayController.getInsetsState(taskInfo.displayId), hasGlobalFocus);
 
         relayout(mRelayoutParams, startT, finishT, wct, oldRootView, mResult);
         // After this line, mTaskInfo is up-to-date and should be used instead of taskInfo
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 bcf48d9..9e089b2 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
@@ -56,7 +56,6 @@
 import android.graphics.Region;
 import android.hardware.input.InputManager;
 import android.os.Handler;
-import android.os.IBinder;
 import android.os.Looper;
 import android.os.RemoteException;
 import android.os.UserHandle;
@@ -77,10 +76,10 @@
 import android.view.View;
 import android.view.ViewConfiguration;
 import android.widget.Toast;
+import android.window.DesktopModeFlags;
 import android.window.TaskSnapshot;
 import android.window.WindowContainerToken;
 import android.window.WindowContainerTransaction;
-import android.window.flags.DesktopModeFlags;
 
 import androidx.annotation.Nullable;
 import androidx.annotation.OptIn;
@@ -103,8 +102,8 @@
 import com.android.wm.shell.common.ShellExecutor;
 import com.android.wm.shell.common.SyncTransactionQueue;
 import com.android.wm.shell.desktopmode.DesktopActivityOrientationChangeHandler;
-import com.android.wm.shell.desktopmode.DesktopRepository;
 import com.android.wm.shell.desktopmode.DesktopModeVisualIndicator;
+import com.android.wm.shell.desktopmode.DesktopRepository;
 import com.android.wm.shell.desktopmode.DesktopTasksController;
 import com.android.wm.shell.desktopmode.DesktopTasksController.SnapPosition;
 import com.android.wm.shell.desktopmode.DesktopTasksLimiter;
@@ -112,6 +111,7 @@
 import com.android.wm.shell.desktopmode.WindowDecorCaptionHandleRepository;
 import com.android.wm.shell.desktopmode.education.AppHandleEducationController;
 import com.android.wm.shell.freeform.FreeformTaskTransitionStarter;
+import com.android.wm.shell.shared.FocusTransitionListener;
 import com.android.wm.shell.shared.annotations.ShellBackgroundThread;
 import com.android.wm.shell.shared.annotations.ShellMainThread;
 import com.android.wm.shell.shared.desktopmode.DesktopModeStatus;
@@ -124,6 +124,7 @@
 import com.android.wm.shell.sysui.ShellCommandHandler;
 import com.android.wm.shell.sysui.ShellController;
 import com.android.wm.shell.sysui.ShellInit;
+import com.android.wm.shell.transition.FocusTransitionObserver;
 import com.android.wm.shell.transition.Transitions;
 import com.android.wm.shell.windowdecor.DesktopModeWindowDecoration.ExclusionRegionListener;
 import com.android.wm.shell.windowdecor.extension.InsetsStateKt;
@@ -146,7 +147,8 @@
  * {@link DesktopModeWindowDecoration}.
  */
 
-public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
+public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel,
+        FocusTransitionListener {
     private static final String TAG = "DesktopModeWindowDecorViewModel";
 
     private final DesktopModeWindowDecoration.Factory mDesktopModeWindowDecorFactory;
@@ -216,6 +218,7 @@
                 }
             };
     private final TaskPositionerFactory mTaskPositionerFactory;
+    private final FocusTransitionObserver mFocusTransitionObserver;
 
     public DesktopModeWindowDecorViewModel(
             Context context,
@@ -242,7 +245,8 @@
             Optional<DesktopTasksLimiter> desktopTasksLimiter,
             AppHandleEducationController appHandleEducationController,
             WindowDecorCaptionHandleRepository windowDecorCaptionHandleRepository,
-            Optional<DesktopActivityOrientationChangeHandler> activityOrientationChangeHandler) {
+            Optional<DesktopActivityOrientationChangeHandler> activityOrientationChangeHandler,
+            FocusTransitionObserver focusTransitionObserver) {
         this(
                 context,
                 shellExecutor,
@@ -274,7 +278,8 @@
                 appHandleEducationController,
                 windowDecorCaptionHandleRepository,
                 activityOrientationChangeHandler,
-                new TaskPositionerFactory());
+                new TaskPositionerFactory(),
+                focusTransitionObserver);
     }
 
     @VisibleForTesting
@@ -309,7 +314,8 @@
             AppHandleEducationController appHandleEducationController,
             WindowDecorCaptionHandleRepository windowDecorCaptionHandleRepository,
             Optional<DesktopActivityOrientationChangeHandler> activityOrientationChangeHandler,
-            TaskPositionerFactory taskPositionerFactory) {
+            TaskPositionerFactory taskPositionerFactory,
+            FocusTransitionObserver focusTransitionObserver) {
         mContext = context;
         mMainExecutor = shellExecutor;
         mMainHandler = mainHandler;
@@ -369,6 +375,7 @@
             }
         };
         mTaskPositionerFactory = taskPositionerFactory;
+        mFocusTransitionObserver = focusTransitionObserver;
 
         shellInit.addInitCallback(this::onInit, this);
     }
@@ -402,11 +409,22 @@
                         return Unit.INSTANCE;
                     });
         }
+        mFocusTransitionObserver.setLocalFocusTransitionListener(this, mMainExecutor);
+    }
+
+    @Override
+    public void onFocusedTaskChanged(int taskId, boolean isFocusedOnDisplay,
+            boolean isFocusedGlobally) {
+        final WindowDecoration decor = mWindowDecorByTaskId.get(taskId);
+        if (decor != null) {
+            decor.relayout(decor.mTaskInfo, isFocusedGlobally);
+        }
     }
 
     @Override
     public void setFreeformTaskTransitionStarter(FreeformTaskTransitionStarter transitionStarter) {
         mTaskOperations = new TaskOperations(transitionStarter, mContext, mSyncQueue);
+        mDesktopTasksController.setFreeformTaskTransitionStarter(transitionStarter);
     }
 
     @Override
@@ -447,7 +465,7 @@
             removeTaskFromEventReceiver(oldTaskInfo.displayId);
             incrementEventReceiverTasks(taskInfo.displayId);
         }
-        decoration.relayout(taskInfo);
+        decoration.relayout(taskInfo, decoration.mHasGlobalFocus);
         mActivityOrientationChangeHandler.ifPresent(handler ->
                 handler.handleActivityOrientationChange(oldTaskInfo, taskInfo));
     }
@@ -486,7 +504,8 @@
             createWindowDecoration(taskInfo, taskSurface, startT, finishT);
         } else {
             decoration.relayout(taskInfo, startT, finishT, false /* applyStartTransactionOnDraw */,
-                    false /* shouldSetTaskPositionAndCrop */);
+                    false /* shouldSetTaskPositionAndCrop */,
+                    mFocusTransitionObserver.hasGlobalFocus(taskInfo));
         }
     }
 
@@ -499,7 +518,8 @@
         if (decoration == null) return;
 
         decoration.relayout(taskInfo, startT, finishT, false /* applyStartTransactionOnDraw */,
-                false /* shouldSetTaskPositionAndCrop */);
+                false /* shouldSetTaskPositionAndCrop */,
+                mFocusTransitionObserver.hasGlobalFocus(taskInfo));
     }
 
     @Override
@@ -774,11 +794,7 @@
                     onMaximizeOrRestore(decoration.mTaskInfo.taskId, "caption_bar_button");
                 }
             } else if (id == R.id.minimize_window) {
-                final WindowContainerTransaction wct = new WindowContainerTransaction();
-                mDesktopTasksController.onDesktopWindowMinimize(wct, mTaskId);
-                final IBinder transition = mTaskOperations.minimizeTask(mTaskToken, wct);
-                mDesktopTasksLimiter.ifPresent(limiter ->
-                        limiter.addPendingMinimizeChange(transition, mDisplayId, mTaskId));
+                mDesktopTasksController.minimizeTask(decoration.mTaskInfo);
             }
         }
 
@@ -895,7 +911,7 @@
         }
 
         private void moveTaskToFront(RunningTaskInfo taskInfo) {
-            if (!taskInfo.isFocused) {
+            if (!mFocusTransitionObserver.hasGlobalFocus(taskInfo)) {
                 mDesktopTasksController.moveTaskToFront(taskInfo);
             }
         }
@@ -1516,7 +1532,8 @@
         windowDecoration.setExclusionRegionListener(mExclusionRegionListener);
         windowDecoration.setDragPositioningCallback(taskPositioner);
         windowDecoration.relayout(taskInfo, startT, finishT,
-                false /* applyStartTransactionOnDraw */, false /* shouldSetTaskPositionAndCrop */);
+                false /* applyStartTransactionOnDraw */, false /* shouldSetTaskPositionAndCrop */,
+                mFocusTransitionObserver.hasGlobalFocus(taskInfo));
         if (!Flags.enableHandleInputFix()) {
             incrementEventReceiverTasks(taskInfo.displayId);
         }
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 25d37fc..2c621b1f 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
@@ -24,8 +24,8 @@
 import static android.view.MotionEvent.ACTION_CANCEL;
 import static android.view.MotionEvent.ACTION_DOWN;
 import static android.view.MotionEvent.ACTION_UP;
-import static android.window.flags.DesktopModeFlags.ENABLE_CAPTION_COMPAT_INSET_FORCE_CONSUMPTION;
-import static android.window.flags.DesktopModeFlags.ENABLE_CAPTION_COMPAT_INSET_FORCE_CONSUMPTION_ALWAYS;
+import static android.window.DesktopModeFlags.ENABLE_CAPTION_COMPAT_INSET_FORCE_CONSUMPTION;
+import static android.window.DesktopModeFlags.ENABLE_CAPTION_COMPAT_INSET_FORCE_CONSUMPTION_ALWAYS;
 
 import static com.android.launcher3.icons.BaseIconFactory.MODE_DEFAULT;
 import static com.android.wm.shell.shared.desktopmode.DesktopModeStatus.canEnterDesktopMode;
@@ -72,9 +72,9 @@
 import android.view.WindowInsets;
 import android.view.WindowManager;
 import android.widget.ImageButton;
+import android.window.DesktopModeFlags;
 import android.window.TaskSnapshot;
 import android.window.WindowContainerTransaction;
-import android.window.flags.DesktopModeFlags;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.policy.ScreenDecorationsUtils;
@@ -352,7 +352,7 @@
     }
 
     @Override
-    void relayout(ActivityManager.RunningTaskInfo taskInfo) {
+    void relayout(ActivityManager.RunningTaskInfo taskInfo, boolean hasGlobalFocus) {
         final SurfaceControl.Transaction t = mSurfaceControlTransactionSupplier.get();
         // The crop and position of the task should only be set when a task is fluid resizing. In
         // all other cases, it is expected that the transition handler positions and crops the task
@@ -365,7 +365,8 @@
         // the View). Both will be shown on screen at the same, whereas applying them independently
         // causes flickering. See b/270202228.
         final boolean applyTransactionOnDraw = taskInfo.isFreeform();
-        relayout(taskInfo, t, t, applyTransactionOnDraw, shouldSetTaskPositionAndCrop);
+        relayout(taskInfo, t, t, applyTransactionOnDraw, shouldSetTaskPositionAndCrop,
+                hasGlobalFocus);
         if (!applyTransactionOnDraw) {
             t.apply();
         }
@@ -373,18 +374,19 @@
 
     void relayout(ActivityManager.RunningTaskInfo taskInfo,
             SurfaceControl.Transaction startT, SurfaceControl.Transaction finishT,
-            boolean applyStartTransactionOnDraw, boolean shouldSetTaskPositionAndCrop) {
+            boolean applyStartTransactionOnDraw, boolean shouldSetTaskPositionAndCrop,
+            boolean hasGlobalFocus) {
         Trace.beginSection("DesktopModeWindowDecoration#relayout");
         if (taskInfo.isFreeform()) {
             // The Task is in Freeform mode -> show its header in sync since it's an integral part
             // of the window itself - a delayed header might cause bad UX.
             relayoutInSync(taskInfo, startT, finishT, applyStartTransactionOnDraw,
-                    shouldSetTaskPositionAndCrop);
+                    shouldSetTaskPositionAndCrop, hasGlobalFocus);
         } else {
             // The Task is outside Freeform mode -> allow the handle view to be delayed since the
             // handle is just a small addition to the window.
             relayoutWithDelayedViewHost(taskInfo, startT, finishT, applyStartTransactionOnDraw,
-                    shouldSetTaskPositionAndCrop);
+                    shouldSetTaskPositionAndCrop, hasGlobalFocus);
         }
         Trace.endSection();
     }
@@ -392,11 +394,12 @@
     /** Run the whole relayout phase immediately without delay. */
     private void relayoutInSync(ActivityManager.RunningTaskInfo taskInfo,
             SurfaceControl.Transaction startT, SurfaceControl.Transaction finishT,
-            boolean applyStartTransactionOnDraw, boolean shouldSetTaskPositionAndCrop) {
+            boolean applyStartTransactionOnDraw, boolean shouldSetTaskPositionAndCrop,
+            boolean hasGlobalFocus) {
         // Clear the current ViewHost runnable as we will update the ViewHost here
         clearCurrentViewHostRunnable();
         updateRelayoutParamsAndSurfaces(taskInfo, startT, finishT, applyStartTransactionOnDraw,
-                shouldSetTaskPositionAndCrop);
+                shouldSetTaskPositionAndCrop, hasGlobalFocus);
         if (mResult.mRootView != null) {
             updateViewHost(mRelayoutParams, startT, mResult);
         }
@@ -418,7 +421,8 @@
      */
     private void relayoutWithDelayedViewHost(ActivityManager.RunningTaskInfo taskInfo,
             SurfaceControl.Transaction startT, SurfaceControl.Transaction finishT,
-            boolean applyStartTransactionOnDraw, boolean shouldSetTaskPositionAndCrop) {
+            boolean applyStartTransactionOnDraw, boolean shouldSetTaskPositionAndCrop,
+            boolean hasGlobalFocus) {
         if (applyStartTransactionOnDraw) {
             throw new IllegalArgumentException(
                     "We cannot both sync viewhost ondraw and delay viewhost creation.");
@@ -426,7 +430,8 @@
         // Clear the current ViewHost runnable as we will update the ViewHost here
         clearCurrentViewHostRunnable();
         updateRelayoutParamsAndSurfaces(taskInfo, startT, finishT,
-                false /* applyStartTransactionOnDraw */, shouldSetTaskPositionAndCrop);
+                false /* applyStartTransactionOnDraw */, shouldSetTaskPositionAndCrop,
+                hasGlobalFocus);
         if (mResult.mRootView == null) {
             // This means something blocks the window decor from showing, e.g. the task is hidden.
             // Nothing is set up in this case including the decoration surface.
@@ -440,7 +445,8 @@
     @SuppressLint("MissingPermission")
     private void updateRelayoutParamsAndSurfaces(ActivityManager.RunningTaskInfo taskInfo,
             SurfaceControl.Transaction startT, SurfaceControl.Transaction finishT,
-            boolean applyStartTransactionOnDraw, boolean shouldSetTaskPositionAndCrop) {
+            boolean applyStartTransactionOnDraw, boolean shouldSetTaskPositionAndCrop,
+            boolean hasGlobalFocus) {
         Trace.beginSection("DesktopModeWindowDecoration#updateRelayoutParamsAndSurfaces");
 
         if (Flags.enableDesktopWindowingAppToWeb()) {
@@ -459,7 +465,8 @@
                 .isTaskInFullImmersiveState(taskInfo.taskId);
         updateRelayoutParams(mRelayoutParams, mContext, taskInfo, applyStartTransactionOnDraw,
                 shouldSetTaskPositionAndCrop, mIsStatusBarVisible, mIsKeyguardVisibleAndOccluded,
-                inFullImmersive, mDisplayController.getInsetsState(taskInfo.displayId));
+                inFullImmersive, mDisplayController.getInsetsState(taskInfo.displayId),
+                hasGlobalFocus);
 
         final WindowDecorLinearLayout oldRootView = mResult.mRootView;
         final SurfaceControl oldDecorationSurface = mDecorationContainerSurface;
@@ -507,12 +514,13 @@
             ));
         } else {
             mWindowDecorViewHolder.bindData(new AppHeaderViewHolder.HeaderData(
-                    mTaskInfo, TaskInfoKt.getRequestingImmersive(mTaskInfo), inFullImmersive
+                    mTaskInfo, TaskInfoKt.getRequestingImmersive(mTaskInfo), inFullImmersive,
+                    hasGlobalFocus
             ));
         }
         Trace.endSection();
 
-        if (!mTaskInfo.isFocused) {
+        if (!hasGlobalFocus) {
             closeHandleMenu();
             closeManageWindowsMenu();
             closeMaximizeMenu();
@@ -780,7 +788,8 @@
             boolean isStatusBarVisible,
             boolean isKeyguardVisibleAndOccluded,
             boolean inFullImmersiveMode,
-            @NonNull InsetsState displayInsetsState) {
+            @NonNull InsetsState displayInsetsState,
+            boolean hasGlobalFocus) {
         final int captionLayoutId = getDesktopModeWindowDecorLayoutId(taskInfo.getWindowingMode());
         final boolean isAppHeader =
                 captionLayoutId == R.layout.desktop_mode_app_header;
@@ -790,6 +799,7 @@
         relayoutParams.mLayoutResId = captionLayoutId;
         relayoutParams.mCaptionHeightId = getCaptionHeightIdStatic(taskInfo.getWindowingMode());
         relayoutParams.mCaptionWidthId = getCaptionWidthId(relayoutParams.mLayoutResId);
+        relayoutParams.mHasGlobalFocus = hasGlobalFocus;
 
         final boolean showCaption;
         if (Flags.enableFullyImmersiveInDesktop()) {
@@ -812,7 +822,7 @@
                     || (isStatusBarVisible && !isKeyguardVisibleAndOccluded);
         }
         relayoutParams.mIsCaptionVisible = showCaption;
-
+        relayoutParams.mIsInsetSource = isAppHeader && !inFullImmersiveMode;
         if (isAppHeader) {
             if (TaskInfoKt.isTransparentCaptionBarAppearance(taskInfo)) {
                 // If the app is requesting to customize the caption bar, allow input to fall
@@ -837,7 +847,6 @@
                         WindowInsets.Type.systemBars() & ~WindowInsets.Type.captionBar(),
                         false /* ignoreVisibility */);
                 relayoutParams.mCaptionTopPadding = systemBarInsets.top;
-                relayoutParams.mIsInsetSource = false;
             }
             // Report occluding elements as bounding rects to the insets system so that apps can
             // draw in the empty space in the center:
@@ -865,8 +874,8 @@
             relayoutParams.mInputFeatures
                     |= WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL;
         }
-        if (DesktopModeStatus.useWindowShadow(/* isFocusedWindow= */ taskInfo.isFocused)) {
-            relayoutParams.mShadowRadiusId = taskInfo.isFocused
+        if (DesktopModeStatus.useWindowShadow(/* isFocusedWindow= */ hasGlobalFocus)) {
+            relayoutParams.mShadowRadiusId = hasGlobalFocus
                     ? R.dimen.freeform_decor_shadow_focused_thickness
                     : R.dimen.freeform_decor_shadow_unfocused_thickness;
         }
@@ -1408,7 +1417,7 @@
     }
 
     boolean isFocused() {
-        return mTaskInfo.isFocused;
+        return mHasGlobalFocus;
     }
 
     /**
@@ -1592,7 +1601,7 @@
 
     private static int getCaptionHeightIdStatic(@WindowingMode int windowingMode) {
         return windowingMode == WINDOWING_MODE_FULLSCREEN
-                ? R.dimen.desktop_mode_fullscreen_decor_caption_height
+                ? com.android.internal.R.dimen.status_bar_height_default
                 : R.dimen.desktop_mode_freeform_decor_caption_height;
     }
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragPositioningCallbackUtility.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragPositioningCallbackUtility.java
index 38f9cfa..60c9222 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragPositioningCallbackUtility.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragPositioningCallbackUtility.java
@@ -27,7 +27,7 @@
 import android.graphics.Rect;
 import android.util.DisplayMetrics;
 import android.view.SurfaceControl;
-import android.window.flags.DesktopModeFlags;
+import android.window.DesktopModeFlags;
 
 import androidx.annotation.NonNull;
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeWindowGeometry.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeWindowGeometry.java
index d726f50..33d1c26 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeWindowGeometry.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeWindowGeometry.java
@@ -18,7 +18,7 @@
 
 import static android.view.InputDevice.SOURCE_MOUSE;
 import static android.view.InputDevice.SOURCE_TOUCHSCREEN;
-import static android.window.flags.DesktopModeFlags.ENABLE_WINDOWING_EDGE_DRAG_RESIZE;
+import static android.window.DesktopModeFlags.ENABLE_WINDOWING_EDGE_DRAG_RESIZE;
 
 import static com.android.wm.shell.windowdecor.DragPositioningCallback.CTRL_TYPE_BOTTOM;
 import static com.android.wm.shell.windowdecor.DragPositioningCallback.CTRL_TYPE_LEFT;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/FluidResizeTaskPositioner.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/FluidResizeTaskPositioner.java
index 3853f1f..ccf329c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/FluidResizeTaskPositioner.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/FluidResizeTaskPositioner.java
@@ -93,9 +93,10 @@
                 mWindowDecoration.mTaskInfo.configuration.windowConfiguration.getBounds());
         mRepositionStartPoint.set(x, y);
         mDragStartListener.onDragStart(mWindowDecoration.mTaskInfo.taskId);
-        if (mCtrlType != CTRL_TYPE_UNDEFINED && !mWindowDecoration.mTaskInfo.isFocused) {
+        if (mCtrlType != CTRL_TYPE_UNDEFINED && !mWindowDecoration.mHasGlobalFocus) {
             WindowContainerTransaction wct = new WindowContainerTransaction();
-            wct.reorder(mWindowDecoration.mTaskInfo.token, true);
+            wct.reorder(mWindowDecoration.mTaskInfo.token, true /* onTop */,
+                    true /* includingParents */);
             mTaskOrganizer.applyTransaction(wct);
         }
         mRepositionTaskBounds.set(mTaskBoundsAtDragStart);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/MaximizeButtonView.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/MaximizeButtonView.kt
index 68a58ee0..376cd2a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/MaximizeButtonView.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/MaximizeButtonView.kt
@@ -33,7 +33,7 @@
 import androidx.core.animation.doOnStart
 import androidx.core.content.ContextCompat
 import com.android.wm.shell.R
-import android.window.flags.DesktopModeFlags
+import android.window.DesktopModeFlags
 
 private const val OPEN_MAXIMIZE_MENU_DELAY_ON_HOVER_MS = 350
 private const val MAX_DRAWABLE_ALPHA = 255
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/VeiledResizeTaskPositioner.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/VeiledResizeTaskPositioner.java
index 6eb5cca..ff3b455 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/VeiledResizeTaskPositioner.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/VeiledResizeTaskPositioner.java
@@ -106,9 +106,10 @@
             // Capture CUJ for re-sizing window in DW mode.
             mInteractionJankMonitor.begin(mDesktopWindowDecoration.mTaskSurface,
                     mDesktopWindowDecoration.mContext, mHandler, CUJ_DESKTOP_MODE_RESIZE_WINDOW);
-            if (!mDesktopWindowDecoration.mTaskInfo.isFocused) {
+            if (!mDesktopWindowDecoration.mHasGlobalFocus) {
                 WindowContainerTransaction wct = new WindowContainerTransaction();
-                wct.reorder(mDesktopWindowDecoration.mTaskInfo.token, true);
+                wct.reorder(mDesktopWindowDecoration.mTaskInfo.token, true /* onTop */,
+                        true /* includingParents */);
                 mTaskOrganizer.applyTransaction(wct);
             }
         }
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 f8aed41..ce5cfd0 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
@@ -125,7 +125,7 @@
                     }
 
                     mDisplayController.removeDisplayWindowListener(this);
-                    relayout(mTaskInfo);
+                    relayout(mTaskInfo, mHasGlobalFocus);
                 }
             };
 
@@ -146,6 +146,7 @@
 
     boolean mIsStatusBarVisible;
     boolean mIsKeyguardVisibleAndOccluded;
+    boolean mHasGlobalFocus;
 
     /** The most recent set of insets applied to this window decoration. */
     private WindowDecorationInsets mWindowDecorationInsets;
@@ -199,8 +200,9 @@
      *
      * @param taskInfo The previous {@link RunningTaskInfo} passed into {@link #relayout} or the
      *                 constructor.
+     * @param hasGlobalFocus Whether the task is focused
      */
-    abstract void relayout(RunningTaskInfo taskInfo);
+    abstract void relayout(RunningTaskInfo taskInfo, boolean hasGlobalFocus);
 
     /**
      * Used by the {@link DragPositioningCallback} associated with the implementing class to
@@ -225,6 +227,7 @@
         if (params.mRunningTaskInfo != null) {
             mTaskInfo = params.mRunningTaskInfo;
         }
+        mHasGlobalFocus = params.mHasGlobalFocus;
         final int oldLayoutResId = mLayoutResId;
         mLayoutResId = params.mLayoutResId;
 
@@ -246,7 +249,7 @@
         final Rect taskBounds = mTaskInfo.getConfiguration().windowConfiguration.getBounds();
         outResult.mWidth = taskBounds.width();
         outResult.mHeight = taskBounds.height();
-        outResult.mRootView.setTaskFocusState(mTaskInfo.isFocused);
+        outResult.mRootView.setTaskFocusState(mHasGlobalFocus);
         final Resources resources = mDecorWindowContext.getResources();
         outResult.mCaptionHeight = loadDimensionPixelSize(resources, params.mCaptionHeightId)
                 + params.mCaptionTopPadding;
@@ -391,11 +394,11 @@
 
         final WindowDecorationInsets newInsets = new WindowDecorationInsets(
                 mTaskInfo.token, mOwner, captionInsetsRect, boundingRects,
-                params.mInsetSourceFlags);
+                params.mInsetSourceFlags, params.mIsInsetSource);
         if (!newInsets.equals(mWindowDecorationInsets)) {
             // Add or update this caption as an insets source.
             mWindowDecorationInsets = newInsets;
-            mWindowDecorationInsets.addOrUpdate(wct);
+            mWindowDecorationInsets.update(wct);
         }
     }
 
@@ -512,7 +515,7 @@
         mIsKeyguardVisibleAndOccluded = visible && occluded;
         final boolean changed = prevVisAndOccluded != mIsKeyguardVisibleAndOccluded;
         if (changed) {
-            relayout(mTaskInfo);
+            relayout(mTaskInfo, mHasGlobalFocus);
         }
     }
 
@@ -522,7 +525,7 @@
         final boolean changed = prevStatusBarVisibility != mIsStatusBarVisible;
 
         if (changed) {
-            relayout(mTaskInfo);
+            relayout(mTaskInfo, mHasGlobalFocus);
         }
     }
 
@@ -710,10 +713,11 @@
         final int captionHeight = loadDimensionPixelSize(mContext.getResources(), captionHeightId);
         final Rect captionInsets = new Rect(0, 0, 0, captionHeight);
         final WindowDecorationInsets newInsets = new WindowDecorationInsets(mTaskInfo.token,
-                mOwner, captionInsets, null /* boundingRets */, 0 /* flags */);
+                mOwner, captionInsets, null /* boundingRets */, 0 /* flags */,
+                true /* shouldAddCaptionInset */);
         if (!newInsets.equals(mWindowDecorationInsets)) {
             mWindowDecorationInsets = newInsets;
-            mWindowDecorationInsets.addOrUpdate(wct);
+            mWindowDecorationInsets.update(wct);
         }
     }
 
@@ -737,6 +741,7 @@
 
         boolean mApplyStartTransactionOnDraw;
         boolean mSetTaskPositionAndCrop;
+        boolean mHasGlobalFocus;
 
         void reset() {
             mLayoutResId = Resources.ID_NULL;
@@ -756,6 +761,7 @@
             mApplyStartTransactionOnDraw = false;
             mSetTaskPositionAndCrop = false;
             mWindowDecorConfig = null;
+            mHasGlobalFocus = false;
         }
 
         boolean hasInputFeatureSpy() {
@@ -814,21 +820,26 @@
         private final Rect mFrame;
         private final Rect[] mBoundingRects;
         private final @InsetsSource.Flags int mFlags;
+        private final boolean mShouldAddCaptionInset;
 
         private WindowDecorationInsets(WindowContainerToken token, Binder owner, Rect frame,
-                Rect[] boundingRects, @InsetsSource.Flags int flags) {
+                Rect[] boundingRects, @InsetsSource.Flags int flags,
+                boolean shouldAddCaptionInset) {
             mToken = token;
             mOwner = owner;
             mFrame = frame;
             mBoundingRects = boundingRects;
             mFlags = flags;
+            mShouldAddCaptionInset = shouldAddCaptionInset;
         }
 
-        void addOrUpdate(WindowContainerTransaction wct) {
-            wct.addInsetsSource(mToken, mOwner, INDEX, captionBar(), mFrame, mBoundingRects,
-                    mFlags);
-            wct.addInsetsSource(mToken, mOwner, INDEX, mandatorySystemGestures(), mFrame,
-                    mBoundingRects, 0 /* flags */);
+        void update(WindowContainerTransaction wct) {
+            if (mShouldAddCaptionInset) {
+                wct.addInsetsSource(mToken, mOwner, INDEX, captionBar(), mFrame, mBoundingRects,
+                        mFlags);
+                wct.addInsetsSource(mToken, mOwner, INDEX, mandatorySystemGestures(), mFrame,
+                        mBoundingRects, 0 /* flags */);
+            }
         }
 
         void remove(WindowContainerTransaction wct) {
@@ -843,7 +854,8 @@
             return Objects.equals(mToken, that.mToken) && Objects.equals(mOwner,
                     that.mOwner) && Objects.equals(mFrame, that.mFrame)
                     && Objects.deepEquals(mBoundingRects, that.mBoundingRects)
-                    && mFlags == that.mFlags;
+                    && mFlags == that.mFlags
+                    && mShouldAddCaptionInset == that.mShouldAddCaptionInset;
         }
 
         @Override
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/AppHeaderViewHolder.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/AppHeaderViewHolder.kt
index 52bf400..cf03b3f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/AppHeaderViewHolder.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/AppHeaderViewHolder.kt
@@ -49,7 +49,7 @@
 import com.android.window.flags.Flags
 import com.android.window.flags.Flags.enableMinimizeButton
 import com.android.wm.shell.R
-import android.window.flags.DesktopModeFlags
+import android.window.DesktopModeFlags
 import com.android.wm.shell.windowdecor.MaximizeButtonView
 import com.android.wm.shell.windowdecor.common.DecorThemeUtil
 import com.android.wm.shell.windowdecor.common.OPACITY_100
@@ -81,6 +81,7 @@
         val taskInfo: RunningTaskInfo,
         val isRequestingImmersive: Boolean,
         val inFullImmersiveState: Boolean,
+        val hasGlobalFocus: Boolean
     ) : Data()
 
     private val decorThemeUtil = DecorThemeUtil(context)
@@ -159,24 +160,27 @@
     }
 
     override fun bindData(data: HeaderData) {
-        bindData(data.taskInfo, data.isRequestingImmersive, data.inFullImmersiveState)
+        bindData(data.taskInfo, data.isRequestingImmersive, data.inFullImmersiveState,
+            data.hasGlobalFocus)
     }
 
     private fun bindData(
         taskInfo: RunningTaskInfo,
         isRequestingImmersive: Boolean,
         inFullImmersiveState: Boolean,
+        hasGlobalFocus: Boolean
     ) {
         if (DesktopModeFlags.ENABLE_THEMED_APP_HEADERS.isTrue()) {
-            bindDataWithThemedHeaders(taskInfo, isRequestingImmersive, inFullImmersiveState)
+            bindDataWithThemedHeaders(taskInfo, isRequestingImmersive, inFullImmersiveState,
+                hasGlobalFocus)
         } else {
-            bindDataLegacy(taskInfo)
+            bindDataLegacy(taskInfo, hasGlobalFocus)
         }
     }
 
-    private fun bindDataLegacy(taskInfo: RunningTaskInfo) {
-        captionView.setBackgroundColor(getCaptionBackgroundColor(taskInfo))
-        val color = getAppNameAndButtonColor(taskInfo)
+    private fun bindDataLegacy(taskInfo: RunningTaskInfo, hasGlobalFocus: Boolean) {
+        captionView.setBackgroundColor(getCaptionBackgroundColor(taskInfo, hasGlobalFocus))
+        val color = getAppNameAndButtonColor(taskInfo, hasGlobalFocus)
         val alpha = Color.alpha(color)
         closeWindowButton.imageTintList = ColorStateList.valueOf(color)
         maximizeWindowButton.imageTintList = ColorStateList.valueOf(color)
@@ -210,9 +214,10 @@
     private fun bindDataWithThemedHeaders(
         taskInfo: RunningTaskInfo,
         requestingImmersive: Boolean,
-        inFullImmersiveState: Boolean
+        inFullImmersiveState: Boolean,
+        hasGlobalFocus: Boolean
     ) {
-        val header = fillHeaderInfo(taskInfo)
+        val header = fillHeaderInfo(taskInfo, hasGlobalFocus)
         val headerStyle = getHeaderStyle(header)
 
         // Caption Background
@@ -455,7 +460,7 @@
         }
     }
 
-    private fun fillHeaderInfo(taskInfo: RunningTaskInfo): Header {
+    private fun fillHeaderInfo(taskInfo: RunningTaskInfo, hasGlobalFocus: Boolean): Header {
         return Header(
             type = if (taskInfo.isTransparentCaptionBarAppearance) {
                 Header.Type.CUSTOM
@@ -463,7 +468,7 @@
                 Header.Type.DEFAULT
             },
             appTheme = decorThemeUtil.getAppTheme(taskInfo),
-            isFocused = taskInfo.isFocused,
+            isFocused = hasGlobalFocus,
             isAppearanceCaptionLight = taskInfo.isLightCaptionBarAppearance
         )
     }
@@ -544,19 +549,19 @@
     }
 
     @ColorInt
-    private fun getCaptionBackgroundColor(taskInfo: RunningTaskInfo): Int {
+    private fun getCaptionBackgroundColor(taskInfo: RunningTaskInfo, hasGlobalFocus: Boolean): Int {
         if (taskInfo.isTransparentCaptionBarAppearance) {
             return Color.TRANSPARENT
         }
         val materialColorAttr: Int =
             if (isDarkMode()) {
-                if (!taskInfo.isFocused) {
+                if (!hasGlobalFocus) {
                     materialColorSurfaceContainerHigh
                 } else {
                     materialColorSurfaceDim
                 }
             } else {
-                if (!taskInfo.isFocused) {
+                if (!hasGlobalFocus) {
                     materialColorSurfaceContainerLow
                 } else {
                     materialColorSecondaryContainer
@@ -569,7 +574,7 @@
     }
 
     @ColorInt
-    private fun getAppNameAndButtonColor(taskInfo: RunningTaskInfo): Int {
+    private fun getAppNameAndButtonColor(taskInfo: RunningTaskInfo, hasGlobalFocus: Boolean): Int {
         val materialColorAttr = when {
             taskInfo.isTransparentCaptionBarAppearance &&
                     taskInfo.isLightCaptionBarAppearance -> materialColorOnSecondaryContainer
@@ -579,8 +584,8 @@
             else -> materialColorOnSecondaryContainer
         }
         val appDetailsOpacity = when {
-            isDarkMode() && !taskInfo.isFocused -> DARK_THEME_UNFOCUSED_OPACITY
-            !isDarkMode() && !taskInfo.isFocused -> LIGHT_THEME_UNFOCUSED_OPACITY
+            isDarkMode() && !hasGlobalFocus -> DARK_THEME_UNFOCUSED_OPACITY
+            !isDarkMode() && !hasGlobalFocus -> LIGHT_THEME_UNFOCUSED_OPACITY
             else -> FOCUSED_OPACITY
         }
         context.withStyledAttributes(null, intArrayOf(materialColorAttr), 0, 0) {
diff --git a/libs/WindowManager/Shell/tests/e2e/splitscreen/flicker-legacy/Android.bp b/libs/WindowManager/Shell/tests/e2e/splitscreen/flicker-legacy/Android.bp
index a231e38..176020f 100644
--- a/libs/WindowManager/Shell/tests/e2e/splitscreen/flicker-legacy/Android.bp
+++ b/libs/WindowManager/Shell/tests/e2e/splitscreen/flicker-legacy/Android.bp
@@ -69,116 +69,6 @@
 }
 
 ////////////////////////////////////////////////////////////////////////////////
-// Begin cleanup after gcl merges
-
-filegroup {
-    name: "WMShellFlickerTestsSplitScreenGroup1-src",
-    srcs: [
-        "src/**/A*.kt",
-        "src/**/B*.kt",
-        "src/**/C*.kt",
-        "src/**/D*.kt",
-    ],
-}
-
-filegroup {
-    name: "WMShellFlickerTestsSplitScreenGroup2-src",
-    srcs: [
-        "src/**/E*.kt",
-    ],
-}
-
-filegroup {
-    name: "WMShellFlickerTestsSplitScreenGroup3-src",
-    srcs: [
-        "src/**/S*.kt",
-    ],
-}
-
-filegroup {
-    name: "WMShellFlickerTestsSplitScreenGroupOther-src",
-    srcs: [
-        "src/**/*.kt",
-    ],
-}
-
-android_test {
-    name: "WMShellFlickerTestsSplitScreenGroup1",
-    defaults: ["WMShellFlickerTestsDefault"],
-    manifest: "AndroidManifest.xml",
-    package_name: "com.android.wm.shell.flicker.splitscreen",
-    instrumentation_target_package: "com.android.wm.shell.flicker.splitscreen",
-    test_config_template: "AndroidTestTemplate.xml",
-    srcs: [
-        ":WMShellFlickerTestsSplitScreenGroup1-src",
-    ],
-    static_libs: [
-        "WMShellFlickerTestsBase",
-        "WMShellFlickerTestsSplitScreenBase",
-    ],
-    data: ["trace_config/*"],
-}
-
-android_test {
-    name: "WMShellFlickerTestsSplitScreenGroup2",
-    defaults: ["WMShellFlickerTestsDefault"],
-    manifest: "AndroidManifest.xml",
-    package_name: "com.android.wm.shell.flicker.splitscreen",
-    instrumentation_target_package: "com.android.wm.shell.flicker.splitscreen",
-    test_config_template: "AndroidTestTemplate.xml",
-    srcs: [
-        ":WMShellFlickerTestsSplitScreenGroup2-src",
-    ],
-    static_libs: [
-        "WMShellFlickerTestsBase",
-        "WMShellFlickerTestsSplitScreenBase",
-    ],
-    data: ["trace_config/*"],
-}
-
-android_test {
-    name: "WMShellFlickerTestsSplitScreenGroup3",
-    defaults: ["WMShellFlickerTestsDefault"],
-    manifest: "AndroidManifest.xml",
-    package_name: "com.android.wm.shell.flicker.splitscreen",
-    instrumentation_target_package: "com.android.wm.shell.flicker.splitscreen",
-    test_config_template: "AndroidTestTemplate.xml",
-    srcs: [
-        ":WMShellFlickerTestsSplitScreenGroup3-src",
-    ],
-    static_libs: [
-        "WMShellFlickerTestsBase",
-        "WMShellFlickerTestsSplitScreenBase",
-    ],
-    data: ["trace_config/*"],
-}
-
-android_test {
-    name: "WMShellFlickerTestsSplitScreenGroupOther",
-    defaults: ["WMShellFlickerTestsDefault"],
-    manifest: "AndroidManifest.xml",
-    package_name: "com.android.wm.shell.flicker.splitscreen",
-    instrumentation_target_package: "com.android.wm.shell.flicker.splitscreen",
-    test_config_template: "AndroidTestTemplate.xml",
-    srcs: [
-        ":WMShellFlickerTestsSplitScreenGroupOther-src",
-    ],
-    exclude_srcs: [
-        ":WMShellFlickerTestsSplitScreenGroup1-src",
-        ":WMShellFlickerTestsSplitScreenGroup2-src",
-        ":WMShellFlickerTestsSplitScreenGroup3-src",
-    ],
-    static_libs: [
-        "WMShellFlickerTestsBase",
-        "WMShellFlickerTestsSplitScreenBase",
-    ],
-    data: ["trace_config/*"],
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// End cleanup after gcl merges
-
-////////////////////////////////////////////////////////////////////////////////
 // Begin breakdowns for FlickerTestsRotation module
 
 test_module_config {
diff --git a/libs/WindowManager/Shell/tests/flicker/Android.bp b/libs/WindowManager/Shell/tests/flicker/Android.bp
index 58559ac..7b6cfe3 100644
--- a/libs/WindowManager/Shell/tests/flicker/Android.bp
+++ b/libs/WindowManager/Shell/tests/flicker/Android.bp
@@ -30,7 +30,6 @@
 
 java_library {
     name: "wm-shell-flicker-utils",
-    platform_apis: true,
     optimize: {
         enabled: false,
     },
diff --git a/libs/WindowManager/Shell/tests/flicker/appcompat/Android.bp b/libs/WindowManager/Shell/tests/flicker/appcompat/Android.bp
index 7412c1d..b016c9f 100644
--- a/libs/WindowManager/Shell/tests/flicker/appcompat/Android.bp
+++ b/libs/WindowManager/Shell/tests/flicker/appcompat/Android.bp
@@ -24,31 +24,6 @@
     default_applicable_licenses: ["frameworks_base_license"],
 }
 
-////////////////////////////////////////////////////////////////////////////////
-// Begin cleanup after gcl merge
-
-filegroup {
-    name: "WMShellFlickerTestsAppCompat-src",
-    srcs: [
-        "src/**/*.kt",
-    ],
-}
-
-android_test {
-    name: "WMShellFlickerTestsOther",
-    defaults: ["WMShellFlickerTestsDefault"],
-    manifest: "AndroidManifest.xml",
-    package_name: "com.android.wm.shell.flicker",
-    instrumentation_target_package: "com.android.wm.shell.flicker",
-    test_config_template: "AndroidTestTemplate.xml",
-    srcs: [":WMShellFlickerTestsAppCompat-src"],
-    static_libs: ["WMShellFlickerTestsBase"],
-    data: ["trace_config/*"],
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// End cleanup after gcl merge
-
 android_test {
     name: "WMShellFlickerTestsAppCompat",
     defaults: ["WMShellFlickerTestsDefault"],
diff --git a/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/OpenAppInSizeCompatModeTest.kt b/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/OpenAppInSizeCompatModeTest.kt
index 16c2d47..27303c1 100644
--- a/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/OpenAppInSizeCompatModeTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/OpenAppInSizeCompatModeTest.kt
@@ -31,7 +31,7 @@
 /**
  * Test launching app in size compat mode.
  *
- * To run this test: `atest WMShellFlickerTestsOther:OpenAppInSizeCompatModeTest`
+ * To run this test: `atest WMShellFlickerTestsAppCompat:OpenAppInSizeCompatModeTest`
  *
  * Actions:
  * ```
diff --git a/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/OpenTransparentActivityTest.kt b/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/OpenTransparentActivityTest.kt
index d85b771..e176f47 100644
--- a/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/OpenTransparentActivityTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/OpenTransparentActivityTest.kt
@@ -17,7 +17,6 @@
 package com.android.wm.shell.flicker.appcompat
 
 import android.platform.test.annotations.Postsubmit
-import android.tools.Rotation
 import android.tools.flicker.assertions.FlickerTest
 import android.tools.flicker.junit.FlickerParametersRunnerFactory
 import android.tools.flicker.legacy.FlickerBuilder
@@ -32,7 +31,7 @@
 /**
  * Test launching app in size compat mode.
  *
- * To run this test: `atest WMShellFlickerTestsOther:OpenTransparentActivityTest`
+ * To run this test: `atest WMShellFlickerTestsAppCompat:OpenTransparentActivityTest`
  *
  * Actions:
  * ```
@@ -109,9 +108,7 @@
         @Parameterized.Parameters(name = "{0}")
         @JvmStatic
         fun getParams(): Collection<FlickerTest> {
-            return LegacyFlickerTestFactory.nonRotationTests(
-                supportedRotations = listOf(Rotation.ROTATION_90)
-            )
+            return LegacyFlickerTestFactory.nonRotationTests()
         }
     }
 }
diff --git a/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/QuickSwitchLauncherToLetterboxAppTest.kt b/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/QuickSwitchLauncherToLetterboxAppTest.kt
index 164534c..9b8c949 100644
--- a/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/QuickSwitchLauncherToLetterboxAppTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/QuickSwitchLauncherToLetterboxAppTest.kt
@@ -20,7 +20,6 @@
 import android.platform.test.annotations.Postsubmit
 import android.platform.test.annotations.RequiresDevice
 import android.tools.NavBar
-import android.tools.Rotation
 import android.tools.flicker.assertions.FlickerTest
 import android.tools.flicker.junit.FlickerParametersRunnerFactory
 import android.tools.flicker.legacy.FlickerBuilder
@@ -36,7 +35,7 @@
 /**
  * Test quick switching to letterboxed app from launcher
  *
- * To run this test: `atest WMShellFlickerTestsOther:QuickSwitchLauncherToLetterboxAppTest`
+ * To run this test: `atest WMShellFlickerTestsAppCompat:QuickSwitchLauncherToLetterboxAppTest`
  *
  * Actions:
  * ```
@@ -266,8 +265,7 @@
         @JvmStatic
         fun getParams(): Collection<FlickerTest> {
             return LegacyFlickerTestFactory.nonRotationTests(
-                supportedNavigationModes = listOf(NavBar.MODE_GESTURAL),
-                supportedRotations = listOf(Rotation.ROTATION_90)
+                supportedNavigationModes = listOf(NavBar.MODE_GESTURAL)
             )
         }
     }
diff --git a/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/RepositionFixedPortraitAppTest.kt b/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/RepositionFixedPortraitAppTest.kt
index 034d54b..43ee186 100644
--- a/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/RepositionFixedPortraitAppTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/RepositionFixedPortraitAppTest.kt
@@ -17,7 +17,6 @@
 package com.android.wm.shell.flicker.appcompat
 
 import android.platform.test.annotations.Postsubmit
-import android.tools.Rotation
 import android.tools.flicker.assertions.FlickerTest
 import android.tools.flicker.junit.FlickerParametersRunnerFactory
 import android.tools.flicker.legacy.FlickerBuilder
@@ -32,7 +31,7 @@
 /**
  * Test launching a fixed portrait letterboxed app in landscape and repositioning to the right.
  *
- * To run this test: `atest WMShellFlickerTestsOther:RepositionFixedPortraitAppTest`
+ * To run this test: `atest WMShellFlickerTestsAppCompat:RepositionFixedPortraitAppTest`
  *
  * Actions:
  *
@@ -91,9 +90,7 @@
         @Parameterized.Parameters(name = "{0}")
         @JvmStatic
         fun getParams(): Collection<FlickerTest> {
-            return LegacyFlickerTestFactory.nonRotationTests(
-                supportedRotations = listOf(Rotation.ROTATION_90)
-            )
+            return LegacyFlickerTestFactory.nonRotationTests()
         }
     }
 }
diff --git a/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/RestartAppInSizeCompatModeTest.kt b/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/RestartAppInSizeCompatModeTest.kt
index 443fac1..5459ef03 100644
--- a/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/RestartAppInSizeCompatModeTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/RestartAppInSizeCompatModeTest.kt
@@ -31,7 +31,7 @@
 /**
  * Test restarting app in size compat mode.
  *
- * To run this test: `atest WMShellFlickerTestsOther:RestartAppInSizeCompatModeTest`
+ * To run this test: `atest WMShellFlickerTestsAppCompat:RestartAppInSizeCompatModeTest`
  *
  * Actions:
  * ```
diff --git a/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/RotateImmersiveAppInFullscreenTest.kt b/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/RotateImmersiveAppInFullscreenTest.kt
index 22543aa..5bb9640 100644
--- a/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/RotateImmersiveAppInFullscreenTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/RotateImmersiveAppInFullscreenTest.kt
@@ -45,7 +45,7 @@
 /**
  * Test rotating an immersive app in fullscreen.
  *
- * To run this test: `atest WMShellFlickerTestsOther:RotateImmersiveAppInFullscreenTest`
+ * To run this test: `atest WMShellFlickerTestsAppCompat:RotateImmersiveAppInFullscreenTest`
  *
  * Actions:
  * ```
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/Android.bp b/libs/WindowManager/Shell/tests/flicker/pip/Android.bp
index 3c95d3a..ddbc681 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/Android.bp
+++ b/libs/WindowManager/Shell/tests/flicker/pip/Android.bp
@@ -29,92 +29,12 @@
     srcs: ["src/**/apps/*.kt"],
 }
 
-////////////////////////////////////////////////////////////////////////////////
-// Begin cleanup after gcl merges
-
-filegroup {
-    name: "WMShellFlickerTestsPip1-src",
-    srcs: [
-        "src/**/A*.kt",
-        "src/**/B*.kt",
-        "src/**/C*.kt",
-        "src/**/D*.kt",
-        "src/**/F*.kt",
-        "src/**/S*.kt",
-    ],
-}
-
-filegroup {
-    name: "WMShellFlickerTestsPip2-src",
-    srcs: [
-        "src/**/E*.kt",
-    ],
-}
-
-filegroup {
-    name: "WMShellFlickerTestsPip3-src",
-    srcs: ["src/**/*.kt"],
-}
-
 filegroup {
     name: "WMShellFlickerTestsPipCommon-src",
     srcs: ["src/**/common/*.kt"],
 }
 
 android_test {
-    name: "WMShellFlickerTestsPip1",
-    defaults: ["WMShellFlickerTestsDefault"],
-    manifest: "AndroidManifest.xml",
-    package_name: "com.android.wm.shell.flicker.pip",
-    instrumentation_target_package: "com.android.wm.shell.flicker.pip",
-    test_config_template: "AndroidTestTemplate.xml",
-    srcs: [
-        ":WMShellFlickerTestsPip1-src",
-        ":WMShellFlickerTestsPipCommon-src",
-    ],
-    static_libs: ["WMShellFlickerTestsBase"],
-    data: ["trace_config/*"],
-}
-
-android_test {
-    name: "WMShellFlickerTestsPip2",
-    defaults: ["WMShellFlickerTestsDefault"],
-    manifest: "AndroidManifest.xml",
-    package_name: "com.android.wm.shell.flicker.pip",
-    instrumentation_target_package: "com.android.wm.shell.flicker.pip",
-    test_config_template: "AndroidTestTemplate.xml",
-    srcs: [
-        ":WMShellFlickerTestsPip2-src",
-        ":WMShellFlickerTestsPipCommon-src",
-    ],
-    static_libs: ["WMShellFlickerTestsBase"],
-    data: ["trace_config/*"],
-}
-
-android_test {
-    name: "WMShellFlickerTestsPip3",
-    defaults: ["WMShellFlickerTestsDefault"],
-    manifest: "AndroidManifest.xml",
-    package_name: "com.android.wm.shell.flicker.pip",
-    instrumentation_target_package: "com.android.wm.shell.flicker.pip",
-    test_config_template: "AndroidTestTemplate.xml",
-    srcs: [
-        ":WMShellFlickerTestsPip3-src",
-        ":WMShellFlickerTestsPipCommon-src",
-    ],
-    exclude_srcs: [
-        ":WMShellFlickerTestsPip1-src",
-        ":WMShellFlickerTestsPip2-src",
-        ":WMShellFlickerTestsPipApps-src",
-    ],
-    static_libs: ["WMShellFlickerTestsBase"],
-    data: ["trace_config/*"],
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// End cleanup after gcl merges
-
-android_test {
     name: "WMShellFlickerTestsPip",
     defaults: ["WMShellFlickerTestsDefault"],
     manifest: "AndroidManifest.xml",
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/AutoEnterPipOnGoToHomeTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/AutoEnterPipOnGoToHomeTest.kt
index a9ed13a..a248303 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/AutoEnterPipOnGoToHomeTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/AutoEnterPipOnGoToHomeTest.kt
@@ -38,7 +38,7 @@
 /**
  * Test entering pip from an app via auto-enter property when navigating to home.
  *
- * To run this test: `atest WMShellFlickerTestsPip1:AutoEnterPipOnGoToHomeTest`
+ * To run this test: `atest WMShellFlickerTestsPip:AutoEnterPipOnGoToHomeTest`
  *
  * Actions:
  * ```
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/AutoEnterPipWithSourceRectHintTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/AutoEnterPipWithSourceRectHintTest.kt
index d059211..df952c9 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/AutoEnterPipWithSourceRectHintTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/AutoEnterPipWithSourceRectHintTest.kt
@@ -30,7 +30,7 @@
 /**
  * Test auto entering pip using a source rect hint.
  *
- * To run this test: `atest WMShellFlickerTestsPip1:AutoEnterPipWithSourceRectHintTest`
+ * To run this test: `atest WMShellFlickerTestsPip:AutoEnterPipWithSourceRectHintTest`
  *
  * Actions:
  * ```
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ClosePipBySwipingDownTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ClosePipBySwipingDownTest.kt
index 3ffc9d7..302b8c4 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ClosePipBySwipingDownTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ClosePipBySwipingDownTest.kt
@@ -32,7 +32,7 @@
 /**
  * Test closing a pip window by swiping it to the bottom-center of the screen
  *
- * To run this test: `atest WMShellFlickerTestsPip1:ClosePipBySwipingDownTest`
+ * To run this test: `atest WMShellFlickerTestsPip:ClosePipBySwipingDownTest`
  *
  * Actions:
  * ```
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ClosePipWithDismissButtonTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ClosePipWithDismissButtonTest.kt
index d177624..77a1edb 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ClosePipWithDismissButtonTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ClosePipWithDismissButtonTest.kt
@@ -30,7 +30,7 @@
 /**
  * Test closing a pip window via the dismiss button
  *
- * To run this test: `atest WMShellFlickerTestsPip1:ClosePipWithDismissButtonTest`
+ * To run this test: `atest WMShellFlickerTestsPip:ClosePipWithDismissButtonTest`
  *
  * Actions:
  * ```
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipOnUserLeaveHintTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipOnUserLeaveHintTest.kt
index a86803d..6e32d64 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipOnUserLeaveHintTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipOnUserLeaveHintTest.kt
@@ -31,7 +31,7 @@
 /**
  * Test entering pip from an app via [onUserLeaveHint] and by navigating to home.
  *
- * To run this test: `atest WMShellFlickerTestsPip2:EnterPipOnUserLeaveHintTest`
+ * To run this test: `atest WMShellFlickerTestsPip:EnterPipOnUserLeaveHintTest`
  *
  * Actions:
  * ```
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientation.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientation.kt
index d0e8215..9a6cb61 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientation.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientation.kt
@@ -46,7 +46,7 @@
 /**
  * Test entering pip while changing orientation (from app in landscape to pip window in portrait)
  *
- * To run this test: `atest WMShellFlickerTestsPip2:EnterPipToOtherOrientation`
+ * To run this test: `atest WMShellFlickerTestsPip:EnterPipToOtherOrientation`
  *
  * Actions:
  * ```
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipViaAppUiButtonTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipViaAppUiButtonTest.kt
index d92f55a..6b4751c 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipViaAppUiButtonTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipViaAppUiButtonTest.kt
@@ -28,7 +28,7 @@
 /**
  * Test entering pip from an app by interacting with the app UI
  *
- * To run this test: `atest WMShellFlickerTestsPip2:EnterPipViaAppUiButtonTest`
+ * To run this test: `atest WMShellFlickerTestsPip:EnterPipViaAppUiButtonTest`
  *
  * Actions:
  * ```
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaExpandButtonTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaExpandButtonTest.kt
index 8c0817d..8d0bc0f 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaExpandButtonTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaExpandButtonTest.kt
@@ -28,7 +28,7 @@
 /**
  * Test expanding a pip window back to full screen via the expand button
  *
- * To run this test: `atest WMShellFlickerTestsPip2:ExitPipToAppViaExpandButtonTest`
+ * To run this test: `atest WMShellFlickerTestsPip:ExitPipToAppViaExpandButtonTest`
  *
  * Actions:
  * ```
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaIntentTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaIntentTest.kt
index 90a9623..939f328 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaIntentTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaIntentTest.kt
@@ -28,7 +28,7 @@
 /**
  * Test expanding a pip window back to full screen via an intent
  *
- * To run this test: `atest WMShellFlickerTestsPip2:ExitPipToAppViaIntentTest`
+ * To run this test: `atest WMShellFlickerTestsPip:ExitPipToAppViaIntentTest`
  *
  * Actions:
  * ```
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTest.kt
index 9306c77..258663b 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTest.kt
@@ -33,7 +33,7 @@
 /**
  * Test expanding a pip window by double-clicking it
  *
- * To run this test: `atest WMShellFlickerTestsPip2:ExpandPipOnDoubleClickTest`
+ * To run this test: `atest WMShellFlickerTestsPip:ExpandPipOnDoubleClickTest`
  *
  * Actions:
  * ```
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/FromSplitScreenAutoEnterPipOnGoToHomeTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/FromSplitScreenAutoEnterPipOnGoToHomeTest.kt
index cb8ee27..5f8ac2a 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/FromSplitScreenAutoEnterPipOnGoToHomeTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/FromSplitScreenAutoEnterPipOnGoToHomeTest.kt
@@ -39,7 +39,7 @@
 /**
  * Test entering pip from an app via auto-enter property when navigating to home from split screen.
  *
- * To run this test: `atest WMShellFlickerTestsPip1:FromSplitScreenAutoEnterPipOnGoToHomeTest`
+ * To run this test: `atest WMShellFlickerTestsPip:FromSplitScreenAutoEnterPipOnGoToHomeTest`
  *
  * Actions:
  * ```
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/FromSplitScreenEnterPipOnUserLeaveHintTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/FromSplitScreenEnterPipOnUserLeaveHintTest.kt
index d1bf6ac..48c85a8 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/FromSplitScreenEnterPipOnUserLeaveHintTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/FromSplitScreenEnterPipOnUserLeaveHintTest.kt
@@ -40,7 +40,7 @@
 /**
  * Test entering pip from an app via auto-enter property when navigating to home from split screen.
  *
- * To run this test: `atest WMShellFlickerTestsPip1:FromSplitScreenEnterPipOnUserLeaveHintTest`
+ * To run this test: `atest WMShellFlickerTestsPip:FromSplitScreenEnterPipOnUserLeaveHintTest`
  *
  * Actions:
  * ```
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/MovePipDownOnShelfHeightChange.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/MovePipDownOnShelfHeightChange.kt
index 265eb44..ee62cf5 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/MovePipDownOnShelfHeightChange.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/MovePipDownOnShelfHeightChange.kt
@@ -32,7 +32,7 @@
 /**
  * Test Pip movement with Launcher shelf height change (increase).
  *
- * To run this test: `atest WMShellFlickerTestsPip3:MovePipDownOnShelfHeightChange`
+ * To run this test: `atest WMShellFlickerTestsPip:MovePipDownOnShelfHeightChange`
  *
  * Actions:
  * ```
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/MovePipUpOnShelfHeightChangeTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/MovePipUpOnShelfHeightChangeTest.kt
index 8d6be64..4d643f7 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/MovePipUpOnShelfHeightChangeTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/MovePipUpOnShelfHeightChangeTest.kt
@@ -32,7 +32,7 @@
 /**
  * Test Pip movement with Launcher shelf height change (decrease).
  *
- * To run this test: `atest WMShellFlickerTestsPip3:MovePipUpOnShelfHeightChangeTest`
+ * To run this test: `atest WMShellFlickerTestsPip:MovePipUpOnShelfHeightChangeTest`
  *
  * Actions:
  * ```
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ShowPipAndRotateDisplay.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ShowPipAndRotateDisplay.kt
index 9109eaf..c6cf341 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ShowPipAndRotateDisplay.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ShowPipAndRotateDisplay.kt
@@ -35,7 +35,7 @@
 /**
  * Test Pip Stack in bounds after rotations.
  *
- * To run this test: `atest WMShellFlickerTestsPip1:ShowPipAndRotateDisplay`
+ * To run this test: `atest WMShellFlickerTestsPip:ShowPipAndRotateDisplay`
  *
  * Actions:
  * ```
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/MapsEnterPipTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/MapsEnterPipTest.kt
index 1fc9d99..7b04b76 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/MapsEnterPipTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/MapsEnterPipTest.kt
@@ -40,7 +40,7 @@
 /**
  * Test entering pip from Maps app by interacting with the app UI
  *
- * To run this test: `atest WMShellFlickerTests:MapsEnterPipTest`
+ * To run this test: `atest WMShellFlickerTestsPipAppsCSuite:MapsEnterPipTest`
  *
  * Actions:
  * ```
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/NetflixEnterPipTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/NetflixEnterPipTest.kt
index 68fa7c7..6911946 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/NetflixEnterPipTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/NetflixEnterPipTest.kt
@@ -38,7 +38,7 @@
 /**
  * Test entering pip from Netflix app by interacting with the app UI
  *
- * To run this test: `atest WMShellFlickerTests:NetflixEnterPipTest`
+ * To run this test: `atest WMShellFlickerTestsPipAppsCSuite:NetflixEnterPipTest`
  *
  * Actions:
  * ```
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/YouTubeEnterPipTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/YouTubeEnterPipTest.kt
index 7873a85..5e54f30 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/YouTubeEnterPipTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/YouTubeEnterPipTest.kt
@@ -34,7 +34,7 @@
 /**
  * Test entering pip from YouTube app by interacting with the app UI
  *
- * To run this test: `atest WMShellFlickerTests:YouTubeEnterPipTest`
+ * To run this test: `atest WMShellFlickerTestsPipAppsCSuite:YouTubeEnterPipTest`
  *
  * Actions:
  * ```
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/YouTubeEnterPipToOtherOrientationTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/YouTubeEnterPipToOtherOrientationTest.kt
index 72be3d8..159cba4 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/YouTubeEnterPipToOtherOrientationTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/YouTubeEnterPipToOtherOrientationTest.kt
@@ -38,7 +38,7 @@
 /**
  * Test entering pip from YouTube app by interacting with the app UI
  *
- * To run this test: `atest WMShellFlickerTests:YouTubeEnterPipTest`
+ * To run this test: `atest WMShellFlickerTestsPipAppsCSuite:YouTubeEnterPipTest`
  *
  * Actions:
  * ```
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/tv/TvPipBasicTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/tv/TvPipBasicTest.kt
index 8a073ab..6a84b28 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/tv/TvPipBasicTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/tv/TvPipBasicTest.kt
@@ -25,7 +25,7 @@
 import org.junit.runner.RunWith
 import org.junit.runners.Parameterized
 
-/** Test Pip Menu on TV. To run this test: `atest WMShellFlickerTests:TvPipBasicTest` */
+/** Test Pip Menu on TV. To run this test: `atest WMShellFlickerTestsPip:TvPipBasicTest` */
 @RequiresDevice
 @RunWith(Parameterized::class)
 class TvPipBasicTest(private val radioButtonId: String, private val pipWindowRatio: Rational?) :
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/tv/TvPipMenuTests.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/tv/TvPipMenuTests.kt
index d4cd6da..09e8745 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/tv/TvPipMenuTests.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/tv/TvPipMenuTests.kt
@@ -27,7 +27,7 @@
 import org.junit.Before
 import org.junit.Test
 
-/** Test Pip Menu on TV. To run this test: `atest WMShellFlickerTests:TvPipMenuTests` */
+/** Test Pip Menu on TV. To run this test: `atest WMShellFlickerTestsPip:TvPipMenuTests` */
 @RequiresDevice
 class TvPipMenuTests : TvPipTestBase() {
 
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java
index 227060d..dee0b23 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java
@@ -860,15 +860,9 @@
     }
 
     private void doMotionEvent(int actionDown, int coordinate) {
-        doMotionEvent(actionDown, coordinate, 0);
-    }
-
-    private void doMotionEvent(int actionDown, int coordinate, float velocity) {
         mController.onMotionEvent(
                 /* touchX */ coordinate,
                 /* touchY */ coordinate,
-                /* velocityX = */ velocity,
-                /* velocityY = */ velocity,
                 /* keyAction */ actionDown,
                 /* swipeEdge */ BackEvent.EDGE_LEFT);
     }
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackProgressAnimatorTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackProgressAnimatorTest.java
index 9b019dd..1da4ef6 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackProgressAnimatorTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackProgressAnimatorTest.java
@@ -54,8 +54,6 @@
                 /* touchX = */ touchX,
                 /* touchY = */ 0,
                 /* progress = */ progress,
-                /* velocityX = */ 0,
-                /* velocityY = */ 0,
                 /* triggerBack = */ false,
                 /* swipeEdge = */ BackEvent.EDGE_LEFT,
                 /* departingAnimationTarget = */ null);
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/CustomCrossActivityBackAnimationTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/CustomCrossActivityBackAnimationTest.kt
index 5b5ef6f..2235c20 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/CustomCrossActivityBackAnimationTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/CustomCrossActivityBackAnimationTest.kt
@@ -222,8 +222,6 @@
             /* touchX = */ touchX,
             /* touchY = */ 0f,
             /* progress = */ progress,
-            /* velocityX = */ 0f,
-            /* velocityY = */ 0f,
             /* triggerBack = */ false,
             /* swipeEdge = */ BackEvent.EDGE_LEFT,
             /* departingAnimationTarget = */ null
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopFullImmersiveTransitionHandlerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopFullImmersiveTransitionHandlerTest.kt
index cae6095..2e9effb4 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopFullImmersiveTransitionHandlerTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopFullImmersiveTransitionHandlerTest.kt
@@ -15,23 +15,39 @@
  */
 package com.android.wm.shell.desktopmode
 
+import android.app.WindowConfiguration.WINDOW_CONFIG_BOUNDS
+import android.os.Binder
 import android.os.IBinder
+import android.platform.test.annotations.EnableFlags
+import android.platform.test.flag.junit.SetFlagsRule
 import android.testing.AndroidTestingRunner
+import android.view.Display.DEFAULT_DISPLAY
 import android.view.SurfaceControl
 import android.view.WindowManager.TRANSIT_CHANGE
+import android.view.WindowManager.TransitionFlags
+import android.view.WindowManager.TransitionType
+import android.window.TransitionInfo
+import android.window.WindowContainerToken
 import android.window.WindowContainerTransaction
 import androidx.test.filters.SmallTest
+import com.android.window.flags.Flags
+import com.android.wm.shell.ShellTaskOrganizer
 import com.android.wm.shell.ShellTestCase
 import com.android.wm.shell.TestShellExecutor
+import com.android.wm.shell.common.DisplayController
+import com.android.wm.shell.common.DisplayLayout
 import com.android.wm.shell.desktopmode.DesktopTestHelpers.Companion.createFreeformTask
 import com.android.wm.shell.sysui.ShellInit
 import com.android.wm.shell.transition.Transitions
 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.mock
+import org.mockito.kotlin.any
+import org.mockito.kotlin.eq
 import org.mockito.kotlin.mock
 import org.mockito.kotlin.times
 import org.mockito.kotlin.verify
@@ -40,14 +56,18 @@
 /**
  * Tests for [DesktopFullImmersiveTransitionHandler].
  *
- * Usage: atest WMShellUnitTests:DesktopFullImmersiveTransitionHandler
+ * Usage: atest WMShellUnitTests:DesktopFullImmersiveTransitionHandlerTest
  */
 @SmallTest
 @RunWith(AndroidTestingRunner::class)
 class DesktopFullImmersiveTransitionHandlerTest : ShellTestCase() {
 
+    @JvmField @Rule val setFlagsRule = SetFlagsRule()
+
     @Mock private lateinit var mockTransitions: Transitions
     private lateinit var desktopRepository: DesktopRepository
+    @Mock private lateinit var mockDisplayController: DisplayController
+    @Mock private lateinit var mockShellTaskOrganizer: ShellTaskOrganizer
     private val transactionSupplier = { SurfaceControl.Transaction() }
 
     private lateinit var immersiveHandler: DesktopFullImmersiveTransitionHandler
@@ -57,19 +77,22 @@
         desktopRepository = DesktopRepository(
             context, ShellInit(TestShellExecutor()), mock(), mock()
         )
+        whenever(mockDisplayController.getDisplayLayout(DEFAULT_DISPLAY))
+            .thenReturn(DisplayLayout())
         immersiveHandler = DesktopFullImmersiveTransitionHandler(
             transitions = mockTransitions,
             desktopRepository = desktopRepository,
-            transactionSupplier = transactionSupplier
+            displayController = mockDisplayController,
+            shellTaskOrganizer = mockShellTaskOrganizer,
+            transactionSupplier = transactionSupplier,
         )
     }
 
     @Test
     fun enterImmersive_transitionReady_updatesRepository() {
         val task = createFreeformTask()
-        val wct = WindowContainerTransaction()
         val mockBinder = mock(IBinder::class.java)
-        whenever(mockTransitions.startTransition(TRANSIT_CHANGE, wct, immersiveHandler))
+        whenever(mockTransitions.startTransition(eq(TRANSIT_CHANGE), any(), eq(immersiveHandler)))
             .thenReturn(mockBinder)
         desktopRepository.setTaskInFullImmersiveState(
             displayId = task.displayId,
@@ -77,8 +100,8 @@
             immersive = false
         )
 
-        immersiveHandler.enterImmersive(task, wct)
-        immersiveHandler.onTransitionReady(mockBinder)
+        immersiveHandler.moveTaskToImmersive(task)
+        immersiveHandler.onTransitionReady(mockBinder, createTransitionInfo())
 
         assertThat(desktopRepository.isTaskInFullImmersiveState(task.taskId)).isTrue()
     }
@@ -86,9 +109,8 @@
     @Test
     fun exitImmersive_transitionReady_updatesRepository() {
         val task = createFreeformTask()
-        val wct = WindowContainerTransaction()
         val mockBinder = mock(IBinder::class.java)
-        whenever(mockTransitions.startTransition(TRANSIT_CHANGE, wct, immersiveHandler))
+        whenever(mockTransitions.startTransition(eq(TRANSIT_CHANGE), any(), eq(immersiveHandler)))
             .thenReturn(mockBinder)
         desktopRepository.setTaskInFullImmersiveState(
             displayId = task.displayId,
@@ -96,8 +118,8 @@
             immersive = true
         )
 
-        immersiveHandler.exitImmersive(task, wct)
-        immersiveHandler.onTransitionReady(mockBinder)
+        immersiveHandler.moveTaskToNonImmersive(task)
+        immersiveHandler.onTransitionReady(mockBinder, createTransitionInfo())
 
         assertThat(desktopRepository.isTaskInFullImmersiveState(task.taskId)).isFalse()
     }
@@ -105,28 +127,251 @@
     @Test
     fun enterImmersive_inProgress_ignores() {
         val task = createFreeformTask()
-        val wct = WindowContainerTransaction()
         val mockBinder = mock(IBinder::class.java)
-        whenever(mockTransitions.startTransition(TRANSIT_CHANGE, wct, immersiveHandler))
+        whenever(mockTransitions.startTransition(eq(TRANSIT_CHANGE), any(), eq(immersiveHandler)))
             .thenReturn(mockBinder)
 
-        immersiveHandler.enterImmersive(task, wct)
-        immersiveHandler.enterImmersive(task, wct)
+        immersiveHandler.moveTaskToImmersive(task)
+        immersiveHandler.moveTaskToImmersive(task)
 
-        verify(mockTransitions, times(1)).startTransition(TRANSIT_CHANGE, wct, immersiveHandler)
+        verify(mockTransitions, times(1))
+            .startTransition(eq(TRANSIT_CHANGE), any(), eq(immersiveHandler))
     }
 
     @Test
     fun exitImmersive_inProgress_ignores() {
         val task = createFreeformTask()
-        val wct = WindowContainerTransaction()
         val mockBinder = mock(IBinder::class.java)
-        whenever(mockTransitions.startTransition(TRANSIT_CHANGE, wct, immersiveHandler))
+        whenever(mockTransitions.startTransition(eq(TRANSIT_CHANGE), any(), eq(immersiveHandler)))
             .thenReturn(mockBinder)
 
-        immersiveHandler.exitImmersive(task, wct)
-        immersiveHandler.exitImmersive(task, wct)
+        immersiveHandler.moveTaskToNonImmersive(task)
+        immersiveHandler.moveTaskToNonImmersive(task)
 
-        verify(mockTransitions, times(1)).startTransition(TRANSIT_CHANGE, wct, immersiveHandler)
+        verify(mockTransitions, times(1))
+            .startTransition(eq(TRANSIT_CHANGE), any(), eq(immersiveHandler))
     }
+
+    @Test
+    @EnableFlags(Flags.FLAG_ENABLE_FULLY_IMMERSIVE_IN_DESKTOP)
+    fun exitImmersiveIfApplicable_inImmersive_addsPendingExit() {
+        val task = createFreeformTask()
+        whenever(mockShellTaskOrganizer.getRunningTaskInfo(task.taskId)).thenReturn(task)
+        val wct = WindowContainerTransaction()
+        val transition = Binder()
+        desktopRepository.setTaskInFullImmersiveState(
+            displayId = DEFAULT_DISPLAY,
+            taskId = task.taskId,
+            immersive = true
+        )
+
+        immersiveHandler.exitImmersiveIfApplicable(transition, wct, DEFAULT_DISPLAY)
+
+        assertThat(immersiveHandler.pendingExternalExitTransitions.any { exit ->
+            exit.transition == transition && exit.displayId == DEFAULT_DISPLAY
+                    && exit.taskId == task.taskId
+        }).isTrue()
+    }
+
+    @Test
+    @EnableFlags(Flags.FLAG_ENABLE_FULLY_IMMERSIVE_IN_DESKTOP)
+    fun exitImmersiveIfApplicable_notInImmersive_doesNotAddPendingExit() {
+        val task = createFreeformTask()
+        whenever(mockShellTaskOrganizer.getRunningTaskInfo(task.taskId)).thenReturn(task)
+        val wct = WindowContainerTransaction()
+        val transition = Binder()
+        desktopRepository.setTaskInFullImmersiveState(
+            displayId = DEFAULT_DISPLAY,
+            taskId = task.taskId,
+            immersive = false
+        )
+
+        immersiveHandler.exitImmersiveIfApplicable(transition, wct, DEFAULT_DISPLAY)
+
+        assertThat(immersiveHandler.pendingExternalExitTransitions.any { exit ->
+            exit.transition == transition && exit.displayId == DEFAULT_DISPLAY
+                    && exit.taskId == task.taskId
+        }).isFalse()
+    }
+
+    @Test
+    @EnableFlags(Flags.FLAG_ENABLE_FULLY_IMMERSIVE_IN_DESKTOP)
+    fun exitImmersiveIfApplicable_byDisplay_inImmersive_changesTaskBounds() {
+        val task = createFreeformTask()
+        whenever(mockShellTaskOrganizer.getRunningTaskInfo(task.taskId)).thenReturn(task)
+        val wct = WindowContainerTransaction()
+        val transition = Binder()
+        desktopRepository.setTaskInFullImmersiveState(
+            displayId = DEFAULT_DISPLAY,
+            taskId = task.taskId,
+            immersive = true
+        )
+
+        immersiveHandler.exitImmersiveIfApplicable(transition, wct, DEFAULT_DISPLAY)
+
+        assertThat(wct.hasBoundsChange(task.token)).isTrue()
+    }
+
+    @Test
+    @EnableFlags(Flags.FLAG_ENABLE_FULLY_IMMERSIVE_IN_DESKTOP)
+    fun exitImmersiveIfApplicable_byDisplay_notInImmersive_doesNotChangeTaskBounds() {
+        val task = createFreeformTask()
+        whenever(mockShellTaskOrganizer.getRunningTaskInfo(task.taskId)).thenReturn(task)
+        val wct = WindowContainerTransaction()
+        val transition = Binder()
+        desktopRepository.setTaskInFullImmersiveState(
+            displayId = DEFAULT_DISPLAY,
+            taskId = task.taskId,
+            immersive = false
+        )
+
+        immersiveHandler.exitImmersiveIfApplicable(transition, wct, DEFAULT_DISPLAY)
+
+        assertThat(wct.hasBoundsChange(task.token)).isFalse()
+    }
+
+    @Test
+    @EnableFlags(Flags.FLAG_ENABLE_FULLY_IMMERSIVE_IN_DESKTOP)
+    fun exitImmersiveIfApplicable_byTask_inImmersive_changesTaskBounds() {
+        val task = createFreeformTask()
+        whenever(mockShellTaskOrganizer.getRunningTaskInfo(task.taskId)).thenReturn(task)
+        val wct = WindowContainerTransaction()
+        desktopRepository.setTaskInFullImmersiveState(
+            displayId = DEFAULT_DISPLAY,
+            taskId = task.taskId,
+            immersive = true
+        )
+
+        immersiveHandler.exitImmersiveIfApplicable(wct = wct, taskInfo = task)
+
+        assertThat(wct.hasBoundsChange(task.token)).isTrue()
+    }
+
+    @Test
+    @EnableFlags(Flags.FLAG_ENABLE_FULLY_IMMERSIVE_IN_DESKTOP)
+    fun exitImmersiveIfApplicable_byTask_notInImmersive_doesNotChangeTaskBounds() {
+        val task = createFreeformTask()
+        whenever(mockShellTaskOrganizer.getRunningTaskInfo(task.taskId)).thenReturn(task)
+        val wct = WindowContainerTransaction()
+        desktopRepository.setTaskInFullImmersiveState(
+            displayId = DEFAULT_DISPLAY,
+            taskId = task.taskId,
+            immersive = false
+        )
+
+        immersiveHandler.exitImmersiveIfApplicable(wct, task.taskId)
+
+        assertThat(wct.hasBoundsChange(task.token)).isFalse()
+    }
+
+    @Test
+    @EnableFlags(Flags.FLAG_ENABLE_FULLY_IMMERSIVE_IN_DESKTOP)
+    fun exitImmersiveIfApplicable_byTask_inImmersive_addsPendingExitOnRun() {
+        val task = createFreeformTask()
+        whenever(mockShellTaskOrganizer.getRunningTaskInfo(task.taskId)).thenReturn(task)
+        val wct = WindowContainerTransaction()
+        val transition = Binder()
+        desktopRepository.setTaskInFullImmersiveState(
+            displayId = DEFAULT_DISPLAY,
+            taskId = task.taskId,
+            immersive = true
+        )
+
+        immersiveHandler.exitImmersiveIfApplicable(wct, task.taskId)?.invoke(transition)
+
+        assertThat(immersiveHandler.pendingExternalExitTransitions.any { exit ->
+            exit.transition == transition && exit.displayId == DEFAULT_DISPLAY
+                    && exit.taskId == task.taskId
+        }).isFalse()
+    }
+
+    @Test
+    @EnableFlags(Flags.FLAG_ENABLE_FULLY_IMMERSIVE_IN_DESKTOP)
+    fun exitImmersiveIfApplicable_byTask_notInImmersive_doesNotAddPendingExitOnRun() {
+        val task = createFreeformTask()
+        whenever(mockShellTaskOrganizer.getRunningTaskInfo(task.taskId)).thenReturn(task)
+        val wct = WindowContainerTransaction()
+        val transition = Binder()
+        desktopRepository.setTaskInFullImmersiveState(
+            displayId = DEFAULT_DISPLAY,
+            taskId = task.taskId,
+            immersive = false
+        )
+
+        immersiveHandler.exitImmersiveIfApplicable(wct, task.taskId)?.invoke(transition)
+
+        assertThat(immersiveHandler.pendingExternalExitTransitions.any { exit ->
+            exit.transition == transition && exit.displayId == DEFAULT_DISPLAY
+                    && exit.taskId == task.taskId
+        }).isFalse()
+    }
+
+    @Test
+    @EnableFlags(Flags.FLAG_ENABLE_FULLY_IMMERSIVE_IN_DESKTOP)
+    fun onTransitionReady_pendingExit_removesPendingExit() {
+        val task = createFreeformTask()
+        whenever(mockShellTaskOrganizer.getRunningTaskInfo(task.taskId)).thenReturn(task)
+        val wct = WindowContainerTransaction()
+        val transition = Binder()
+        desktopRepository.setTaskInFullImmersiveState(
+            displayId = DEFAULT_DISPLAY,
+            taskId = task.taskId,
+            immersive = true
+        )
+        immersiveHandler.exitImmersiveIfApplicable(transition, wct, DEFAULT_DISPLAY)
+
+        immersiveHandler.onTransitionReady(
+            transition = transition,
+            info = createTransitionInfo(
+                changes = listOf(
+                    TransitionInfo.Change(task.token, SurfaceControl()).apply { taskInfo = task }
+                )
+            )
+        )
+
+        assertThat(immersiveHandler.pendingExternalExitTransitions.any { exit ->
+            exit.transition == transition && exit.displayId == DEFAULT_DISPLAY
+                    && exit.taskId == task.taskId
+        }).isFalse()
+    }
+
+    @Test
+    @EnableFlags(Flags.FLAG_ENABLE_FULLY_IMMERSIVE_IN_DESKTOP)
+    fun onTransitionReady_pendingExit_updatesRepository() {
+        val task = createFreeformTask()
+        whenever(mockShellTaskOrganizer.getRunningTaskInfo(task.taskId)).thenReturn(task)
+        val wct = WindowContainerTransaction()
+        val transition = Binder()
+        desktopRepository.setTaskInFullImmersiveState(
+            displayId = DEFAULT_DISPLAY,
+            taskId = task.taskId,
+            immersive = true
+        )
+        immersiveHandler.exitImmersiveIfApplicable(transition, wct, DEFAULT_DISPLAY)
+
+        immersiveHandler.onTransitionReady(
+            transition = transition,
+            info = createTransitionInfo(
+                changes = listOf(
+                    TransitionInfo.Change(task.token, SurfaceControl()).apply { taskInfo = task }
+                )
+            )
+        )
+
+        assertThat(desktopRepository.isTaskInFullImmersiveState(task.taskId)).isFalse()
+    }
+
+    private fun createTransitionInfo(
+        @TransitionType type: Int = TRANSIT_CHANGE,
+        @TransitionFlags flags: Int = 0,
+        changes: List<TransitionInfo.Change> = emptyList()
+    ): TransitionInfo = TransitionInfo(type, flags).apply {
+        changes.forEach { change -> addChange(change) }
+    }
+
+    private fun WindowContainerTransaction.hasBoundsChange(token: WindowContainerToken): Boolean =
+        this.changes.any { change ->
+            change.key == token.asBinder()
+                    && (change.value.windowSetMask and WINDOW_CONFIG_BOUNDS) != 0
+        }
 }
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeEventLoggerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeEventLoggerTest.kt
index d7a132d..dde9fda 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeEventLoggerTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeEventLoggerTest.kt
@@ -16,7 +16,6 @@
 
 package com.android.wm.shell.desktopmode
 
-import android.platform.test.annotations.DisableFlags
 import android.platform.test.annotations.EnableFlags
 import android.platform.test.flag.junit.SetFlagsRule
 import com.android.dx.mockito.inline.extended.ExtendedMockito.verify
@@ -397,6 +396,37 @@
         }
     }
 
+    @Test
+    fun logTaskInfoStateInit_logsTaskInfoChangedStateInit() {
+        desktopModeEventLogger.logTaskInfoStateInit()
+        verify {
+            FrameworkStatsLog.write(eq(FrameworkStatsLog.DESKTOP_MODE_SESSION_TASK_UPDATE),
+                /* task_event */
+                eq(FrameworkStatsLog.DESKTOP_MODE_SESSION_TASK_UPDATE__TASK_EVENT__TASK_INIT_STATSD),
+                /* instance_id */
+                eq(0),
+                /* uid */
+                eq(0),
+                /* task_height */
+                eq(0),
+                /* task_width */
+                eq(0),
+                /* task_x */
+                eq(0),
+                /* task_y */
+                eq(0),
+                /* session_id */
+                eq(0),
+                /* minimize_reason */
+                eq(UNSET_MINIMIZE_REASON),
+                /* unminimize_reason */
+                eq(UNSET_UNMINIMIZE_REASON),
+                /* visible_task_count */
+                eq(0)
+            )
+        }
+    }
+
     private companion object {
         private const val SESSION_ID = 1
         private const val TASK_ID = 1
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeLoggerTransitionObserverTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeLoggerTransitionObserverTest.kt
index d399b20..e7593b5 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeLoggerTransitionObserverTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeLoggerTransitionObserverTest.kt
@@ -110,15 +110,23 @@
     shellInit = spy(ShellInit(testExecutor))
     desktopModeEventLogger = mock<DesktopModeEventLogger>()
 
-    transitionObserver =
-        DesktopModeLoggerTransitionObserver(
-            context, mockShellInit, transitions, desktopModeEventLogger)
-    if (Transitions.ENABLE_SHELL_TRANSITIONS) {
-      val initRunnableCaptor = ArgumentCaptor.forClass(Runnable::class.java)
-      verify(mockShellInit).addInitCallback(initRunnableCaptor.capture(), same(transitionObserver))
-      initRunnableCaptor.value.run()
-    } else {
-      transitionObserver.onInit()
+    transitionObserver = DesktopModeLoggerTransitionObserver(
+        context, mockShellInit, transitions, desktopModeEventLogger)
+    val initRunnableCaptor = ArgumentCaptor.forClass(Runnable::class.java)
+    verify(mockShellInit).addInitCallback(initRunnableCaptor.capture(), same(transitionObserver))
+    initRunnableCaptor.value.run()
+    // verify this initialisation interaction to leave the desktopmodeEventLogger mock in a
+    // consistent state with no outstanding interactions when test cases start executing.
+    verify(desktopModeEventLogger).logTaskInfoStateInit()
+  }
+
+  @Test
+  fun testInitialiseVisibleTasksSystemProperty() {
+    ExtendedMockito.verify {
+      SystemProperties.set(
+          eq(DesktopModeLoggerTransitionObserver.VISIBLE_TASKS_COUNTER_SYSTEM_PROPERTY),
+          eq(DesktopModeLoggerTransitionObserver
+              .VISIBLE_TASKS_COUNTER_SYSTEM_PROPERTY_DEFAULT_VALUE))
     }
   }
 
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopRepositoryTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopRepositoryTest.kt
index 55b9724..e20f0ec 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopRepositoryTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopRepositoryTest.kt
@@ -940,6 +940,32 @@
         assertThat(repo.isTaskInFullImmersiveState(taskId = 2)).isTrue()
     }
 
+    @Test
+    fun removeDesktop_multipleTasks_removesAll() {
+        repo.addActiveTask(displayId = DEFAULT_DISPLAY, taskId = 1)
+        repo.addActiveTask(displayId = DEFAULT_DISPLAY, taskId = 2)
+        repo.addActiveTask(displayId = DEFAULT_DISPLAY, taskId = 3)
+        // The front-most task will be the one added last through `addOrMoveFreeformTaskToTop`
+        repo.addOrMoveFreeformTaskToTop(displayId = DEFAULT_DISPLAY, taskId = 3)
+        repo.addOrMoveFreeformTaskToTop(displayId = DEFAULT_DISPLAY, taskId = 2)
+        repo.addOrMoveFreeformTaskToTop(displayId = DEFAULT_DISPLAY, taskId = 1)
+        repo.minimizeTask(displayId = DEFAULT_DISPLAY, taskId = 2)
+
+        val tasksBeforeRemoval = repo.removeDesktop(displayId = DEFAULT_DISPLAY)
+
+        assertThat(tasksBeforeRemoval).containsExactly(1, 2, 3).inOrder()
+        assertThat(repo.getActiveTasks(displayId = DEFAULT_DISPLAY)).isEmpty()
+    }
+
+    @Test
+    fun getTaskInFullImmersiveState_byDisplay() {
+        repo.setTaskInFullImmersiveState(DEFAULT_DESKTOP_ID, taskId = 1, immersive = true)
+        repo.setTaskInFullImmersiveState(DEFAULT_DESKTOP_ID + 1, taskId = 2, immersive = true)
+
+        assertThat(repo.getTaskInFullImmersiveState(DEFAULT_DESKTOP_ID)).isEqualTo(1)
+        assertThat(repo.getTaskInFullImmersiveState(DEFAULT_DESKTOP_ID + 1)).isEqualTo(2)
+    }
+
     class TestListener : DesktopRepository.ActiveTasksListener {
         var activeChangesOnDefaultDisplay = 0
         var activeChangesOnSecondaryDisplay = 0
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt
index 9e5c1a6..b3c10d6 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt
@@ -42,6 +42,7 @@
 import android.os.Binder
 import android.os.Bundle
 import android.os.Handler
+import android.os.IBinder
 import android.platform.test.annotations.DisableFlags
 import android.platform.test.annotations.EnableFlags
 import android.platform.test.flag.junit.SetFlagsRule
@@ -50,6 +51,7 @@
 import android.view.DragEvent
 import android.view.Gravity
 import android.view.SurfaceControl
+import android.view.WindowInsets
 import android.view.WindowManager
 import android.view.WindowManager.TRANSIT_CHANGE
 import android.view.WindowManager.TRANSIT_CLOSE
@@ -75,6 +77,7 @@
 import com.android.internal.jank.InteractionJankMonitor
 import com.android.window.flags.Flags
 import com.android.window.flags.Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE
+import com.android.window.flags.Flags.FLAG_ENABLE_FULLY_IMMERSIVE_IN_DESKTOP
 import com.android.wm.shell.MockToken
 import com.android.wm.shell.R
 import com.android.wm.shell.RootTaskDisplayAreaOrganizer
@@ -97,6 +100,7 @@
 import com.android.wm.shell.desktopmode.persistence.Desktop
 import com.android.wm.shell.desktopmode.persistence.DesktopPersistentRepository
 import com.android.wm.shell.draganddrop.DragAndDropController
+import com.android.wm.shell.freeform.FreeformTaskTransitionStarter
 import com.android.wm.shell.recents.RecentTasksController
 import com.android.wm.shell.recents.RecentsTransitionHandler
 import com.android.wm.shell.recents.RecentsTransitionStateListener
@@ -147,7 +151,6 @@
 import org.mockito.Mockito.times
 import org.mockito.kotlin.any
 import org.mockito.kotlin.anyOrNull
-import org.mockito.kotlin.argThat
 import org.mockito.kotlin.atLeastOnce
 import org.mockito.kotlin.capture
 import org.mockito.kotlin.eq
@@ -198,6 +201,7 @@
   private lateinit var mockInteractionJankMonitor: InteractionJankMonitor
   @Mock private lateinit var mockSurface: SurfaceControl
   @Mock private lateinit var taskbarDesktopTaskListener: TaskbarDesktopTaskListener
+  @Mock private lateinit var freeformTaskTransitionStarter: FreeformTaskTransitionStarter
   @Mock private lateinit var mockHandler: Handler
   @Mock lateinit var persistentRepository: DesktopPersistentRepository
 
@@ -263,6 +267,7 @@
 
     controller = createController()
     controller.setSplitScreenController(splitScreenController)
+    controller.freeformTaskTransitionStarter = freeformTaskTransitionStarter
 
     shellInit.init()
 
@@ -1539,75 +1544,142 @@
   }
 
   @Test
-  fun onDesktopWindowMinimize_noActiveTask_doesntUpdateTransaction() {
-    val wct = WindowContainerTransaction()
-    controller.onDesktopWindowMinimize(wct, taskId = 1)
-    // Nothing happens.
-    assertThat(wct.hierarchyOps).isEmpty()
+  fun onDesktopWindowMinimize_noActiveTask_doesntRemoveWallpaper() {
+    val task = setUpFreeformTask(active = false)
+    val transition = Binder()
+    whenever(freeformTaskTransitionStarter.startMinimizedModeTransition(any()))
+      .thenReturn(transition)
+    val wallpaperToken = MockToken().token()
+    taskRepository.wallpaperActivityToken = wallpaperToken
+
+    controller.minimizeTask(task)
+
+    val captor = ArgumentCaptor.forClass(WindowContainerTransaction::class.java)
+    verify(freeformTaskTransitionStarter).startMinimizedModeTransition(captor.capture())
+    captor.value.hierarchyOps.none { hop ->
+      hop.type == HIERARCHY_OP_TYPE_REMOVE_TASK && hop.container == wallpaperToken.asBinder()
+    }
   }
 
   @Test
-  fun onDesktopWindowMinimize_singleActiveTask_noWallpaperActivityToken_doesntUpdateTransaction() {
-    val task = setUpFreeformTask()
-    val wct = WindowContainerTransaction()
-    controller.onDesktopWindowMinimize(wct, taskId = task.taskId)
-    // Nothing happens.
-    assertThat(wct.hierarchyOps).isEmpty()
+  fun onDesktopWindowMinimize_singleActiveTask_noWallpaperActivityToken_doesntRemoveWallpaper() {
+    val task = setUpFreeformTask(active = true)
+    val transition = Binder()
+    whenever(freeformTaskTransitionStarter.startMinimizedModeTransition(any()))
+      .thenReturn(transition)
+
+    controller.minimizeTask(task)
+
+    val captor = ArgumentCaptor.forClass(WindowContainerTransaction::class.java)
+    verify(freeformTaskTransitionStarter).startMinimizedModeTransition(captor.capture())
+    captor.value.hierarchyOps.none { hop ->
+      hop.type == HIERARCHY_OP_TYPE_REMOVE_TASK
+    }
   }
 
   @Test
   fun onDesktopWindowMinimize_singleActiveTask_hasWallpaperActivityToken_removesWallpaper() {
     val task = setUpFreeformTask()
+    val transition = Binder()
+    whenever(freeformTaskTransitionStarter.startMinimizedModeTransition(any()))
+      .thenReturn(transition)
     val wallpaperToken = MockToken().token()
     taskRepository.wallpaperActivityToken = wallpaperToken
 
-    val wct = WindowContainerTransaction()
     // The only active task is being minimized.
-    controller.onDesktopWindowMinimize(wct, taskId = task.taskId)
+    controller.minimizeTask(task)
+
+    val captor = ArgumentCaptor.forClass(WindowContainerTransaction::class.java)
+    verify(freeformTaskTransitionStarter).startMinimizedModeTransition(captor.capture())
     // Adds remove wallpaper operation
-    wct.assertRemoveAt(index = 0, wallpaperToken)
+    captor.value.assertRemoveAt(index = 0, wallpaperToken)
   }
 
   @Test
-  fun onDesktopWindowMinimize_singleActiveTask_alreadyMinimized_doesntUpdateTransaction() {
+  fun onDesktopWindowMinimize_singleActiveTask_alreadyMinimized_doesntRemoveWallpaper() {
     val task = setUpFreeformTask()
+    val transition = Binder()
+    whenever(freeformTaskTransitionStarter.startMinimizedModeTransition(any()))
+      .thenReturn(transition)
     val wallpaperToken = MockToken().token()
     taskRepository.wallpaperActivityToken = wallpaperToken
     taskRepository.minimizeTask(DEFAULT_DISPLAY, task.taskId)
 
-    val wct = WindowContainerTransaction()
     // The only active task is already minimized.
-    controller.onDesktopWindowMinimize(wct, taskId = task.taskId)
-    // Doesn't modify transaction
-    assertThat(wct.hierarchyOps).isEmpty()
+    controller.minimizeTask(task)
+
+    val captor = ArgumentCaptor.forClass(WindowContainerTransaction::class.java)
+    verify(freeformTaskTransitionStarter).startMinimizedModeTransition(captor.capture())
+    captor.value.hierarchyOps.none { hop ->
+      hop.type == HIERARCHY_OP_TYPE_REMOVE_TASK && hop.container == wallpaperToken.asBinder()
+    }
   }
 
   @Test
-  fun onDesktopWindowMinimize_multipleActiveTasks_doesntUpdateTransaction() {
-    val task1 = setUpFreeformTask()
-    setUpFreeformTask()
+  fun onDesktopWindowMinimize_multipleActiveTasks_doesntRemoveWallpaper() {
+    val task1 = setUpFreeformTask(active = true)
+    setUpFreeformTask(active = true)
+    val transition = Binder()
+    whenever(freeformTaskTransitionStarter.startMinimizedModeTransition(any()))
+      .thenReturn(transition)
     val wallpaperToken = MockToken().token()
     taskRepository.wallpaperActivityToken = wallpaperToken
 
-    val wct = WindowContainerTransaction()
-    controller.onDesktopWindowMinimize(wct, taskId = task1.taskId)
-    // Doesn't modify transaction
-    assertThat(wct.hierarchyOps).isEmpty()
+    controller.minimizeTask(task1)
+
+    val captor = ArgumentCaptor.forClass(WindowContainerTransaction::class.java)
+    verify(freeformTaskTransitionStarter).startMinimizedModeTransition(captor.capture())
+    captor.value.hierarchyOps.none { hop ->
+      hop.type == HIERARCHY_OP_TYPE_REMOVE_TASK && hop.container == wallpaperToken.asBinder()
+    }
   }
 
   @Test
   fun onDesktopWindowMinimize_multipleActiveTasks_minimizesTheOnlyVisibleTask_removesWallpaper() {
-    val task1 = setUpFreeformTask()
-    val task2 = setUpFreeformTask()
+    val task1 = setUpFreeformTask(active = true)
+    val task2 = setUpFreeformTask(active = true)
+    val transition = Binder()
+    whenever(freeformTaskTransitionStarter.startMinimizedModeTransition(any()))
+      .thenReturn(transition)
     val wallpaperToken = MockToken().token()
     taskRepository.wallpaperActivityToken = wallpaperToken
     taskRepository.minimizeTask(DEFAULT_DISPLAY, task2.taskId)
 
-    val wct = WindowContainerTransaction()
     // task1 is the only visible task as task2 is minimized.
-    controller.onDesktopWindowMinimize(wct, taskId = task1.taskId)
+    controller.minimizeTask(task1)
     // Adds remove wallpaper operation
-    wct.assertRemoveAt(index = 0, wallpaperToken)
+    val captor = ArgumentCaptor.forClass(WindowContainerTransaction::class.java)
+    verify(freeformTaskTransitionStarter).startMinimizedModeTransition(captor.capture())
+    // Adds remove wallpaper operation
+    captor.value.assertRemoveAt(index = 0, wallpaperToken)
+  }
+
+  @Test
+  fun onDesktopWindowMinimize_triesToExitImmersive() {
+    val task = setUpFreeformTask()
+    val transition = Binder()
+    whenever(freeformTaskTransitionStarter.startMinimizedModeTransition(any()))
+      .thenReturn(transition)
+
+    controller.minimizeTask(task)
+
+    verify(mockDesktopFullImmersiveTransitionHandler).exitImmersiveIfApplicable(any(), eq(task))
+  }
+
+  @Test
+  fun onDesktopWindowMinimize_invokesImmersiveTransitionStartCallback() {
+    val task = setUpFreeformTask()
+    val transition = Binder()
+    val runOnTransit = RunOnStartTransitionCallback()
+    whenever(freeformTaskTransitionStarter.startMinimizedModeTransition(any()))
+      .thenReturn(transition)
+    whenever(mockDesktopFullImmersiveTransitionHandler.exitImmersiveIfApplicable(any(), eq(task)))
+      .thenReturn(runOnTransit)
+
+    controller.minimizeTask(task)
+
+    assertThat(runOnTransit.invocations).isEqualTo(1)
+    assertThat(runOnTransit.lastInvoked).isEqualTo(transition)
   }
 
   @Test
@@ -2463,6 +2535,41 @@
   }
 
   @Test
+  @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_BACK_NAVIGATION)
+  fun removeDesktop_multipleTasks_removesAll() {
+    val task1 = setUpFreeformTask()
+    val task2 = setUpFreeformTask()
+    val task3 = setUpFreeformTask()
+    taskRepository.minimizeTask(DEFAULT_DISPLAY, task2.taskId)
+
+    controller.removeDesktop(displayId = DEFAULT_DISPLAY)
+
+    val wct = getLatestWct(TRANSIT_CLOSE)
+    assertThat(wct.hierarchyOps).hasSize(3)
+    wct.assertRemoveAt(index = 0, task1.token)
+    wct.assertRemoveAt(index = 1, task2.token)
+    wct.assertRemoveAt(index = 2, task3.token)
+  }
+
+  @Test
+  @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_BACK_NAVIGATION)
+  fun removeDesktop_multipleTasksWithBackgroundTask_removesAll() {
+    val task1 = setUpFreeformTask()
+    val task2 = setUpFreeformTask()
+    val task3 = setUpFreeformTask()
+    taskRepository.minimizeTask(DEFAULT_DISPLAY, task2.taskId)
+    whenever(shellTaskOrganizer.getRunningTaskInfo(task3.taskId)).thenReturn(null)
+
+    controller.removeDesktop(displayId = DEFAULT_DISPLAY)
+
+    val wct = getLatestWct(TRANSIT_CLOSE)
+    assertThat(wct.hierarchyOps).hasSize(2)
+    wct.assertRemoveAt(index = 0, task1.token)
+    wct.assertRemoveAt(index = 1, task2.token)
+    verify(recentTasksController).removeBackgroundTask(task3.taskId)
+  }
+
+  @Test
   @EnableFlags(Flags.FLAG_ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS)
   fun dragToDesktop_landscapeDevice_resizable_undefinedOrientation_defaultLandscapeBounds() {
     val spyController = spy(controller)
@@ -3128,27 +3235,153 @@
   }
 
   @Test
-  fun toggleImmersive_enter_resizesToDisplayBounds() {
+  fun toggleImmersive_enter_movesToImmersive() {
     val task = setUpFreeformTask(DEFAULT_DISPLAY)
     taskRepository.setTaskInFullImmersiveState(DEFAULT_DISPLAY, task.taskId, false /* immersive */)
 
     controller.toggleDesktopTaskFullImmersiveState(task)
 
-    verify(mockDesktopFullImmersiveTransitionHandler).enterImmersive(eq(task), argThat { wct ->
-      wct.hasBoundsChange(task.token, Rect())
-    })
+    verify(mockDesktopFullImmersiveTransitionHandler).moveTaskToImmersive(task)
   }
 
   @Test
-  fun toggleImmersive_exit_resizesToStableBounds() {
+  fun toggleImmersive_exit_movesToNonImmersive() {
     val task = setUpFreeformTask(DEFAULT_DISPLAY)
     taskRepository.setTaskInFullImmersiveState(DEFAULT_DISPLAY, task.taskId, true /* immersive */)
 
     controller.toggleDesktopTaskFullImmersiveState(task)
 
-    verify(mockDesktopFullImmersiveTransitionHandler).exitImmersive(eq(task), argThat { wct ->
-      wct.hasBoundsChange(task.token, STABLE_BOUNDS)
-    })
+    verify(mockDesktopFullImmersiveTransitionHandler).moveTaskToNonImmersive(task)
+  }
+
+  @Test
+  @EnableFlags(FLAG_ENABLE_FULLY_IMMERSIVE_IN_DESKTOP)
+  fun onTaskInfoChanged_inImmersiveUnrequestsImmersive_exits() {
+    val task = setUpFreeformTask(DEFAULT_DISPLAY)
+    taskRepository.setTaskInFullImmersiveState(DEFAULT_DISPLAY, task.taskId, immersive = true)
+
+    task.requestedVisibleTypes = WindowInsets.Type.statusBars()
+    controller.onTaskInfoChanged(task)
+
+    verify(mockDesktopFullImmersiveTransitionHandler).moveTaskToNonImmersive(task)
+  }
+
+  @Test
+  @EnableFlags(FLAG_ENABLE_FULLY_IMMERSIVE_IN_DESKTOP)
+  fun onTaskInfoChanged_notInImmersiveUnrequestsImmersive_noReExit() {
+    val task = setUpFreeformTask(DEFAULT_DISPLAY)
+    taskRepository.setTaskInFullImmersiveState(DEFAULT_DISPLAY, task.taskId, immersive = false)
+
+    task.requestedVisibleTypes = WindowInsets.Type.statusBars()
+    controller.onTaskInfoChanged(task)
+
+    verify(mockDesktopFullImmersiveTransitionHandler, never()).moveTaskToNonImmersive(task)
+  }
+
+  @Test
+  fun moveTaskToDesktop_background_attemptsImmersiveExit() {
+    val task = setUpFreeformTask(background = true)
+    val wct = WindowContainerTransaction()
+    val runOnStartTransit = RunOnStartTransitionCallback()
+    val transition = Binder()
+    whenever(mockDesktopFullImmersiveTransitionHandler
+      .exitImmersiveIfApplicable(wct, task.displayId)).thenReturn(runOnStartTransit)
+    whenever(enterDesktopTransitionHandler.moveToDesktop(wct, UNKNOWN)).thenReturn(transition)
+
+    controller.moveTaskToDesktop(taskId = task.taskId, wct = wct, transitionSource = UNKNOWN)
+
+    verify(mockDesktopFullImmersiveTransitionHandler).exitImmersiveIfApplicable(wct, task.displayId)
+    runOnStartTransit.assertOnlyInvocation(transition)
+  }
+
+  @Test
+  fun moveTaskToDesktop_foreground_attemptsImmersiveExit() {
+    val task = setUpFreeformTask(background = false)
+    val wct = WindowContainerTransaction()
+    val runOnStartTransit = RunOnStartTransitionCallback()
+    val transition = Binder()
+    whenever(mockDesktopFullImmersiveTransitionHandler
+      .exitImmersiveIfApplicable(wct, task.displayId)).thenReturn(runOnStartTransit)
+    whenever(enterDesktopTransitionHandler.moveToDesktop(wct, UNKNOWN)).thenReturn(transition)
+
+    controller.moveTaskToDesktop(taskId = task.taskId, wct = wct, transitionSource = UNKNOWN)
+
+    verify(mockDesktopFullImmersiveTransitionHandler).exitImmersiveIfApplicable(wct, task.displayId)
+    runOnStartTransit.assertOnlyInvocation(transition)
+  }
+
+  @Test
+  fun moveTaskToFront_background_attemptsImmersiveExit() {
+    val task = setUpFreeformTask(background = true)
+    val runOnStartTransit = RunOnStartTransitionCallback()
+    val transition = Binder()
+    whenever(mockDesktopFullImmersiveTransitionHandler
+      .exitImmersiveIfApplicable(any(), eq(task.displayId))).thenReturn(runOnStartTransit)
+    whenever(transitions.startTransition(any(), any(), anyOrNull())).thenReturn(transition)
+
+    controller.moveTaskToFront(task.taskId)
+
+    verify(mockDesktopFullImmersiveTransitionHandler)
+      .exitImmersiveIfApplicable(any(), eq(task.displayId))
+    runOnStartTransit.assertOnlyInvocation(transition)
+  }
+
+  @Test
+  fun moveTaskToFront_foreground_attemptsImmersiveExit() {
+    val task = setUpFreeformTask(background = false)
+    val runOnStartTransit = RunOnStartTransitionCallback()
+    val transition = Binder()
+    whenever(mockDesktopFullImmersiveTransitionHandler
+      .exitImmersiveIfApplicable(any(), eq(task.displayId))).thenReturn(runOnStartTransit)
+    whenever(transitions.startTransition(any(), any(), anyOrNull())).thenReturn(transition)
+
+    controller.moveTaskToFront(task.taskId)
+
+    verify(mockDesktopFullImmersiveTransitionHandler)
+      .exitImmersiveIfApplicable(any(), eq(task.displayId))
+    runOnStartTransit.assertOnlyInvocation(transition)
+  }
+
+  @Test
+  fun handleRequest_freeformLaunchToDesktop_attemptsImmersiveExit() {
+    markTaskVisible(setUpFreeformTask())
+    val task = setUpFreeformTask()
+    markTaskVisible(task)
+    val binder = Binder()
+
+    controller.handleRequest(binder, createTransition(task))
+
+    verify(mockDesktopFullImmersiveTransitionHandler)
+      .exitImmersiveIfApplicable(eq(binder), any(), eq(task.displayId))
+  }
+
+  @Test
+  fun handleRequest_fullscreenLaunchToDesktop_attemptsImmersiveExit() {
+    setUpFreeformTask()
+    val task = setUpFullscreenTask()
+    val binder = Binder()
+
+    controller.handleRequest(binder, createTransition(task))
+
+    verify(mockDesktopFullImmersiveTransitionHandler)
+      .exitImmersiveIfApplicable(eq(binder), any(), eq(task.displayId))
+  }
+
+  private class RunOnStartTransitionCallback : ((IBinder) -> Unit) {
+    var invocations = 0
+      private set
+    var lastInvoked: IBinder? = null
+      private set
+
+    override fun invoke(transition: IBinder) {
+      invocations++
+      lastInvoked = transition
+    }
+  }
+
+  private fun RunOnStartTransitionCallback.assertOnlyInvocation(transition: IBinder) {
+    assertThat(invocations).isEqualTo(1)
+    assertThat(lastInvoked).isEqualTo(transition)
   }
 
   /**
@@ -3229,18 +3462,27 @@
   private fun setUpFreeformTask(
       displayId: Int = DEFAULT_DISPLAY,
       bounds: Rect? = null,
-      active: Boolean = true
+      active: Boolean = true,
+      background: Boolean = false,
   ): RunningTaskInfo {
     val task = createFreeformTask(displayId, bounds)
     val activityInfo = ActivityInfo()
     task.topActivityInfo = activityInfo
-    whenever(shellTaskOrganizer.getRunningTaskInfo(task.taskId)).thenReturn(task)
+    if (background) {
+      whenever(shellTaskOrganizer.getRunningTaskInfo(task.taskId)).thenReturn(null)
+      whenever(recentTasksController.findTaskInBackground(task.taskId))
+        .thenReturn(createTaskInfo(task.taskId))
+    } else {
+      whenever(shellTaskOrganizer.getRunningTaskInfo(task.taskId)).thenReturn(task)
+    }
     if (active) {
       taskRepository.addActiveTask(displayId, task.taskId)
       taskRepository.updateTaskVisibility(displayId, task.taskId, visible = true)
     }
     taskRepository.addOrMoveFreeformTaskToTop(displayId, task.taskId)
-    runningTasks.add(task)
+    if (!background) {
+      runningTasks.add(task)
+    }
     return task
   }
 
@@ -3494,6 +3736,21 @@
   assertThat(op.container).isEqualTo(token.asBinder())
 }
 
+private fun WindowContainerTransaction.assertNoRemoveAt(index: Int, token: WindowContainerToken) {
+  assertIndexInBounds(index)
+  val op = hierarchyOps[index]
+  assertThat(op.type).isEqualTo(HIERARCHY_OP_TYPE_REMOVE_TASK)
+  assertThat(op.container).isEqualTo(token.asBinder())
+}
+
+private fun WindowContainerTransaction.hasRemoveAt(index: Int, token: WindowContainerToken) {
+
+  assertIndexInBounds(index)
+  val op = hierarchyOps[index]
+  assertThat(op.type).isEqualTo(HIERARCHY_OP_TYPE_REMOVE_TASK)
+  assertThat(op.container).isEqualTo(token.asBinder())
+}
+
 private fun WindowContainerTransaction.assertPendingIntentAt(index: Int, intent: Intent) {
   assertIndexInBounds(index)
   val op = hierarchyOps[index]
@@ -3516,13 +3773,6 @@
       .isEqualTo(windowingMode)
 }
 
-private fun WindowContainerTransaction.hasBoundsChange(
-  token: WindowContainerToken,
-  bounds: Rect
-): Boolean = this.changes.any { change ->
-  change.key == token.asBinder() && change.value.configuration.windowConfiguration.bounds == bounds
-}
-
 private fun WindowContainerTransaction?.anyDensityConfigChange(
     token: WindowContainerToken
 ): Boolean {
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksTransitionObserverTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksTransitionObserverTest.kt
index 598df34..fe87aa8 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksTransitionObserverTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksTransitionObserverTest.kt
@@ -22,26 +22,38 @@
 import android.content.ComponentName
 import android.content.Context
 import android.content.Intent
+import android.os.IBinder
 import android.platform.test.annotations.EnableFlags
 import android.view.Display.DEFAULT_DISPLAY
+import android.view.WindowManager
+import android.view.WindowManager.TRANSIT_CLOSE
 import android.view.WindowManager.TRANSIT_OPEN
 import android.view.WindowManager.TRANSIT_TO_BACK
 import android.window.IWindowContainerToken
 import android.window.TransitionInfo
 import android.window.TransitionInfo.Change
 import android.window.WindowContainerToken
+import android.window.WindowContainerTransaction
+import android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REMOVE_TASK
 import com.android.modules.utils.testing.ExtendedMockitoRule
 import com.android.window.flags.Flags
+import com.android.wm.shell.MockToken
 import com.android.wm.shell.ShellTaskOrganizer
 import com.android.wm.shell.common.ShellExecutor
 import com.android.wm.shell.shared.desktopmode.DesktopModeStatus
 import com.android.wm.shell.sysui.ShellInit
 import com.android.wm.shell.transition.Transitions
+import com.google.common.truth.Truth.assertThat
+import com.google.common.truth.Truth.assertWithMessage
 import org.junit.Before
 import org.junit.Rule
 import org.junit.Test
+import org.mockito.ArgumentCaptor
+import org.mockito.ArgumentMatchers.eq
+import org.mockito.ArgumentMatchers.isA
 import org.mockito.Mockito
 import org.mockito.kotlin.any
+import org.mockito.kotlin.isNull
 import org.mockito.kotlin.mock
 import org.mockito.kotlin.never
 import org.mockito.kotlin.spy
@@ -130,6 +142,27 @@
         verify(taskRepository).removeFreeformTask(task.displayId, task.taskId)
     }
 
+    @Test
+    fun closeLastTask_wallpaperTokenExists_wallpaperIsRemoved() {
+        val mockTransition = Mockito.mock(IBinder::class.java)
+        val task = createTaskInfo(1, WINDOWING_MODE_FREEFORM)
+        val wallpaperToken = MockToken().token()
+        whenever(taskRepository.getVisibleTaskCount(task.displayId)).thenReturn(1)
+        whenever(taskRepository.wallpaperActivityToken).thenReturn(wallpaperToken)
+
+        transitionObserver.onTransitionReady(
+            transition = mockTransition,
+            info = createCloseTransition(task),
+            startTransaction = mock(),
+            finishTransaction = mock(),
+        )
+        transitionObserver.onTransitionFinished(mockTransition, false)
+
+        val wct = getLatestWct(type = TRANSIT_CLOSE)
+        assertThat(wct.hierarchyOps).hasSize(1)
+        wct.assertRemoveAt(index = 0, wallpaperToken)
+    }
+
     private fun createBackNavigationTransition(
         task: RunningTaskInfo?
     ): TransitionInfo {
@@ -160,6 +193,48 @@
         }
     }
 
+    private fun createCloseTransition(
+        task: RunningTaskInfo?
+    ): TransitionInfo {
+        return TransitionInfo(TRANSIT_CLOSE, 0 /* flags */).apply {
+            addChange(
+                Change(mock(), mock()).apply {
+                    mode = TRANSIT_CLOSE
+                    parent = null
+                    taskInfo = task
+                    flags = flags
+                }
+            )
+        }
+    }
+
+    private fun getLatestWct(
+        @WindowManager.TransitionType type: Int = TRANSIT_OPEN,
+        handlerClass: Class<out Transitions.TransitionHandler>? = null
+    ): WindowContainerTransaction {
+        val arg = ArgumentCaptor.forClass(WindowContainerTransaction::class.java)
+        if (handlerClass == null) {
+            Mockito.verify(transitions).startTransition(eq(type), arg.capture(), isNull())
+        } else {
+            Mockito.verify(transitions)
+                .startTransition(eq(type), arg.capture(), isA(handlerClass))
+        }
+        return arg.value
+    }
+
+    private fun WindowContainerTransaction.assertRemoveAt(index: Int, token: WindowContainerToken) {
+        assertIndexInBounds(index)
+        val op = hierarchyOps[index]
+        assertThat(op.type).isEqualTo(HIERARCHY_OP_TYPE_REMOVE_TASK)
+        assertThat(op.container).isEqualTo(token.asBinder())
+    }
+
+    private fun WindowContainerTransaction.assertIndexInBounds(index: Int) {
+        assertWithMessage("WCT does not have a hierarchy operation at index $index")
+            .that(hierarchyOps.size)
+            .isGreaterThan(index)
+    }
+
     private fun createTaskInfo(id: Int, windowingMode: Int = WINDOWING_MODE_FREEFORM) =
         RunningTaskInfo().apply {
             taskId = id
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/SplitDragPolicyTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/SplitDragPolicyTest.java
index 46b60499..eb74218 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/SplitDragPolicyTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/SplitDragPolicyTest.java
@@ -150,7 +150,8 @@
         mPortraitDisplayLayout = new DisplayLayout(info2, res, false, false);
         mInsets = Insets.of(0, 0, 0, 0);
 
-        mPolicy = spy(new SplitDragPolicy(mContext, mSplitScreenStarter, mFullscreenStarter));
+        mPolicy = spy(new SplitDragPolicy(mContext, mSplitScreenStarter, mFullscreenStarter,
+                mock(DragZoneAnimator.class)));
         mActivityClipData = createAppClipData(MIMETYPE_APPLICATION_ACTIVITY);
         mLaunchableIntentPendingIntent = mock(PendingIntent.class);
         when(mLaunchableIntentPendingIntent.getCreatorUserHandle())
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/freeform/FreeformTaskListenerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/freeform/FreeformTaskListenerTests.java
index 956ef14..f95b0d1 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/freeform/FreeformTaskListenerTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/freeform/FreeformTaskListenerTests.java
@@ -42,6 +42,7 @@
 import com.android.wm.shell.TestRunningTaskInfoBuilder;
 import com.android.wm.shell.common.LaunchAdjacentController;
 import com.android.wm.shell.desktopmode.DesktopRepository;
+import com.android.wm.shell.desktopmode.DesktopTasksController;
 import com.android.wm.shell.shared.desktopmode.DesktopModeStatus;
 import com.android.wm.shell.sysui.ShellInit;
 import com.android.wm.shell.windowdecor.WindowDecorViewModel;
@@ -75,6 +76,8 @@
     @Mock
     private DesktopRepository mDesktopRepository;
     @Mock
+    private DesktopTasksController mDesktopTasksController;
+    @Mock
     private LaunchAdjacentController mLaunchAdjacentController;
     private FreeformTaskListener mFreeformTaskListener;
     private StaticMockitoSession mMockitoSession;
@@ -90,6 +93,7 @@
                 mShellInit,
                 mTaskOrganizer,
                 Optional.of(mDesktopRepository),
+                Optional.of(mDesktopTasksController),
                 mLaunchAdjacentController,
                 mWindowDecorViewModel);
     }
@@ -174,9 +178,22 @@
         mFreeformTaskListener.onTaskVanished(task);
 
         verify(mDesktopRepository, never()).minimizeTask(task.displayId, task.taskId);
+        verify(mDesktopRepository).removeClosingTask(task.taskId);
         verify(mDesktopRepository).removeFreeformTask(task.displayId, task.taskId);
     }
 
+    @Test
+    public void onTaskInfoChanged_withDesktopController_forwards() {
+        ActivityManager.RunningTaskInfo task = new TestRunningTaskInfoBuilder()
+                .setWindowingMode(WINDOWING_MODE_FREEFORM).build();
+        task.isVisible = true;
+        mFreeformTaskListener.onTaskAppeared(task, mMockSurfaceControl);
+
+        mFreeformTaskListener.onTaskInfoChanged(task);
+
+        verify(mDesktopTasksController).onTaskInfoChanged(task);
+    }
+
     @After
     public void tearDown() {
         mMockitoSession.finishMocking();
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/freeform/FreeformTaskTransitionObserverTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/freeform/FreeformTaskTransitionObserverTest.java
index 86a8502..7ae0bcd 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/freeform/FreeformTaskTransitionObserverTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/freeform/FreeformTaskTransitionObserverTest.java
@@ -20,8 +20,8 @@
 import static android.view.WindowManager.TRANSIT_CHANGE;
 import static android.view.WindowManager.TRANSIT_CLOSE;
 import static android.view.WindowManager.TRANSIT_OPEN;
+import static android.view.WindowManager.TRANSIT_TO_BACK;
 import static android.view.WindowManager.TRANSIT_TO_FRONT;
-import static android.view.WindowManager.TRANSIT_CHANGE;
 
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
@@ -43,18 +43,14 @@
 import androidx.test.filters.SmallTest;
 
 import com.android.window.flags.Flags;
-
-import com.android.wm.shell.desktopmode.DesktopTaskChangeListener;
 import com.android.wm.shell.desktopmode.DesktopFullImmersiveTransitionHandler;
 import com.android.wm.shell.sysui.ShellInit;
+import com.android.wm.shell.transition.FocusTransitionObserver;
 import com.android.wm.shell.transition.TransitionInfoBuilder;
 import com.android.wm.shell.transition.Transitions;
 import com.android.wm.shell.windowdecor.WindowDecorViewModel;
 
-import java.util.Optional;
-
 import org.junit.Before;
-import org.junit.Rule;
 import org.junit.Test;
 import org.mockito.ArgumentCaptor;
 import org.mockito.Mock;
@@ -79,6 +75,9 @@
     private WindowDecorViewModel mWindowDecorViewModel;
     @Mock
     private TaskChangeListener mTaskChangeListener;
+    @Mock
+    private FocusTransitionObserver mFocusTransitionObserver;
+
     private FreeformTaskTransitionObserver mTransitionObserver;
 
     @Before
@@ -94,16 +93,13 @@
         mTransitionObserver = new FreeformTaskTransitionObserver(
                 context, mShellInit, mTransitions,
                 Optional.of(mDesktopFullImmersiveTransitionHandler),
-                mWindowDecorViewModel, Optional.of(mTaskChangeListener));
-        if (Transitions.ENABLE_SHELL_TRANSITIONS) {
-            final ArgumentCaptor<Runnable> initRunnableCaptor = ArgumentCaptor.forClass(
-                    Runnable.class);
-            verify(mShellInit).addInitCallback(initRunnableCaptor.capture(),
-                    same(mTransitionObserver));
-            initRunnableCaptor.getValue().run();
-        } else {
-            mTransitionObserver.onInit();
-        }
+                mWindowDecorViewModel, Optional.of(mTaskChangeListener), mFocusTransitionObserver);
+
+        final ArgumentCaptor<Runnable> initRunnableCaptor = ArgumentCaptor.forClass(
+                Runnable.class);
+        verify(mShellInit).addInitCallback(initRunnableCaptor.capture(),
+                same(mTransitionObserver));
+        initRunnableCaptor.getValue().run();
     }
 
     @Test
@@ -161,6 +157,22 @@
     }
 
     @Test
+    public void toBackTransition_notifiesOnTaskMovingToBack() {
+        final TransitionInfo.Change change =
+                createChange(TRANSIT_TO_BACK, /* taskId= */ 1, WINDOWING_MODE_FREEFORM);
+        final TransitionInfo info = new TransitionInfoBuilder(TRANSIT_TO_BACK, /* flags= */ 0)
+                .addChange(change).build();
+
+        final IBinder transition = mock(IBinder.class);
+        final SurfaceControl.Transaction startT = mock(SurfaceControl.Transaction.class);
+        final SurfaceControl.Transaction finishT = mock(SurfaceControl.Transaction.class);
+        mTransitionObserver.onTransitionReady(transition, info, startT, finishT);
+        mTransitionObserver.onTransitionStarting(transition);
+
+        verify(mTaskChangeListener).onTaskMovingToBack(change.getTaskInfo());
+    }
+
+    @Test
     public void changeTransition_notifiesOnTaskChanging() {
         final TransitionInfo.Change change =
                 createChange(TRANSIT_CHANGE, /* taskId= */ 1, WINDOWING_MODE_FREEFORM);
@@ -317,7 +329,7 @@
 
         mTransitionObserver.onTransitionReady(transition, info, startT, finishT);
 
-        verify(mDesktopFullImmersiveTransitionHandler).onTransitionReady(transition);
+        verify(mDesktopFullImmersiveTransitionHandler).onTransitionReady(transition, info);
     }
 
     private static TransitionInfo.Change createChange(int mode, int taskId, int windowingMode) {
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/TaskStackTransitionObserverTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/TaskStackTransitionObserverTest.kt
index 0e5efa6..afdb687 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/TaskStackTransitionObserverTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/TaskStackTransitionObserverTest.kt
@@ -114,7 +114,7 @@
 
     @Test
     @EnableFlags(Flags.FLAG_ENABLE_TASK_STACK_OBSERVER_IN_SHELL)
-    fun taskCreated_fullscreenWindow_listenerNotNotified() {
+    fun taskCreated_fullscreenWindow_listenerNotified() {
         val listener = TestListener()
         val executor = TestShellExecutor()
         transitionObserver.addTaskStackTransitionObserverListener(listener, executor)
@@ -130,9 +130,9 @@
         callOnTransitionFinished()
         executor.flushAll()
 
-        assertThat(listener.taskInfoToBeNotified.taskId).isEqualTo(0)
+        assertThat(listener.taskInfoToBeNotified.taskId).isEqualTo(1)
         assertThat(listener.taskInfoToBeNotified.windowingMode)
-            .isEqualTo(WindowConfiguration.WINDOWING_MODE_UNDEFINED)
+            .isEqualTo(WindowConfiguration.WINDOWING_MODE_FULLSCREEN)
     }
 
     @Test
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/shared/bubbles/BubbleInfoTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/shared/bubbles/BubbleInfoTest.kt
index 641063c..205defe 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/shared/bubbles/BubbleInfoTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/shared/bubbles/BubbleInfoTest.kt
@@ -16,6 +16,8 @@
 
 package com.android.wm.shell.shared.bubbles
 
+import android.graphics.drawable.Icon
+import android.net.Uri
 import android.os.Parcel
 import android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE
 import android.testing.AndroidTestingRunner
@@ -42,7 +44,12 @@
                 "title",
                 "Some app",
                 true,
-                true
+                true,
+                ParcelableFlyoutMessage(
+                    Icon.createWithContentUri(Uri.parse("content://image/123")),
+                    "sender",
+                    "message"
+                )
             )
         val parcel = Parcel.obtain()
         bubbleInfo.writeToParcel(parcel, PARCELABLE_WRITE_RETURN_VALUE)
@@ -60,5 +67,10 @@
         assertThat(bubbleInfo.appName).isEqualTo(bubbleInfoFromParcel.appName)
         assertThat(bubbleInfo.isImportantConversation)
             .isEqualTo(bubbleInfoFromParcel.isImportantConversation)
+        with(bubbleInfo.parcelableFlyoutMessage!!) {
+            assertThat(icon!!.uri.toString()).isEqualTo("content://image/123")
+            assertThat(title).isEqualTo("sender")
+            assertThat(message).isEqualTo("message")
+        }
     }
 }
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java
index 67eda8b..a6e33e5 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java
@@ -232,17 +232,6 @@
     }
 
     @Test
-    public void testRemoveFromSideStage() {
-        final ActivityManager.RunningTaskInfo task = new TestRunningTaskInfoBuilder().build();
-
-        doReturn(false).when(mMainStage).isActive();
-        mStageCoordinator.removeFromSideStage(task.taskId);
-
-        verify(mSideStage).removeTask(
-                eq(task.taskId), any(), any(WindowContainerTransaction.class));
-    }
-
-    @Test
     public void testResolveStartStage_beforeSplitActivated_setsStagePosition() {
         mStageCoordinator.setSideStagePosition(SPLIT_POSITION_TOP_OR_LEFT, null /* wct */);
 
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/FocusTransitionObserverTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/FocusTransitionObserverTest.java
index d63158c..015ea20 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/FocusTransitionObserverTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/FocusTransitionObserverTest.java
@@ -23,6 +23,7 @@
 
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
 
+import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.Mockito.clearInvocations;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
@@ -30,9 +31,6 @@
 import static org.mockito.Mockito.when;
 
 import android.app.ActivityManager.RunningTaskInfo;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.Looper;
 import android.os.RemoteException;
 import android.platform.test.annotations.RequiresFlagsEnabled;
 import android.platform.test.flag.junit.CheckFlagsRule;
@@ -43,17 +41,11 @@
 
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
-import androidx.test.platform.app.InstrumentationRegistry;
 
 import com.android.window.flags.Flags;
-import com.android.wm.shell.ShellTaskOrganizer;
 import com.android.wm.shell.ShellTestCase;
 import com.android.wm.shell.TestShellExecutor;
-import com.android.wm.shell.common.DisplayController;
-import com.android.wm.shell.shared.IFocusTransitionListener;
-import com.android.wm.shell.shared.TransactionPool;
-import com.android.wm.shell.sysui.ShellController;
-import com.android.wm.shell.sysui.ShellInit;
+import com.android.wm.shell.shared.FocusTransitionListener;
 
 import org.junit.Before;
 import org.junit.Rule;
@@ -75,57 +67,64 @@
 
     @Rule
     public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
-    private IFocusTransitionListener mListener;
-    private Transitions mTransition;
+    private FocusTransitionListener mListener;
+    private final TestShellExecutor mShellExecutor = new TestShellExecutor();
     private FocusTransitionObserver mFocusTransitionObserver;
 
     @Before
     public void setUp() {
-        mListener = mock(IFocusTransitionListener.class);
-        when(mListener.asBinder()).thenReturn(mock(IBinder.class));
-
+        mListener = mock(FocusTransitionListener.class);
         mFocusTransitionObserver = new FocusTransitionObserver();
-        mTransition =
-                new Transitions(InstrumentationRegistry.getInstrumentation().getTargetContext(),
-                        mock(ShellInit.class), mock(ShellController.class),
-                        mock(ShellTaskOrganizer.class), mock(TransactionPool.class),
-                        mock(DisplayController.class), new TestShellExecutor(),
-                        new Handler(Looper.getMainLooper()), new TestShellExecutor(),
-                        mock(HomeTransitionObserver.class),
-                mFocusTransitionObserver);
-        mFocusTransitionObserver.setRemoteFocusTransitionListener(mTransition, mListener);
+        mFocusTransitionObserver.setLocalFocusTransitionListener(mListener, mShellExecutor);
+        mShellExecutor.flushAll();
+        clearInvocations(mListener);
     }
 
     @Test
-    public void testOnlyDisplayChangeAffectsDisplayFocus() throws RemoteException {
-        final IBinder binder = mock(IBinder.class);
+    public void testBasicTaskAndDisplayFocusSwitch() throws RemoteException {
         final SurfaceControl.Transaction tx = mock(SurfaceControl.Transaction.class);
 
-        // Open a task on the secondary display, but it doesn't change display focus because it only
-        // has a task change.
+        // First, open a task on the default display.
         TransitionInfo info = mock(TransitionInfo.class);
         final List<TransitionInfo.Change> changes = new ArrayList<>();
-        setupTaskChange(changes, 123 /* taskId */, TRANSIT_OPEN, SECONDARY_DISPLAY_ID,
-                true /* focused */);
+        setupTaskChange(changes, 1 /* taskId */, TRANSIT_OPEN,
+                DEFAULT_DISPLAY, true /* focused */);
         when(info.getChanges()).thenReturn(changes);
-        mFocusTransitionObserver.onTransitionReady(binder, info, tx, tx);
-        verify(mListener, never()).onFocusedDisplayChanged(SECONDARY_DISPLAY_ID);
+        mFocusTransitionObserver.updateFocusState(info);
+        mShellExecutor.flushAll();
+        verify(mListener, never()).onFocusedDisplayChanged(anyInt());
+        verify(mListener, times(1)).onFocusedTaskChanged(1 /* taskId */,
+                true /* isFocusedOnDisplay */, true /* isFocusedGlobally */);
         clearInvocations(mListener);
 
-        // Moving the secondary display to front must change display focus to it.
-        changes.clear();
+        // Open a task on the secondary display.
+        setupTaskChange(changes, 2 /* taskId */, TRANSIT_OPEN,
+                SECONDARY_DISPLAY_ID, true /* focused */);
         setupDisplayToTopChange(changes, SECONDARY_DISPLAY_ID);
         when(info.getChanges()).thenReturn(changes);
-        mFocusTransitionObserver.onTransitionReady(binder, info, tx, tx);
+        mFocusTransitionObserver.updateFocusState(info);
+        mShellExecutor.flushAll();
         verify(mListener, times(1))
                 .onFocusedDisplayChanged(SECONDARY_DISPLAY_ID);
+        verify(mListener, times(1)).onFocusedTaskChanged(1 /* taskId */,
+                true /* isFocusedOnDisplay */, false /* isFocusedGlobally */);
+        verify(mListener, times(1)).onFocusedTaskChanged(2 /* taskId */,
+                true /* isFocusedOnDisplay */, true /* isFocusedGlobally */);
+        clearInvocations(mListener);
 
-        // Moving the secondary display to front must change display focus back to it.
+        // Moving only the default display back to front, and verify that affected tasks are also
+        // notified.
         changes.clear();
         setupDisplayToTopChange(changes, DEFAULT_DISPLAY);
         when(info.getChanges()).thenReturn(changes);
-        mFocusTransitionObserver.onTransitionReady(binder, info, tx, tx);
-        verify(mListener, times(1)).onFocusedDisplayChanged(DEFAULT_DISPLAY);
+        mFocusTransitionObserver.updateFocusState(info);
+        mShellExecutor.flushAll();
+        verify(mListener, times(1))
+                .onFocusedDisplayChanged(DEFAULT_DISPLAY);
+        verify(mListener, times(1)).onFocusedTaskChanged(1 /* taskId */,
+                true /* isFocusedOnDisplay */, true /* isFocusedGlobally */);
+        verify(mListener, times(1)).onFocusedTaskChanged(2 /* taskId */,
+                true /* isFocusedOnDisplay */, false /* isFocusedGlobally */);
     }
 
     private void setupTaskChange(List<TransitionInfo.Change> changes, int taskId,
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/CaptionWindowDecorationTests.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/CaptionWindowDecorationTests.kt
index 0f16b9d..5ebf517 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/CaptionWindowDecorationTests.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/CaptionWindowDecorationTests.kt
@@ -49,7 +49,8 @@
             false,
             true /* isStatusBarVisible */,
             false /* isKeyguardVisibleAndOccluded */,
-            InsetsState()
+            InsetsState(),
+            true /* hasGlobalFocus */
         )
 
         Truth.assertThat(relayoutParams.hasInputFeatureSpy()).isTrue()
@@ -70,7 +71,8 @@
             false,
             true /* isStatusBarVisible */,
             false /* isKeyguardVisibleAndOccluded */,
-            InsetsState()
+            InsetsState(),
+            true /* hasGlobalFocus */
         )
 
         Truth.assertThat(relayoutParams.hasInputFeatureSpy()).isFalse()
@@ -87,7 +89,8 @@
             false,
             true /* isStatusBarVisible */,
             false /* isKeyguardVisibleAndOccluded */,
-            InsetsState()
+            InsetsState(),
+            true /* hasGlobalFocus */
         )
         Truth.assertThat(relayoutParams.mOccludingCaptionElements.size).isEqualTo(2)
         Truth.assertThat(relayoutParams.mOccludingCaptionElements[0].mAlignment).isEqualTo(
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 4aa7e18..175fbd2 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
@@ -100,6 +100,7 @@
 import com.android.wm.shell.sysui.ShellCommandHandler
 import com.android.wm.shell.sysui.ShellController
 import com.android.wm.shell.sysui.ShellInit
+import com.android.wm.shell.transition.FocusTransitionObserver
 import com.android.wm.shell.transition.Transitions
 import com.android.wm.shell.windowdecor.DesktopModeWindowDecorViewModel.DesktopModeKeyguardChangeListener
 import com.android.wm.shell.windowdecor.DesktopModeWindowDecorViewModel.DesktopModeOnInsetsChangedListener
@@ -126,7 +127,6 @@
 import org.mockito.Mockito.times
 import org.mockito.kotlin.verify
 import org.mockito.kotlin.any
-import org.mockito.kotlin.anyOrNull
 import org.mockito.kotlin.argThat
 import org.mockito.kotlin.argumentCaptor
 import org.mockito.kotlin.doNothing
@@ -192,6 +192,7 @@
             DesktopModeWindowDecorViewModel.TaskPositionerFactory
     @Mock private lateinit var mockTaskPositioner: TaskPositioner
     @Mock private lateinit var mockAppHandleEducationController: AppHandleEducationController
+    @Mock private lateinit var mockFocusTransitionObserver: FocusTransitionObserver
     @Mock private lateinit var mockCaptionHandleRepository: WindowDecorCaptionHandleRepository
     private lateinit var spyContext: TestableContext
 
@@ -254,7 +255,8 @@
                 mockAppHandleEducationController,
                 mockCaptionHandleRepository,
                 Optional.of(mockActivityOrientationChangeHandler),
-                mockTaskPositionerFactory
+                mockTaskPositionerFactory,
+                mockFocusTransitionObserver
         )
         desktopModeWindowDecorViewModel.setSplitScreenController(mockSplitScreenController)
         whenever(mockDisplayController.getDisplayLayout(any())).thenReturn(mockDisplayLayout)
@@ -455,24 +457,13 @@
 
         onClickListenerCaptor.value.onClick(view)
 
-        val transactionCaptor = argumentCaptor<WindowContainerTransaction>()
-        verify(mockFreeformTaskTransitionStarter)
-            .startMinimizedModeTransition(transactionCaptor.capture())
-        val wct = transactionCaptor.firstValue
-
-        verify(mockTasksLimiter).addPendingMinimizeChange(
-                anyOrNull(), eq(DEFAULT_DISPLAY), eq(decor.mTaskInfo.taskId))
-
-        assertEquals(1, wct.getHierarchyOps().size)
-        assertEquals(HierarchyOp.HIERARCHY_OP_TYPE_REORDER, wct.getHierarchyOps().get(0).getType())
-        assertFalse(wct.getHierarchyOps().get(0).getToTop())
-        assertEquals(decor.mTaskInfo.token.asBinder(), wct.getHierarchyOps().get(0).getContainer())
+        verify(mockDesktopTasksController).minimizeTask(decor.mTaskInfo)
     }
 
     @Test
     @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODALS_POLICY)
     fun testDecorationIsCreatedForTopTranslucentActivitiesWithStyleFloating() {
-        val task = createTask(windowingMode = WINDOWING_MODE_FULLSCREEN, focused = true).apply {
+        val task = createTask(windowingMode = WINDOWING_MODE_FULLSCREEN).apply {
             isTopActivityTransparent = true
             isTopActivityStyleFloating = true
             numActivities = 1
@@ -487,7 +478,7 @@
     @Test
     @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODALS_POLICY)
     fun testDecorationIsNotCreatedForTopTranslucentActivitiesWithoutStyleFloating() {
-        val task = createTask(windowingMode = WINDOWING_MODE_FULLSCREEN, focused = true).apply {
+        val task = createTask(windowingMode = WINDOWING_MODE_FULLSCREEN).apply {
             isTopActivityTransparent = true
             isTopActivityStyleFloating = false
             numActivities = 1
@@ -500,7 +491,7 @@
     @Test
     @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODALS_POLICY)
     fun testDecorationIsNotCreatedForSystemUIActivities() {
-        val task = createTask(windowingMode = WINDOWING_MODE_FULLSCREEN, focused = true)
+        val task = createTask(windowingMode = WINDOWING_MODE_FULLSCREEN)
 
         // Set task as systemUI package
         val systemUIPackageName = context.resources.getString(
@@ -573,7 +564,7 @@
         // Simulate default enforce device restrictions system property
         whenever(DesktopModeStatus.enforceDeviceRestrictions()).thenReturn(true)
 
-        val task = createTask(windowingMode = WINDOWING_MODE_FULLSCREEN, focused = true)
+        val task = createTask(windowingMode = WINDOWING_MODE_FULLSCREEN)
         // Simulate device that doesn't support desktop mode
         doReturn(false).`when` { DesktopModeStatus.isDesktopModeSupported(any()) }
 
@@ -589,7 +580,7 @@
         // Simulate device that doesn't support desktop mode
         doReturn(false).`when` { DesktopModeStatus.isDesktopModeSupported(any()) }
 
-        val task = createTask(windowingMode = WINDOWING_MODE_FULLSCREEN, focused = true)
+        val task = createTask(windowingMode = WINDOWING_MODE_FULLSCREEN)
         setUpMockDecorationsForTasks(task)
 
         onTaskOpening(task)
@@ -602,7 +593,7 @@
         // Simulate default enforce device restrictions system property
         whenever(DesktopModeStatus.enforceDeviceRestrictions()).thenReturn(true)
 
-        val task = createTask(windowingMode = WINDOWING_MODE_FULLSCREEN, focused = true)
+        val task = createTask(windowingMode = WINDOWING_MODE_FULLSCREEN)
         doReturn(true).`when` { DesktopModeStatus.isDesktopModeSupported(any()) }
         setUpMockDecorationsForTasks(task)
 
@@ -1045,7 +1036,7 @@
 
     @Test
     fun testOnDisplayRotation_tasksOutOfValidArea_taskBoundsUpdated() {
-        val task = createTask(focused = true, windowingMode = WINDOWING_MODE_FREEFORM)
+        val task = createTask(windowingMode = WINDOWING_MODE_FREEFORM)
         val secondTask =
             createTask(displayId = task.displayId, windowingMode = WINDOWING_MODE_FREEFORM)
         val thirdTask =
@@ -1073,7 +1064,7 @@
 
     @Test
     fun testOnDisplayRotation_taskInValidArea_taskBoundsNotUpdated() {
-        val task = createTask(focused = true, windowingMode = WINDOWING_MODE_FREEFORM)
+        val task = createTask(windowingMode = WINDOWING_MODE_FREEFORM)
         val secondTask =
             createTask(displayId = task.displayId, windowingMode = WINDOWING_MODE_FREEFORM)
         val thirdTask =
@@ -1100,7 +1091,7 @@
 
     @Test
     fun testOnDisplayRotation_sameOrientationRotation_taskBoundsNotUpdated() {
-        val task = createTask(focused = true, windowingMode = WINDOWING_MODE_FREEFORM)
+        val task = createTask(windowingMode = WINDOWING_MODE_FREEFORM)
         val secondTask =
             createTask(displayId = task.displayId, windowingMode = WINDOWING_MODE_FREEFORM)
         val thirdTask =
@@ -1124,7 +1115,7 @@
 
     @Test
     fun testOnDisplayRotation_differentDisplayId_taskBoundsNotUpdated() {
-        val task = createTask(focused = true, windowingMode = WINDOWING_MODE_FREEFORM)
+        val task = createTask(windowingMode = WINDOWING_MODE_FREEFORM)
         val secondTask = createTask(displayId = -2, windowingMode = WINDOWING_MODE_FREEFORM)
         val thirdTask = createTask(displayId = -3, windowingMode = WINDOWING_MODE_FREEFORM)
 
@@ -1149,7 +1140,7 @@
 
     @Test
     fun testOnDisplayRotation_nonFreeformTask_taskBoundsNotUpdated() {
-        val task = createTask(focused = true, windowingMode = WINDOWING_MODE_FREEFORM)
+        val task = createTask(windowingMode = WINDOWING_MODE_FREEFORM)
         val secondTask = createTask(displayId = -2, windowingMode = WINDOWING_MODE_FULLSCREEN)
         val thirdTask = createTask(displayId = -3, windowingMode = WINDOWING_MODE_PINNED)
 
@@ -1322,7 +1313,6 @@
             displayId: Int = DEFAULT_DISPLAY,
             @WindowingMode windowingMode: Int,
             activityType: Int = ACTIVITY_TYPE_STANDARD,
-            focused: Boolean = true,
             activityInfo: ActivityInfo = ActivityInfo(),
             requestingImmersive: Boolean = false
     ): RunningTaskInfo {
@@ -1333,7 +1323,6 @@
                 .setActivityType(activityType)
                 .build().apply {
                     topActivityInfo = activityInfo
-                    isFocused = focused
                     isResizeable = true
                     requestedVisibleTypes = if (requestingImmersive) {
                         statusBars().inv()
@@ -1351,7 +1340,6 @@
                 any(), any(), any(), any(), any(), any(), any())
         ).thenReturn(decoration)
         decoration.mTaskInfo = task
-        whenever(decoration.isFocused).thenReturn(task.isFocused)
         whenever(decoration.user).thenReturn(mockUserHandle)
         if (task.windowingMode == WINDOWING_MODE_MULTI_WINDOW) {
             whenever(mockSplitScreenController.isTaskInSplitScreen(task.taskId))
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorationTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorationTests.java
index 35be80e..1d11d2e 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorationTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorationTests.java
@@ -279,7 +279,7 @@
         final DesktopModeWindowDecoration spyWindowDecor =
                 spy(createWindowDecoration(taskInfo));
 
-        spyWindowDecor.relayout(taskInfo);
+        spyWindowDecor.relayout(taskInfo, false /* hasGlobalFocus */);
 
         // Menus should close if open before the task being invisible causes relayout to return.
         verify(spyWindowDecor).closeHandleMenu();
@@ -298,7 +298,8 @@
                 /* isStatusBarVisible */ true,
                 /* isKeyguardVisibleAndOccluded */ false,
                 /* inFullImmersiveMode */ false,
-                new InsetsState());
+                new InsetsState(),
+                /* hasGlobalFocus= */ true);
 
         assertThat(relayoutParams.mShadowRadiusId).isNotEqualTo(Resources.ID_NULL);
     }
@@ -318,7 +319,8 @@
                 /* isStatusBarVisible */ true,
                 /* isKeyguardVisibleAndOccluded */ false,
                 /* inFullImmersiveMode */ false,
-                new InsetsState());
+                new InsetsState(),
+                /* hasGlobalFocus= */ true);
 
         assertThat(relayoutParams.mCornerRadius).isGreaterThan(0);
     }
@@ -343,7 +345,8 @@
                 /* isStatusBarVisible */ true,
                 /* isKeyguardVisibleAndOccluded */ false,
                 /* inFullImmersiveMode */ false,
-                new InsetsState());
+                new InsetsState(),
+                /* hasGlobalFocus= */ true);
 
         assertThat(relayoutParams.mWindowDecorConfig.densityDpi).isEqualTo(customTaskDensity);
     }
@@ -369,7 +372,8 @@
                 /* isStatusBarVisible */ true,
                 /* isKeyguardVisibleAndOccluded */ false,
                 /* inFullImmersiveMode */ false,
-                new InsetsState());
+                new InsetsState(),
+                /* hasGlobalFocus= */ true);
 
         assertThat(relayoutParams.mWindowDecorConfig.densityDpi).isEqualTo(systemDensity);
     }
@@ -391,7 +395,8 @@
                 /* isStatusBarVisible */ true,
                 /* isKeyguardVisibleAndOccluded */ false,
                 /* inFullImmersiveMode */ false,
-                new InsetsState());
+                new InsetsState(),
+                /* hasGlobalFocus= */ true);
 
         assertThat(relayoutParams.hasInputFeatureSpy()).isTrue();
     }
@@ -412,7 +417,8 @@
                 /* isStatusBarVisible */ true,
                 /* isKeyguardVisibleAndOccluded */ false,
                 /* inFullImmersiveMode */ false,
-                new InsetsState());
+                new InsetsState(),
+                /* hasGlobalFocus= */ true);
 
         assertThat(relayoutParams.hasInputFeatureSpy()).isFalse();
     }
@@ -432,7 +438,8 @@
                 /* isStatusBarVisible */ true,
                 /* isKeyguardVisibleAndOccluded */ false,
                 /* inFullImmersiveMode */ false,
-                new InsetsState());
+                new InsetsState(),
+                /* hasGlobalFocus= */ true);
 
         assertThat(relayoutParams.hasInputFeatureSpy()).isFalse();
     }
@@ -452,7 +459,8 @@
                 /* isStatusBarVisible */ true,
                 /* isKeyguardVisibleAndOccluded */ false,
                 /* inFullImmersiveMode */ false,
-                new InsetsState());
+                new InsetsState(),
+                /* hasGlobalFocus= */ true);
 
         assertThat(hasNoInputChannelFeature(relayoutParams)).isFalse();
     }
@@ -473,7 +481,8 @@
                 /* isStatusBarVisible */ true,
                 /* isKeyguardVisibleAndOccluded */ false,
                 /* inFullImmersiveMode */ false,
-                new InsetsState());
+                new InsetsState(),
+                /* hasGlobalFocus= */ true);
 
         assertThat(hasNoInputChannelFeature(relayoutParams)).isTrue();
     }
@@ -494,7 +503,8 @@
                 /* isStatusBarVisible */ true,
                 /* isKeyguardVisibleAndOccluded */ false,
                 /* inFullImmersiveMode */ false,
-                new InsetsState());
+                new InsetsState(),
+                /* hasGlobalFocus= */ true);
 
         assertThat(hasNoInputChannelFeature(relayoutParams)).isTrue();
     }
@@ -516,7 +526,8 @@
                 /* isStatusBarVisible */ true,
                 /* isKeyguardVisibleAndOccluded */ false,
                 /* inFullImmersiveMode */ false,
-                new InsetsState());
+                new InsetsState(),
+                /* hasGlobalFocus= */ true);
 
         assertThat((relayoutParams.mInsetSourceFlags & FLAG_FORCE_CONSUMING) != 0).isTrue();
     }
@@ -539,7 +550,8 @@
                 /* isStatusBarVisible */ true,
                 /* isKeyguardVisibleAndOccluded */ false,
                 /* inFullImmersiveMode */ false,
-                new InsetsState());
+                new InsetsState(),
+                /* hasGlobalFocus= */ true);
 
         assertThat((relayoutParams.mInsetSourceFlags & FLAG_FORCE_CONSUMING) == 0).isTrue();
     }
@@ -560,7 +572,8 @@
                 /* isStatusBarVisible */ true,
                 /* isKeyguardVisibleAndOccluded */ false,
                 /* inFullImmersiveMode */ false,
-                new InsetsState());
+                new InsetsState(),
+                /* hasGlobalFocus= */ true);
 
         assertThat(
                 (relayoutParams.mInsetSourceFlags & FLAG_FORCE_CONSUMING_OPAQUE_CAPTION_BAR) != 0)
@@ -583,7 +596,8 @@
                 /* isStatusBarVisible */ true,
                 /* isKeyguardVisibleAndOccluded */ false,
                 /* inFullImmersiveMode */ false,
-                new InsetsState());
+                new InsetsState(),
+                /* hasGlobalFocus= */ true);
 
         assertThat(
                 (relayoutParams.mInsetSourceFlags & FLAG_FORCE_CONSUMING_OPAQUE_CAPTION_BAR) == 0)
@@ -612,7 +626,8 @@
                 /* isStatusBarVisible */ true,
                 /* isKeyguardVisibleAndOccluded */ false,
                 /* inFullImmersiveMode */ true,
-                insetsState);
+                insetsState,
+                /* hasGlobalFocus= */ true);
 
         // Takes status bar inset as padding, ignores caption bar inset.
         assertThat(relayoutParams.mCaptionTopPadding).isEqualTo(50);
@@ -634,7 +649,8 @@
                 /* isStatusBarVisible */ true,
                 /* isKeyguardVisibleAndOccluded */ false,
                 /* inFullImmersiveMode */ true,
-                new InsetsState());
+                new InsetsState(),
+                /* hasGlobalFocus= */ true);
 
         assertThat(relayoutParams.mIsInsetSource).isFalse();
     }
@@ -655,7 +671,8 @@
                 /* isStatusBarVisible */ false,
                 /* isKeyguardVisibleAndOccluded */ false,
                 /* inFullImmersiveMode */ false,
-                new InsetsState());
+                new InsetsState(),
+                /* hasGlobalFocus= */ true);
 
         // Header is always shown because it's assumed the status bar is always visible.
         assertThat(relayoutParams.mIsCaptionVisible).isTrue();
@@ -676,7 +693,8 @@
                 /* isStatusBarVisible */ true,
                 /* isKeyguardVisibleAndOccluded */ false,
                 /* inFullImmersiveMode */ false,
-                new InsetsState());
+                new InsetsState(),
+                /* hasGlobalFocus= */ true);
 
         assertThat(relayoutParams.mIsCaptionVisible).isTrue();
     }
@@ -696,7 +714,8 @@
                 /* isStatusBarVisible */ false,
                 /* isKeyguardVisibleAndOccluded */ false,
                 /* inFullImmersiveMode */ false,
-                new InsetsState());
+                new InsetsState(),
+                /* hasGlobalFocus= */ true);
 
         assertThat(relayoutParams.mIsCaptionVisible).isFalse();
     }
@@ -716,7 +735,8 @@
                 /* isStatusBarVisible */ true,
                 /* isKeyguardVisibleAndOccluded */ true,
                 /* inFullImmersiveMode */ false,
-                new InsetsState());
+                new InsetsState(),
+                /* hasGlobalFocus= */ true);
 
         assertThat(relayoutParams.mIsCaptionVisible).isFalse();
     }
@@ -737,7 +757,8 @@
                 /* isStatusBarVisible */ true,
                 /* isKeyguardVisibleAndOccluded */ false,
                 /* inFullImmersiveMode */ true,
-                new InsetsState());
+                new InsetsState(),
+                /* hasGlobalFocus= */ true);
 
         assertThat(relayoutParams.mIsCaptionVisible).isTrue();
 
@@ -750,7 +771,8 @@
                 /* isStatusBarVisible */ false,
                 /* isKeyguardVisibleAndOccluded */ false,
                 /* inFullImmersiveMode */ true,
-                new InsetsState());
+                new InsetsState(),
+                /* hasGlobalFocus= */ true);
 
         assertThat(relayoutParams.mIsCaptionVisible).isFalse();
     }
@@ -771,7 +793,8 @@
                 /* isStatusBarVisible */ true,
                 /* isKeyguardVisibleAndOccluded */ true,
                 /* inFullImmersiveMode */ true,
-                new InsetsState());
+                new InsetsState(),
+                /* hasGlobalFocus= */ true);
 
         assertThat(relayoutParams.mIsCaptionVisible).isFalse();
     }
@@ -782,7 +805,7 @@
         final DesktopModeWindowDecoration spyWindowDecor = spy(createWindowDecoration(taskInfo));
         taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
 
-        spyWindowDecor.relayout(taskInfo);
+        spyWindowDecor.relayout(taskInfo, true /* hasGlobalFocus */);
 
         verify(mMockTransaction).apply();
         verify(mMockRootSurfaceControl, never()).applyTransactionOnDraw(any());
@@ -797,7 +820,7 @@
         // Make non-resizable to avoid dealing with input-permissions (MONITOR_INPUT)
         taskInfo.isResizeable = false;
 
-        spyWindowDecor.relayout(taskInfo);
+        spyWindowDecor.relayout(taskInfo, true /* hasGlobalFocus */);
 
         verify(mMockTransaction, never()).apply();
         verify(mMockRootSurfaceControl).applyTransactionOnDraw(mMockTransaction);
@@ -809,7 +832,7 @@
         final DesktopModeWindowDecoration spyWindowDecor = spy(createWindowDecoration(taskInfo));
         taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
 
-        spyWindowDecor.relayout(taskInfo);
+        spyWindowDecor.relayout(taskInfo, true /* hasGlobalFocus */);
 
         verify(mMockSurfaceControlViewHostFactory, never()).create(any(), any(), any());
     }
@@ -821,7 +844,7 @@
         taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
 
         ArgumentCaptor<Runnable> runnableArgument = ArgumentCaptor.forClass(Runnable.class);
-        spyWindowDecor.relayout(taskInfo);
+        spyWindowDecor.relayout(taskInfo, true /* hasGlobalFocus */);
 
         // Once for view host, the other for the AppHandle input layer.
         verify(mMockHandler, times(2)).post(runnableArgument.capture());
@@ -838,7 +861,7 @@
         // Make non-resizable to avoid dealing with input-permissions (MONITOR_INPUT)
         taskInfo.isResizeable = false;
 
-        spyWindowDecor.relayout(taskInfo);
+        spyWindowDecor.relayout(taskInfo, true /* hasGlobalFocus */);
 
         verify(mMockSurfaceControlViewHostFactory).create(any(), any(), any());
         verify(mMockHandler, never()).post(any());
@@ -850,11 +873,11 @@
         final DesktopModeWindowDecoration spyWindowDecor = spy(createWindowDecoration(taskInfo));
         taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
         ArgumentCaptor<Runnable> runnableArgument = ArgumentCaptor.forClass(Runnable.class);
-        spyWindowDecor.relayout(taskInfo);
+        spyWindowDecor.relayout(taskInfo, true /* hasGlobalFocus */);
         // Once for view host, the other for the AppHandle input layer.
         verify(mMockHandler, times(2)).post(runnableArgument.capture());
 
-        spyWindowDecor.relayout(taskInfo);
+        spyWindowDecor.relayout(taskInfo, true /* hasGlobalFocus */);
 
         verify(mMockHandler).removeCallbacks(runnableArgument.getValue());
     }
@@ -865,7 +888,7 @@
         final DesktopModeWindowDecoration spyWindowDecor = spy(createWindowDecoration(taskInfo));
         taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
         ArgumentCaptor<Runnable> runnableArgument = ArgumentCaptor.forClass(Runnable.class);
-        spyWindowDecor.relayout(taskInfo);
+        spyWindowDecor.relayout(taskInfo, true /* hasGlobalFocus */);
         // Once for view host, the other for the AppHandle input layer.
         verify(mMockHandler, times(2)).post(runnableArgument.capture());
 
@@ -998,7 +1021,7 @@
         runnableArgument.getValue().run();
 
         // Relayout decor with same captured link
-        decor.relayout(taskInfo);
+        decor.relayout(taskInfo, true /* hasGlobalFocus */);
 
         // Verify handle menu's browser link not set to captured link since link is expired
         createHandleMenu(decor);
@@ -1147,7 +1170,7 @@
         final DesktopModeWindowDecoration spyWindowDecor = spy(createWindowDecoration(taskInfo));
         taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
 
-        spyWindowDecor.relayout(taskInfo);
+        spyWindowDecor.relayout(taskInfo, true /* hasGlobalFocus */);
 
         verify(mMockCaptionHandleRepository, never()).notifyCaptionChanged(any());
     }
@@ -1164,7 +1187,7 @@
         ArgumentCaptor<CaptionState> captionStateArgumentCaptor = ArgumentCaptor.forClass(
                 CaptionState.class);
 
-        spyWindowDecor.relayout(taskInfo);
+        spyWindowDecor.relayout(taskInfo, true /* hasGlobalFocus */);
 
         verify(mMockCaptionHandleRepository, atLeastOnce()).notifyCaptionChanged(
                 captionStateArgumentCaptor.capture());
@@ -1191,7 +1214,7 @@
         ArgumentCaptor<CaptionState> captionStateArgumentCaptor = ArgumentCaptor.forClass(
                 CaptionState.class);
 
-        spyWindowDecor.relayout(taskInfo);
+        spyWindowDecor.relayout(taskInfo, true /* hasGlobalFocus */);
         verify(mMockAppHeaderViewHolder, atLeastOnce()).runOnAppChipGlobalLayout(
                 runnableArgumentCaptor.capture());
         runnableArgumentCaptor.getValue().invoke();
@@ -1214,7 +1237,7 @@
         ArgumentCaptor<CaptionState> captionStateArgumentCaptor = ArgumentCaptor.forClass(
                 CaptionState.class);
 
-        spyWindowDecor.relayout(taskInfo);
+        spyWindowDecor.relayout(taskInfo, false /* hasGlobalFocus */);
 
         verify(mMockCaptionHandleRepository, atLeastOnce()).notifyCaptionChanged(
                 captionStateArgumentCaptor.capture());
@@ -1234,7 +1257,7 @@
         ArgumentCaptor<CaptionState> captionStateArgumentCaptor = ArgumentCaptor.forClass(
                 CaptionState.class);
 
-        spyWindowDecor.relayout(taskInfo);
+        spyWindowDecor.relayout(taskInfo, true /* hasGlobalFocus */);
         createHandleMenu(spyWindowDecor);
 
         verify(mMockCaptionHandleRepository, atLeastOnce()).notifyCaptionChanged(
@@ -1259,7 +1282,7 @@
         ArgumentCaptor<CaptionState> captionStateArgumentCaptor = ArgumentCaptor.forClass(
                 CaptionState.class);
 
-        spyWindowDecor.relayout(taskInfo);
+        spyWindowDecor.relayout(taskInfo, true /* hasGlobalFocus */);
         createHandleMenu(spyWindowDecor);
         spyWindowDecor.closeHandleMenu();
 
@@ -1356,7 +1379,7 @@
         windowDecor.setOpenInBrowserClickListener(mMockOpenInBrowserClickListener);
         windowDecor.mDecorWindowContext = mContext;
         if (relayout) {
-            windowDecor.relayout(taskInfo);
+            windowDecor.relayout(taskInfo, true /* hasGlobalFocus */);
         }
         return windowDecor;
     }
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/FluidResizeTaskPositionerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/FluidResizeTaskPositionerTest.kt
index 7543fed..ca1f9ab 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/FluidResizeTaskPositionerTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/FluidResizeTaskPositionerTest.kt
@@ -624,7 +624,7 @@
 
     @Test
     fun testDragResize_resize_resizingTaskReorderedToTopWhenNotFocused() {
-        mockWindowDecoration.mTaskInfo.isFocused = false
+        mockWindowDecoration.mHasGlobalFocus = false
         taskPositioner.onDragPositioningStart(
                 CTRL_TYPE_RIGHT, // Resize right
                 STARTING_BOUNDS.left.toFloat(),
@@ -640,7 +640,7 @@
 
     @Test
     fun testDragResize_resize_resizingTaskNotReorderedToTopWhenFocused() {
-        mockWindowDecoration.mTaskInfo.isFocused = true
+        mockWindowDecoration.mHasGlobalFocus = true
         taskPositioner.onDragPositioningStart(
                 CTRL_TYPE_RIGHT, // Resize right
                 STARTING_BOUNDS.left.toFloat(),
@@ -656,7 +656,7 @@
 
     @Test
     fun testDragResize_drag_draggedTaskNotReorderedToTop() {
-        mockWindowDecoration.mTaskInfo.isFocused = false
+        mockWindowDecoration.mHasGlobalFocus = false
         taskPositioner.onDragPositioningStart(
                 CTRL_TYPE_UNDEFINED, // drag
                 STARTING_BOUNDS.left.toFloat(),
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/VeiledResizeTaskPositionerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/VeiledResizeTaskPositionerTest.kt
index 1273ee8..1dfbd67 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/VeiledResizeTaskPositionerTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/VeiledResizeTaskPositionerTest.kt
@@ -323,7 +323,7 @@
 
     @Test
     fun testDragResize_resize_resizingTaskReorderedToTopWhenNotFocused() = runOnUiThread {
-        mockDesktopWindowDecoration.mTaskInfo.isFocused = false
+        mockDesktopWindowDecoration.mHasGlobalFocus = false
         taskPositioner.onDragPositioningStart(
                 CTRL_TYPE_RIGHT, // Resize right
                 STARTING_BOUNDS.left.toFloat(),
@@ -339,7 +339,7 @@
 
     @Test
     fun testDragResize_resize_resizingTaskNotReorderedToTopWhenFocused() = runOnUiThread {
-        mockDesktopWindowDecoration.mTaskInfo.isFocused = true
+        mockDesktopWindowDecoration.mHasGlobalFocus = true
         taskPositioner.onDragPositioningStart(
                 CTRL_TYPE_RIGHT, // Resize right
                 STARTING_BOUNDS.left.toFloat(),
@@ -355,7 +355,7 @@
 
     @Test
     fun testDragResize_drag_draggedTaskNotReorderedToTop() = runOnUiThread {
-        mockDesktopWindowDecoration.mTaskInfo.isFocused = false
+        mockDesktopWindowDecoration.mHasGlobalFocus = false
         taskPositioner.onDragPositioningStart(
                 CTRL_TYPE_UNDEFINED, // drag
                 STARTING_BOUNDS.left.toFloat(),
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 54dd15ba..bb41e9c 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
@@ -203,13 +203,12 @@
                 .setPositionInParent(TASK_POSITION_IN_PARENT.x, TASK_POSITION_IN_PARENT.y)
                 .setVisible(false)
                 .build();
-        taskInfo.isFocused = false;
         // Density is 2. Shadow radius is 10px. Caption height is 64px.
         taskInfo.configuration.densityDpi = DisplayMetrics.DENSITY_DEFAULT * 2;
 
         final TestWindowDecoration windowDecor = createWindowDecoration(taskInfo);
 
-        windowDecor.relayout(taskInfo);
+        windowDecor.relayout(taskInfo, false /* hasGlobalFocus */);
 
         verify(decorContainerSurfaceBuilder, never()).build();
         verify(taskBackgroundSurfaceBuilder, never()).build();
@@ -243,13 +242,12 @@
                 .setVisible(true)
                 .setWindowingMode(WINDOWING_MODE_FREEFORM)
                 .build();
-        taskInfo.isFocused = true;
         // Density is 2. Shadow radius is 10px. Caption height is 64px.
         taskInfo.configuration.densityDpi = DisplayMetrics.DENSITY_DEFAULT * 2;
         final TestWindowDecoration windowDecor = createWindowDecoration(taskInfo);
         mRelayoutParams.mIsCaptionVisible = true;
 
-        windowDecor.relayout(taskInfo);
+        windowDecor.relayout(taskInfo, true /* hasGlobalFocus */);
 
         verify(decorContainerSurfaceBuilder).setParent(mMockTaskSurface);
         verify(decorContainerSurfaceBuilder).setContainerLayer();
@@ -316,14 +314,13 @@
                 .setPositionInParent(TASK_POSITION_IN_PARENT.x, TASK_POSITION_IN_PARENT.y)
                 .setVisible(true)
                 .build();
-        taskInfo.isFocused = true;
         // Density is 2. Shadow radius is 10px. Caption height is 64px.
         taskInfo.configuration.densityDpi = DisplayMetrics.DENSITY_DEFAULT * 2;
 
         final TestWindowDecoration windowDecor = createWindowDecoration(taskInfo);
         mRelayoutParams.mIsCaptionVisible = true;
 
-        windowDecor.relayout(taskInfo);
+        windowDecor.relayout(taskInfo, true /* hasGlobalFocus */);
 
         verify(mMockSurfaceControlViewHost, never()).release();
         verify(t, never()).apply();
@@ -333,7 +330,7 @@
         final SurfaceControl.Transaction t2 = mock(SurfaceControl.Transaction.class);
         mMockSurfaceControlTransactions.add(t2);
         taskInfo.isVisible = false;
-        windowDecor.relayout(taskInfo);
+        windowDecor.relayout(taskInfo, false /* hasGlobalFocus */);
 
         final InOrder releaseOrder = inOrder(t2, mMockSurfaceControlViewHost);
         releaseOrder.verify(mMockSurfaceControlViewHost).release();
@@ -361,7 +358,7 @@
                 .build();
 
         final TestWindowDecoration windowDecor = createWindowDecoration(taskInfo);
-        windowDecor.relayout(taskInfo);
+        windowDecor.relayout(taskInfo, true /* hasGlobalFocus */);
 
         // It shouldn't show the window decoration when it can't obtain the display instance.
         assertThat(mRelayoutResult.mRootView).isNull();
@@ -417,10 +414,9 @@
                 .setPositionInParent(TASK_POSITION_IN_PARENT.x, TASK_POSITION_IN_PARENT.y)
                 .setVisible(true)
                 .build();
-        taskInfo.isFocused = true;
         taskInfo.configuration.densityDpi = DisplayMetrics.DENSITY_DEFAULT * 2;
         final TestWindowDecoration windowDecor = createWindowDecoration(taskInfo);
-        windowDecor.relayout(taskInfo);
+        windowDecor.relayout(taskInfo, true /* hasGlobalFocus */);
 
         final SurfaceControl additionalWindowSurface = mock(SurfaceControl.class);
         final SurfaceControl.Builder additionalWindowSurfaceBuilder =
@@ -470,11 +466,10 @@
                 .setPositionInParent(TASK_POSITION_IN_PARENT.x, TASK_POSITION_IN_PARENT.y)
                 .setVisible(true)
                 .build();
-        taskInfo.isFocused = true;
         taskInfo.configuration.densityDpi = DisplayMetrics.DENSITY_DEFAULT * 2;
         final TestWindowDecoration windowDecor = createWindowDecoration(taskInfo);
 
-        windowDecor.relayout(taskInfo);
+        windowDecor.relayout(taskInfo, true /* hasGlobalFocus */);
 
         verify(captionContainerSurfaceBuilder).setParent(decorContainerSurface);
         verify(captionContainerSurfaceBuilder).setContainerLayer();
@@ -510,11 +505,11 @@
                 .setPositionInParent(TASK_POSITION_IN_PARENT.x, TASK_POSITION_IN_PARENT.y)
                 .setVisible(true)
                 .build();
-        taskInfo.isFocused = true;
         taskInfo.configuration.densityDpi = DisplayMetrics.DENSITY_DEFAULT * 2;
         final TestWindowDecoration windowDecor = createWindowDecoration(taskInfo);
 
-        windowDecor.relayout(taskInfo, true /* applyStartTransactionOnDraw */);
+        windowDecor.relayout(taskInfo, true /* applyStartTransactionOnDraw */,
+                true /* hasGlobalFocus */);
 
         verify(mMockRootSurfaceControl).applyTransactionOnDraw(mMockSurfaceControlStartT);
     }
@@ -549,10 +544,9 @@
                 .setVisible(true)
                 .setWindowingMode(WINDOWING_MODE_FREEFORM)
                 .build();
-        taskInfo.isFocused = true;
         final TestWindowDecoration windowDecor = createWindowDecoration(taskInfo);
 
-        windowDecor.relayout(taskInfo);
+        windowDecor.relayout(taskInfo, true /* hasGlobalFocus */);
 
         verify(mMockSurfaceControlStartT).setColor(mMockTaskSurface, new float[]{1.f, 1.f, 0.f});
 
@@ -575,7 +569,7 @@
         final TestWindowDecoration windowDecor = createWindowDecoration(taskInfo);
 
         mRelayoutParams.mIsCaptionVisible = true;
-        windowDecor.relayout(taskInfo);
+        windowDecor.relayout(taskInfo, true /* hasGlobalFocus */);
 
         verify(mMockWindowContainerTransaction).addInsetsSource(eq(taskInfo.token), any(),
                 eq(0) /* index */, eq(captionBar()), any(), any(), anyInt());
@@ -611,10 +605,9 @@
                 .setVisible(true)
                 .setWindowingMode(WINDOWING_MODE_FULLSCREEN)
                 .build();
-        taskInfo.isFocused = true;
         final TestWindowDecoration windowDecor = createWindowDecoration(taskInfo);
 
-        windowDecor.relayout(taskInfo);
+        windowDecor.relayout(taskInfo, true /* hasGlobalFocus */);
 
         verify(mMockSurfaceControlStartT).unsetColor(mMockTaskSurface);
 
@@ -635,7 +628,7 @@
         // Hidden from the beginning, so no insets were ever added.
         final TestWindowDecoration windowDecor = createWindowDecoration(taskInfo);
         mRelayoutParams.mIsCaptionVisible = false;
-        windowDecor.relayout(taskInfo);
+        windowDecor.relayout(taskInfo, true /* hasGlobalFocus */);
 
         // Never added.
         verify(mMockWindowContainerTransaction, never()).addInsetsSource(eq(taskInfo.token), any(),
@@ -663,7 +656,7 @@
         final TestWindowDecoration windowDecor = createWindowDecoration(taskInfo);
 
         mRelayoutParams.mIsInsetSource = false;
-        windowDecor.relayout(taskInfo);
+        windowDecor.relayout(taskInfo, true /* hasGlobalFocus */);
 
         // Never added.
         verify(mMockWindowContainerTransaction, never()).addInsetsSource(eq(taskInfo.token), any(),
@@ -687,11 +680,11 @@
 
         mRelayoutParams.mIsCaptionVisible = true;
         mRelayoutParams.mIsInsetSource = true;
-        windowDecor.relayout(taskInfo);
+        windowDecor.relayout(taskInfo, true /* hasGlobalFocus */);
 
         mRelayoutParams.mIsCaptionVisible = true;
         mRelayoutParams.mIsInsetSource = false;
-        windowDecor.relayout(taskInfo);
+        windowDecor.relayout(taskInfo, true /* hasGlobalFocus */);
 
         // Insets should be removed.
         verify(mMockWindowContainerTransaction).removeInsetsSource(eq(taskInfo.token), any(),
@@ -715,7 +708,7 @@
 
         // Relayout will add insets.
         mRelayoutParams.mIsCaptionVisible = true;
-        windowDecor.relayout(taskInfo);
+        windowDecor.relayout(taskInfo, true /* hasGlobalFocus */);
         verify(mMockWindowContainerTransaction).addInsetsSource(eq(taskInfo.token), any(),
                 eq(0) /* index */, eq(captionBar()), any(), any(), anyInt());
         verify(mMockWindowContainerTransaction).addInsetsSource(eq(taskInfo.token), any(),
@@ -768,10 +761,10 @@
         final ActivityManager.RunningTaskInfo firstTaskInfo =
                 builder.setToken(token).setBounds(new Rect(0, 0, 1000, 1000)).build();
         final TestWindowDecoration windowDecor = createWindowDecoration(firstTaskInfo);
-        windowDecor.relayout(firstTaskInfo);
+        windowDecor.relayout(firstTaskInfo, true /* hasGlobalFocus */);
         final ActivityManager.RunningTaskInfo secondTaskInfo =
                 builder.setToken(token).setBounds(new Rect(50, 50, 1000, 1000)).build();
-        windowDecor.relayout(secondTaskInfo);
+        windowDecor.relayout(secondTaskInfo, true /* hasGlobalFocus */);
 
         // Insets should be applied twice.
         verify(mMockWindowContainerTransaction, times(2)).addInsetsSource(eq(token), any(),
@@ -796,10 +789,10 @@
         final ActivityManager.RunningTaskInfo firstTaskInfo =
                 builder.setToken(token).setBounds(new Rect(0, 0, 1000, 1000)).build();
         final TestWindowDecoration windowDecor = createWindowDecoration(firstTaskInfo);
-        windowDecor.relayout(firstTaskInfo);
+        windowDecor.relayout(firstTaskInfo, true /* hasGlobalFocus */);
         final ActivityManager.RunningTaskInfo secondTaskInfo =
                 builder.setToken(token).setBounds(new Rect(0, 0, 1000, 1000)).build();
-        windowDecor.relayout(secondTaskInfo);
+        windowDecor.relayout(secondTaskInfo, true /* hasGlobalFocus */);
 
         // Insets should only need to be applied once.
         verify(mMockWindowContainerTransaction, times(1)).addInsetsSource(eq(token), any(),
@@ -824,7 +817,7 @@
         mRelayoutParams.mIsCaptionVisible = true;
         mRelayoutParams.mInsetSourceFlags =
                 FLAG_FORCE_CONSUMING | FLAG_FORCE_CONSUMING_OPAQUE_CAPTION_BAR;
-        windowDecor.relayout(taskInfo);
+        windowDecor.relayout(taskInfo, true /* hasGlobalFocus */);
 
         // Caption inset source should add params' flags.
         verify(mMockWindowContainerTransaction).addInsetsSource(eq(token), any(),
@@ -845,14 +838,13 @@
                 .setVisible(true)
                 .setWindowingMode(WINDOWING_MODE_FREEFORM)
                 .build();
-        taskInfo.isFocused = true;
         // Density is 2. Shadow radius is 10px. Caption height is 64px.
         taskInfo.configuration.densityDpi = DisplayMetrics.DENSITY_DEFAULT * 2;
         final TestWindowDecoration windowDecor = createWindowDecoration(taskInfo);
 
 
         mRelayoutParams.mSetTaskPositionAndCrop = false;
-        windowDecor.relayout(taskInfo);
+        windowDecor.relayout(taskInfo, true /* hasGlobalFocus */);
 
         verify(mMockSurfaceControlStartT, never()).setWindowCrop(
                 eq(mMockTaskSurface), anyInt(), anyInt());
@@ -875,13 +867,12 @@
                 .setVisible(true)
                 .setWindowingMode(WINDOWING_MODE_FREEFORM)
                 .build();
-        taskInfo.isFocused = true;
         // Density is 2. Shadow radius is 10px. Caption height is 64px.
         taskInfo.configuration.densityDpi = DisplayMetrics.DENSITY_DEFAULT * 2;
         final TestWindowDecoration windowDecor = createWindowDecoration(taskInfo);
 
         mRelayoutParams.mSetTaskPositionAndCrop = true;
-        windowDecor.relayout(taskInfo);
+        windowDecor.relayout(taskInfo, true /* hasGlobalFocus */);
 
         verify(mMockSurfaceControlStartT).setWindowCrop(
                 eq(mMockTaskSurface), anyInt(), anyInt());
@@ -932,12 +923,12 @@
         when(mMockDisplayController.getInsetsState(task.displayId))
                 .thenReturn(createInsetsState(statusBars(), true /* visible */));
         final TestWindowDecoration decor = spy(createWindowDecoration(task));
-        decor.relayout(task);
+        decor.relayout(task, true /* hasGlobalFocus */);
         assertTrue(decor.mIsStatusBarVisible);
 
         decor.onInsetsStateChanged(createInsetsState(statusBars(), false /* visible */));
 
-        verify(decor, times(2)).relayout(task);
+        verify(decor, times(2)).relayout(task, true /* hasGlobalFocus */);
     }
 
     @Test
@@ -947,11 +938,11 @@
         when(mMockDisplayController.getInsetsState(task.displayId))
                 .thenReturn(createInsetsState(statusBars(), true /* visible */));
         final TestWindowDecoration decor = spy(createWindowDecoration(task));
-        decor.relayout(task);
+        decor.relayout(task, true /* hasGlobalFocus */);
 
         decor.onInsetsStateChanged(createInsetsState(statusBars(), true /* visible */));
 
-        verify(decor, times(1)).relayout(task);
+        verify(decor, times(1)).relayout(task, true /* hasGlobalFocus */);
     }
 
     @Test
@@ -960,13 +951,13 @@
         when(mMockDisplayController.getInsetsState(task.displayId))
                 .thenReturn(createInsetsState(statusBars(), true /* visible */));
         final TestWindowDecoration decor = spy(createWindowDecoration(task));
-        decor.relayout(task);
+        decor.relayout(task, true /* hasGlobalFocus */);
         assertFalse(decor.mIsKeyguardVisibleAndOccluded);
 
         decor.onKeyguardStateChanged(true /* visible */, true /* occluding */);
 
         assertTrue(decor.mIsKeyguardVisibleAndOccluded);
-        verify(decor, times(2)).relayout(task);
+        verify(decor, times(2)).relayout(task, true /* hasGlobalFocus */);
     }
 
     @Test
@@ -975,19 +966,18 @@
         when(mMockDisplayController.getInsetsState(task.displayId))
                 .thenReturn(createInsetsState(statusBars(), true /* visible */));
         final TestWindowDecoration decor = spy(createWindowDecoration(task));
-        decor.relayout(task);
+        decor.relayout(task, true /* hasGlobalFocus */);
         assertFalse(decor.mIsKeyguardVisibleAndOccluded);
 
         decor.onKeyguardStateChanged(false /* visible */, true /* occluding */);
 
-        verify(decor, times(1)).relayout(task);
+        verify(decor, times(1)).relayout(task, true /* hasGlobalFocus */);
     }
 
     private ActivityManager.RunningTaskInfo createTaskInfo() {
         final ActivityManager.RunningTaskInfo taskInfo = new TestRunningTaskInfoBuilder()
                 .setVisible(true)
                 .build();
-        taskInfo.isFocused = true;
         return taskInfo;
     }
 
@@ -1055,8 +1045,8 @@
         }
 
         @Override
-        void relayout(ActivityManager.RunningTaskInfo taskInfo) {
-            relayout(taskInfo, false /* applyStartTransactionOnDraw */);
+        void relayout(ActivityManager.RunningTaskInfo taskInfo, boolean hasGlobalFocus) {
+            relayout(taskInfo, false /* applyStartTransactionOnDraw */, hasGlobalFocus);
         }
 
         @Override
@@ -1078,10 +1068,11 @@
         }
 
         void relayout(ActivityManager.RunningTaskInfo taskInfo,
-                boolean applyStartTransactionOnDraw) {
+                boolean applyStartTransactionOnDraw, boolean hasGlobalFocus) {
             mRelayoutParams.mRunningTaskInfo = taskInfo;
             mRelayoutParams.mApplyStartTransactionOnDraw = applyStartTransactionOnDraw;
             mRelayoutParams.mLayoutResId = R.layout.caption_layout;
+            mRelayoutParams.mHasGlobalFocus = hasGlobalFocus;
             relayout(mRelayoutParams, mMockSurfaceControlStartT, mMockSurfaceControlFinishT,
                     mMockWindowContainerTransaction, mMockView, mRelayoutResult);
         }
diff --git a/libs/androidfw/Idmap.cpp b/libs/androidfw/Idmap.cpp
index f066e46..3ecd82b 100644
--- a/libs/androidfw/Idmap.cpp
+++ b/libs/androidfw/Idmap.cpp
@@ -65,13 +65,7 @@
   uint32_t string_pool_index_offset;
 };
 
-struct Idmap_target_entry {
-  uint32_t target_id;
-  uint32_t overlay_id;
-};
-
 struct Idmap_target_entry_inline {
-  uint32_t target_id;
   uint32_t start_value_index;
   uint32_t value_count;
 };
@@ -81,10 +75,9 @@
   Res_value value;
 };
 
-struct Idmap_overlay_entry {
-  uint32_t overlay_id;
-  uint32_t target_id;
-};
+static constexpr uint32_t convert_dev_target_id(uint32_t dev_target_id) {
+  return (0x00FFFFFFU & dtohl(dev_target_id));
+}
 
 OverlayStringPool::OverlayStringPool(const LoadedIdmap* loaded_idmap)
     : data_header_(loaded_idmap->data_header_),
@@ -117,27 +110,29 @@
 }
 
 OverlayDynamicRefTable::OverlayDynamicRefTable(const Idmap_data_header* data_header,
-                                               const Idmap_overlay_entry* entries,
+                                               Idmap_overlay_entries entries,
                                                uint8_t target_assigned_package_id)
     : data_header_(data_header),
       entries_(entries),
-      target_assigned_package_id_(target_assigned_package_id) {}
+      target_assigned_package_id_(target_assigned_package_id) {
+}
 
 status_t OverlayDynamicRefTable::lookupResourceId(uint32_t* resId) const {
-  const Idmap_overlay_entry* first_entry = entries_;
-  const Idmap_overlay_entry* end_entry = entries_ + dtohl(data_header_->overlay_entry_count);
-  auto entry = std::lower_bound(first_entry, end_entry, *resId,
-                                [](const Idmap_overlay_entry& e1, const uint32_t overlay_id) {
-    return dtohl(e1.overlay_id) < overlay_id;
-  });
+  const auto count = dtohl(data_header_->overlay_entry_count);
+  const auto overlay_it_end = entries_.overlay_id + count;
+  const auto entry_it = std::lower_bound(entries_.overlay_id, overlay_it_end, *resId,
+                                         [](uint32_t dev_overlay_id, uint32_t overlay_id) {
+                                           return dtohl(dev_overlay_id) < overlay_id;
+                                         });
 
-  if (entry == end_entry || dtohl(entry->overlay_id) != *resId) {
+  if (entry_it == overlay_it_end || dtohl(*entry_it) != *resId) {
     // A mapping for the target resource id could not be found.
     return DynamicRefTable::lookupResourceId(resId);
   }
 
-  *resId = (0x00FFFFFFU & dtohl(entry->target_id))
-      | (((uint32_t) target_assigned_package_id_) << 24U);
+  const auto index = entry_it - entries_.overlay_id;
+  *resId = convert_dev_target_id(entries_.target_id[index]) |
+           (((uint32_t)target_assigned_package_id_) << 24U);
   return NO_ERROR;
 }
 
@@ -145,12 +140,10 @@
   return DynamicRefTable::lookupResourceId(resId);
 }
 
-IdmapResMap::IdmapResMap(const Idmap_data_header* data_header,
-                         const Idmap_target_entry* entries,
-                         const Idmap_target_entry_inline* inline_entries,
+IdmapResMap::IdmapResMap(const Idmap_data_header* data_header, Idmap_target_entries entries,
+                         Idmap_target_inline_entries inline_entries,
                          const Idmap_target_entry_inline_value* inline_entry_values,
-                         const ConfigDescription* configs,
-                         uint8_t target_assigned_package_id,
+                         const ConfigDescription* configs, uint8_t target_assigned_package_id,
                          const OverlayDynamicRefTable* overlay_ref_table)
     : data_header_(data_header),
       entries_(entries),
@@ -158,7 +151,8 @@
       inline_entry_values_(inline_entry_values),
       configurations_(configs),
       target_assigned_package_id_(target_assigned_package_id),
-      overlay_ref_table_(overlay_ref_table) { }
+      overlay_ref_table_(overlay_ref_table) {
+}
 
 IdmapResMap::Result IdmapResMap::Lookup(uint32_t target_res_id) const {
   if ((target_res_id >> 24U) != target_assigned_package_id_) {
@@ -171,15 +165,15 @@
   target_res_id &= 0x00FFFFFFU;
 
   // Check if the target resource is mapped to an overlay resource.
-  auto first_entry = entries_;
-  auto end_entry = entries_ + dtohl(data_header_->target_entry_count);
-  auto entry = std::lower_bound(first_entry, end_entry, target_res_id,
-                                [](const Idmap_target_entry& e, const uint32_t target_id) {
-    return (0x00FFFFFFU & dtohl(e.target_id)) < target_id;
-  });
+  const auto target_end = entries_.target_id + dtohl(data_header_->target_entry_count);
+  auto target_it = std::lower_bound(entries_.target_id, target_end, target_res_id,
+                                    [](uint32_t dev_target_id, uint32_t target_id) {
+                                      return convert_dev_target_id(dev_target_id) < target_id;
+                                    });
 
-  if (entry != end_entry && (0x00FFFFFFU & dtohl(entry->target_id)) == target_res_id) {
-    uint32_t overlay_resource_id = dtohl(entry->overlay_id);
+  if (target_it != target_end && convert_dev_target_id(*target_it) == target_res_id) {
+    const auto index = target_it - entries_.target_id;
+    uint32_t overlay_resource_id = dtohl(entries_.overlay_id[index]);
     // Lookup the resource without rewriting the overlay resource id back to the target resource id
     // being looked up.
     overlay_ref_table_->lookupResourceIdNoRewrite(&overlay_resource_id);
@@ -187,20 +181,22 @@
   }
 
   // Check if the target resources is mapped to an inline table entry.
-  auto first_inline_entry = inline_entries_;
-  auto end_inline_entry = inline_entries_ + dtohl(data_header_->target_inline_entry_count);
-  auto inline_entry = std::lower_bound(first_inline_entry, end_inline_entry, target_res_id,
-                                       [](const Idmap_target_entry_inline& e,
-                                          const uint32_t target_id) {
-    return (0x00FFFFFFU & dtohl(e.target_id)) < target_id;
-  });
+  const auto inline_entry_target_end =
+      inline_entries_.target_id + dtohl(data_header_->target_inline_entry_count);
+  const auto inline_entry_target_it =
+      std::lower_bound(inline_entries_.target_id, inline_entry_target_end, target_res_id,
+                       [](uint32_t dev_target_id, uint32_t target_id) {
+                         return convert_dev_target_id(dev_target_id) < target_id;
+                       });
 
-  if (inline_entry != end_inline_entry &&
-      (0x00FFFFFFU & dtohl(inline_entry->target_id)) == target_res_id) {
+  if (inline_entry_target_it != inline_entry_target_end &&
+      convert_dev_target_id(*inline_entry_target_it) == target_res_id) {
+    const auto index = inline_entry_target_it - inline_entries_.target_id;
     std::map<ConfigDescription, Res_value> values_map;
-    for (int i = 0; i < inline_entry->value_count; i++) {
-      const auto& value = inline_entry_values_[inline_entry->start_value_index + i];
-      const auto& config = configurations_[value.config_index];
+    const auto& inline_entry = inline_entries_.entry[index];
+    for (int i = 0; i < dtohl(inline_entry.value_count); i++) {
+      const auto& value = inline_entry_values_[dtohl(inline_entry.start_value_index) + i];
+      const auto& config = configurations_[dtohl(value.config_index)];
       values_map[config] = value.value;
     }
     return Result(std::move(values_map));
@@ -210,15 +206,15 @@
 
 namespace {
 template <typename T>
-const T* ReadType(const uint8_t** in_out_data_ptr, size_t* in_out_size, const std::string& label,
+const T* ReadType(const uint8_t** in_out_data_ptr, size_t* in_out_size, const char* label,
                   size_t count = 1) {
   if (!util::IsFourByteAligned(*in_out_data_ptr)) {
-    LOG(ERROR) << "Idmap " << label << " is not word aligned.";
+    LOG(ERROR) << "Idmap " << label << " in " << __func__ << " is not word aligned.";
     return {};
   }
   if ((*in_out_size / sizeof(T)) < count) {
-    LOG(ERROR) << "Idmap too small for the number of " << label << " entries ("
-               << count << ").";
+    LOG(ERROR) << "Idmap too small for the number of " << label << " in " << __func__
+               << " entries (" << count << ").";
     return nullptr;
   }
   auto data_ptr = *in_out_data_ptr;
@@ -229,8 +225,8 @@
 }
 
 std::optional<std::string_view> ReadString(const uint8_t** in_out_data_ptr, size_t* in_out_size,
-                                           const std::string& label) {
-  const auto* len = ReadType<uint32_t>(in_out_data_ptr, in_out_size, label + " length");
+                                           const char* label) {
+  const auto* len = ReadType<uint32_t>(in_out_data_ptr, in_out_size, label);
   if (len == nullptr) {
     return {};
   }
@@ -242,7 +238,7 @@
   const uint32_t padding_size = (4U - ((size_t)*in_out_data_ptr & 0x3U)) % 4U;
   for (uint32_t i = 0; i < padding_size; i++) {
     if (**in_out_data_ptr != 0) {
-      LOG(ERROR) << " Idmap padding of " << label << " is non-zero.";
+      LOG(ERROR) << " Idmap padding of " << label << " in " << __func__ << " is non-zero.";
       return {};
     }
     *in_out_data_ptr += sizeof(uint8_t);
@@ -258,12 +254,10 @@
 #endif
 
 LoadedIdmap::LoadedIdmap(const std::string& idmap_path, const Idmap_header* header,
-                         const Idmap_data_header* data_header,
-                         const Idmap_target_entry* target_entries,
-                         const Idmap_target_entry_inline* target_inline_entries,
+                         const Idmap_data_header* data_header, Idmap_target_entries target_entries,
+                         Idmap_target_inline_entries target_inline_entries,
                          const Idmap_target_entry_inline_value* inline_entry_values,
-                         const ConfigDescription* configs,
-                         const Idmap_overlay_entry* overlay_entries,
+                         const ConfigDescription* configs, Idmap_overlay_entries overlay_entries,
                          std::unique_ptr<ResStringPool>&& string_pool,
                          std::string_view overlay_apk_path, std::string_view target_apk_path)
     : header_(header),
@@ -274,10 +268,12 @@
       configurations_(configs),
       overlay_entries_(overlay_entries),
       string_pool_(std::move(string_pool)),
-      idmap_fd_(android::base::utf8::open(idmap_path.c_str(), O_RDONLY|O_CLOEXEC|O_BINARY|O_PATH)),
+      idmap_fd_(
+          android::base::utf8::open(idmap_path.c_str(), O_RDONLY | O_CLOEXEC | O_BINARY | O_PATH)),
       overlay_apk_path_(overlay_apk_path),
       target_apk_path_(target_apk_path),
-      idmap_last_mod_time_(getFileModDate(idmap_fd_.get())) {}
+      idmap_last_mod_time_(getFileModDate(idmap_fd_.get())) {
+}
 
 std::unique_ptr<LoadedIdmap> LoadedIdmap::Load(StringPiece idmap_path, StringPiece idmap_data) {
   ATRACE_CALL();
@@ -319,14 +315,21 @@
   if (data_header == nullptr) {
     return {};
   }
-  auto target_entries = ReadType<Idmap_target_entry>(&data_ptr, &data_size, "target",
-                                                     dtohl(data_header->target_entry_count));
-  if (target_entries == nullptr) {
+  Idmap_target_entries target_entries{
+      .target_id = ReadType<uint32_t>(&data_ptr, &data_size, "entries.target_id",
+                                      dtohl(data_header->target_entry_count)),
+      .overlay_id = ReadType<uint32_t>(&data_ptr, &data_size, "entries.overlay_id",
+                                       dtohl(data_header->target_entry_count)),
+  };
+  if (!target_entries.target_id || !target_entries.overlay_id) {
     return {};
   }
-  auto target_inline_entries = ReadType<Idmap_target_entry_inline>(
-      &data_ptr, &data_size, "target inline", dtohl(data_header->target_inline_entry_count));
-  if (target_inline_entries == nullptr) {
+  Idmap_target_inline_entries target_inline_entries{
+      .target_id = ReadType<uint32_t>(&data_ptr, &data_size, "target inline.target_id",
+                                      dtohl(data_header->target_inline_entry_count)),
+      .entry = ReadType<Idmap_target_entry_inline>(&data_ptr, &data_size, "target inline.entry",
+                                                   dtohl(data_header->target_inline_entry_count))};
+  if (!target_inline_entries.target_id || !target_inline_entries.entry) {
     return {};
   }
 
@@ -344,9 +347,13 @@
     return {};
   }
 
-  auto overlay_entries = ReadType<Idmap_overlay_entry>(&data_ptr, &data_size, "target inline",
-                                                       dtohl(data_header->overlay_entry_count));
-  if (overlay_entries == nullptr) {
+  Idmap_overlay_entries overlay_entries{
+      .overlay_id = ReadType<uint32_t>(&data_ptr, &data_size, "overlay entries.overlay_id",
+                                       dtohl(data_header->overlay_entry_count)),
+      .target_id = ReadType<uint32_t>(&data_ptr, &data_size, "overlay entries.target_id",
+                                      dtohl(data_header->overlay_entry_count)),
+  };
+  if (!overlay_entries.overlay_id || !overlay_entries.target_id) {
     return {};
   }
   std::optional<std::string_view> string_pool = ReadString(&data_ptr, &data_size, "string pool");
diff --git a/libs/androidfw/include/androidfw/Idmap.h b/libs/androidfw/include/androidfw/Idmap.h
index 64b1f0c..e213fbd 100644
--- a/libs/androidfw/include/androidfw/Idmap.h
+++ b/libs/androidfw/include/androidfw/Idmap.h
@@ -40,6 +40,19 @@
 struct Idmap_target_entry_inline_value;
 struct Idmap_overlay_entry;
 
+struct Idmap_target_entries {
+  const uint32_t* target_id = nullptr;
+  const uint32_t* overlay_id = nullptr;
+};
+struct Idmap_target_inline_entries {
+  const uint32_t* target_id = nullptr;
+  const Idmap_target_entry_inline* entry = nullptr;
+};
+struct Idmap_overlay_entries {
+  const uint32_t* overlay_id = nullptr;
+  const uint32_t* target_id = nullptr;
+};
+
 // A string pool for overlay apk assets. The string pool holds the strings of the overlay resources
 // table and additionally allows for loading strings from the idmap string pool. The idmap string
 // pool strings are offset after the end of the overlay resource table string pool entries so
@@ -67,7 +80,7 @@
 
  private:
   explicit OverlayDynamicRefTable(const Idmap_data_header* data_header,
-                                  const Idmap_overlay_entry* entries,
+                                  Idmap_overlay_entries entries,
                                   uint8_t target_assigned_package_id);
 
   // Rewrites a compile-time overlay resource id to the runtime resource id of corresponding target
@@ -75,8 +88,8 @@
   status_t lookupResourceIdNoRewrite(uint32_t* resId) const;
 
   const Idmap_data_header* data_header_;
-  const Idmap_overlay_entry* entries_;
-  const int8_t target_assigned_package_id_;
+  Idmap_overlay_entries entries_;
+  uint8_t target_assigned_package_id_;
 
   friend LoadedIdmap;
   friend IdmapResMap;
@@ -131,17 +144,15 @@
   }
 
  private:
-  explicit IdmapResMap(const Idmap_data_header* data_header,
-                       const Idmap_target_entry* entries,
-                       const Idmap_target_entry_inline* inline_entries,
+  explicit IdmapResMap(const Idmap_data_header* data_header, Idmap_target_entries entries,
+                       Idmap_target_inline_entries inline_entries,
                        const Idmap_target_entry_inline_value* inline_entry_values,
-                       const ConfigDescription* configs,
-                       uint8_t target_assigned_package_id,
+                       const ConfigDescription* configs, uint8_t target_assigned_package_id,
                        const OverlayDynamicRefTable* overlay_ref_table);
 
   const Idmap_data_header* data_header_;
-  const Idmap_target_entry* entries_;
-  const Idmap_target_entry_inline* inline_entries_;
+  Idmap_target_entries entries_;
+  Idmap_target_inline_entries inline_entries_;
   const Idmap_target_entry_inline_value* inline_entry_values_;
   const ConfigDescription* configurations_;
   const uint8_t target_assigned_package_id_;
@@ -192,11 +203,11 @@
 
   const Idmap_header* header_;
   const Idmap_data_header* data_header_;
-  const Idmap_target_entry* target_entries_;
-  const Idmap_target_entry_inline* target_inline_entries_;
+  Idmap_target_entries target_entries_;
+  Idmap_target_inline_entries target_inline_entries_;
   const Idmap_target_entry_inline_value* inline_entry_values_;
   const ConfigDescription* configurations_;
-  const Idmap_overlay_entry* overlay_entries_;
+  const Idmap_overlay_entries overlay_entries_;
   const std::unique_ptr<ResStringPool> string_pool_;
 
   android::base::unique_fd idmap_fd_;
@@ -207,17 +218,13 @@
  private:
   DISALLOW_COPY_AND_ASSIGN(LoadedIdmap);
 
-  explicit LoadedIdmap(const std::string& idmap_path,
-                       const Idmap_header* header,
-                       const Idmap_data_header* data_header,
-                       const Idmap_target_entry* target_entries,
-                       const Idmap_target_entry_inline* target_inline_entries,
+  explicit LoadedIdmap(const std::string& idmap_path, const Idmap_header* header,
+                       const Idmap_data_header* data_header, Idmap_target_entries target_entries,
+                       Idmap_target_inline_entries target_inline_entries,
                        const Idmap_target_entry_inline_value* inline_entry_values_,
-                       const ConfigDescription* configs,
-                       const Idmap_overlay_entry* overlay_entries,
+                       const ConfigDescription* configs, Idmap_overlay_entries overlay_entries,
                        std::unique_ptr<ResStringPool>&& string_pool,
-                       std::string_view overlay_apk_path,
-                       std::string_view target_apk_path);
+                       std::string_view overlay_apk_path, std::string_view target_apk_path);
 
   friend OverlayStringPool;
 };
diff --git a/libs/androidfw/include/androidfw/ResourceTypes.h b/libs/androidfw/include/androidfw/ResourceTypes.h
index c264890..e330410 100644
--- a/libs/androidfw/include/androidfw/ResourceTypes.h
+++ b/libs/androidfw/include/androidfw/ResourceTypes.h
@@ -48,7 +48,7 @@
 namespace android {
 
 constexpr const uint32_t kIdmapMagic = 0x504D4449u;
-constexpr const uint32_t kIdmapCurrentVersion = 0x00000009u;
+constexpr const uint32_t kIdmapCurrentVersion = 0x0000000Au;
 
 // This must never change.
 constexpr const uint32_t kFabricatedOverlayMagic = 0x4f525246; // FRRO (big endian)
diff --git a/libs/androidfw/tests/data/overlay/overlay.idmap b/libs/androidfw/tests/data/overlay/overlay.idmap
index 8e847e8..7e4b261 100644
--- a/libs/androidfw/tests/data/overlay/overlay.idmap
+++ b/libs/androidfw/tests/data/overlay/overlay.idmap
Binary files differ
diff --git a/libs/appfunctions/api/current.txt b/libs/appfunctions/api/current.txt
index bc269fe..e9845c1 100644
--- a/libs/appfunctions/api/current.txt
+++ b/libs/appfunctions/api/current.txt
@@ -15,7 +15,8 @@
   public abstract class AppFunctionService extends android.app.Service {
     ctor public AppFunctionService();
     method @NonNull public final android.os.IBinder onBind(@Nullable android.content.Intent);
-    method @MainThread public void onExecuteFunction(@NonNull com.google.android.appfunctions.sidecar.ExecuteAppFunctionRequest, @NonNull android.os.CancellationSignal, @NonNull java.util.function.Consumer<com.google.android.appfunctions.sidecar.ExecuteAppFunctionResponse>);
+    method @MainThread public void onExecuteFunction(@NonNull com.google.android.appfunctions.sidecar.ExecuteAppFunctionRequest, @NonNull String, @NonNull android.os.CancellationSignal, @NonNull java.util.function.Consumer<com.google.android.appfunctions.sidecar.ExecuteAppFunctionResponse>);
+    method @Deprecated @MainThread public void onExecuteFunction(@NonNull com.google.android.appfunctions.sidecar.ExecuteAppFunctionRequest, @NonNull android.os.CancellationSignal, @NonNull java.util.function.Consumer<com.google.android.appfunctions.sidecar.ExecuteAppFunctionResponse>);
     method @Deprecated @MainThread public void onExecuteFunction(@NonNull com.google.android.appfunctions.sidecar.ExecuteAppFunctionRequest, @NonNull java.util.function.Consumer<com.google.android.appfunctions.sidecar.ExecuteAppFunctionResponse>);
     field @NonNull public static final String BIND_APP_FUNCTION_SERVICE = "android.permission.BIND_APP_FUNCTION_SERVICE";
     field @NonNull public static final String SERVICE_INTERFACE = "android.app.appfunctions.AppFunctionService";
diff --git a/libs/appfunctions/java/com/google/android/appfunctions/sidecar/AppFunctionService.java b/libs/appfunctions/java/com/google/android/appfunctions/sidecar/AppFunctionService.java
index 6e91de6..2a168e8 100644
--- a/libs/appfunctions/java/com/google/android/appfunctions/sidecar/AppFunctionService.java
+++ b/libs/appfunctions/java/com/google/android/appfunctions/sidecar/AppFunctionService.java
@@ -24,8 +24,8 @@
 import android.app.Service;
 import android.content.Intent;
 import android.os.Binder;
-import android.os.IBinder;
 import android.os.CancellationSignal;
+import android.os.IBinder;
 import android.util.Log;
 
 import java.util.function.Consumer;
@@ -71,18 +71,21 @@
     private final Binder mBinder =
             android.app.appfunctions.AppFunctionService.createBinder(
                     /* context= */ this,
-                    /* onExecuteFunction= */ (platformRequest, cancellationSignal, callback) -> {
+                    /* onExecuteFunction= */ (platformRequest,
+                            callingPackage,
+                            cancellationSignal,
+                            callback) -> {
                         AppFunctionService.this.onExecuteFunction(
                                 SidecarConverter.getSidecarExecuteAppFunctionRequest(
                                         platformRequest),
+                                callingPackage,
                                 cancellationSignal,
                                 (sidecarResponse) -> {
                                     callback.accept(
                                             SidecarConverter.getPlatformExecuteAppFunctionResponse(
                                                     sidecarResponse));
                                 });
-                    }
-            );
+                    });
 
     @NonNull
     @Override
@@ -107,13 +110,51 @@
      * thread and dispatch the result with the given callback. You should always report back the
      * result using the callback, no matter if the execution was successful or not.
      *
+     * <p>This method also accepts a {@link CancellationSignal} that the app should listen to cancel
+     * the execution of function if requested by the system.
+     *
      * @param request The function execution request.
-     * @param cancellationSignal A {@link CancellationSignal} to cancel the request.
+     * @param callingPackage The package name of the app that is requesting the execution.
+     * @param cancellationSignal A signal to cancel the execution.
      * @param callback A callback to report back the result.
      */
     @MainThread
     public void onExecuteFunction(
             @NonNull ExecuteAppFunctionRequest request,
+            @NonNull String callingPackage,
+            @NonNull CancellationSignal cancellationSignal,
+            @NonNull Consumer<ExecuteAppFunctionResponse> callback) {
+        onExecuteFunction(request, cancellationSignal, callback);
+    }
+
+    /**
+     * Called by the system to execute a specific app function.
+     *
+     * <p>This method is triggered when the system requests your AppFunctionService to handle a
+     * particular function you have registered and made available.
+     *
+     * <p>To ensure proper routing of function requests, assign a unique identifier to each
+     * function. This identifier doesn't need to be globally unique, but it must be unique within
+     * your app. For example, a function to order food could be identified as "orderFood". In most
+     * cases this identifier should come from the ID automatically generated by the AppFunctions
+     * SDK. You can determine the specific function to invoke by calling {@link
+     * ExecuteAppFunctionRequest#getFunctionIdentifier()}.
+     *
+     * <p>This method is always triggered in the main thread. You should run heavy tasks on a worker
+     * thread and dispatch the result with the given callback. You should always report back the
+     * result using the callback, no matter if the execution was successful or not.
+     *
+     * @param request The function execution request.
+     * @param cancellationSignal A {@link CancellationSignal} to cancel the request.
+     * @param callback A callback to report back the result.
+     * @deprecated Use {@link #onExecuteFunction(ExecuteAppFunctionRequest, String,
+     *     CancellationSignal, Consumer)} instead. This method will be removed once usage references
+     *     are updated.
+     */
+    @MainThread
+    @Deprecated
+    public void onExecuteFunction(
+            @NonNull ExecuteAppFunctionRequest request,
             @NonNull CancellationSignal cancellationSignal,
             @NonNull Consumer<ExecuteAppFunctionResponse> callback) {
         onExecuteFunction(request, callback);
@@ -138,7 +179,6 @@
      *
      * @param request The function execution request.
      * @param callback A callback to report back the result.
-     *
      * @deprecated Use {@link #onExecuteFunction(ExecuteAppFunctionRequest, CancellationSignal,
      *     Consumer)} instead. This method will be removed once usage references are updated.
      */
diff --git a/libs/appfunctions/java/com/google/android/appfunctions/sidecar/ExecuteAppFunctionResponse.java b/libs/appfunctions/java/com/google/android/appfunctions/sidecar/ExecuteAppFunctionResponse.java
index d87fec79..969e5d5 100644
--- a/libs/appfunctions/java/com/google/android/appfunctions/sidecar/ExecuteAppFunctionResponse.java
+++ b/libs/appfunctions/java/com/google/android/appfunctions/sidecar/ExecuteAppFunctionResponse.java
@@ -234,12 +234,13 @@
     @IntDef(
             prefix = {"RESULT_"},
             value = {
-                    RESULT_OK,
-                    RESULT_DENIED,
-                    RESULT_APP_UNKNOWN_ERROR,
-                    RESULT_INTERNAL_ERROR,
-                    RESULT_INVALID_ARGUMENT,
-                    RESULT_DISABLED
+                RESULT_OK,
+                RESULT_DENIED,
+                RESULT_APP_UNKNOWN_ERROR,
+                RESULT_INTERNAL_ERROR,
+                RESULT_INVALID_ARGUMENT,
+                RESULT_DISABLED,
+                RESULT_CANCELLED
             })
     @Retention(RetentionPolicy.SOURCE)
     public @interface ResultCode {}
diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp
index 23cd3ce..266c236 100644
--- a/libs/hwui/Android.bp
+++ b/libs/hwui/Android.bp
@@ -501,6 +501,13 @@
     ],
 }
 
+genrule {
+    name: "statslog-hwui-java-gen",
+    tools: ["stats-log-api-gen"],
+    cmd: "$(location stats-log-api-gen) --java $(out) --module hwui --javaPackage com.android.os.coregraphics --javaClass HwuiStatsLog",
+    out: ["com/android/os/coregraphics/HwuiStatsLog.java"],
+}
+
 // ------------------------
 // library
 // ------------------------
diff --git a/libs/hwui/DeferredLayerUpdater.cpp b/libs/hwui/DeferredLayerUpdater.cpp
index b763a96..c016070 100644
--- a/libs/hwui/DeferredLayerUpdater.cpp
+++ b/libs/hwui/DeferredLayerUpdater.cpp
@@ -19,6 +19,7 @@
 #include <GLES2/gl2ext.h>
 
 // TODO: Use public SurfaceTexture APIs once available and include public NDK header file instead.
+#include <statslog_hwui.h>
 #include <surfacetexture/surface_texture_platform.h>
 
 #include "AutoBackendTextureRelease.h"
@@ -50,6 +51,14 @@
     setTransform(nullptr);
     mRenderState.removeContextCallback(this);
     destroyLayer();
+    if (mFirstTimeForDataspace > std::chrono::steady_clock::time_point::min()) {
+        auto currentTime = std::chrono::steady_clock::now();
+        stats_write(stats::TEXTURE_VIEW_EVENT, static_cast<int32_t>(getuid()),
+                    static_cast<int64_t>(std::chrono::duration_cast<std::chrono::milliseconds>(
+                                                 currentTime - mFirstTimeForDataspace)
+                                                 .count()),
+                    mDataspace);
+    }
 }
 
 void DeferredLayerUpdater::setSurfaceTexture(AutoTextureRelease&& consumer) {
@@ -195,6 +204,21 @@
                     updateLayer(forceFilter, layerImage, outTransform, currentCropRect,
                                 maxLuminanceNits);
                 }
+
+                if (dataspace != mDataspace ||
+                    mFirstTimeForDataspace == std::chrono::steady_clock::time_point::min()) {
+                    auto currentTime = std::chrono::steady_clock::now();
+                    if (mFirstTimeForDataspace > std::chrono::steady_clock::time_point::min()) {
+                        stats_write(stats::TEXTURE_VIEW_EVENT, static_cast<int32_t>(getuid()),
+                                    static_cast<int64_t>(
+                                            std::chrono::duration_cast<std::chrono::milliseconds>(
+                                                    currentTime - mFirstTimeForDataspace)
+                                                    .count()),
+                                    mDataspace);
+                    }
+                    mFirstTimeForDataspace = currentTime;
+                    mDataspace = dataspace;
+                }
             }
         }
 
diff --git a/libs/hwui/DeferredLayerUpdater.h b/libs/hwui/DeferredLayerUpdater.h
index a7f8f61..3abb47c 100644
--- a/libs/hwui/DeferredLayerUpdater.h
+++ b/libs/hwui/DeferredLayerUpdater.h
@@ -16,6 +16,8 @@
 
 #pragma once
 
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
 #include <SkBlendMode.h>
 #include <SkColorFilter.h>
 #include <SkImage.h>
@@ -24,9 +26,9 @@
 #include <android/surface_texture.h>
 #include <cutils/compiler.h>
 #include <utils/Errors.h>
+#include <utils/Timers.h>
 
-#include <EGL/egl.h>
-#include <EGL/eglext.h>
+#include <chrono>
 #include <map>
 #include <memory>
 
@@ -154,6 +156,9 @@
     bool mGLContextAttached;
     bool mUpdateTexImage;
     int mCurrentSlot = -1;
+    android_dataspace mDataspace = HAL_DATASPACE_UNKNOWN;
+    std::chrono::steady_clock::time_point mFirstTimeForDataspace =
+            std::chrono::steady_clock::time_point::min();
 
     Layer* mLayer;
 };
diff --git a/libs/hwui/apex/LayoutlibLoader.cpp b/libs/hwui/apex/LayoutlibLoader.cpp
index b4e6b72..56191c0 100644
--- a/libs/hwui/apex/LayoutlibLoader.cpp
+++ b/libs/hwui/apex/LayoutlibLoader.cpp
@@ -205,6 +205,13 @@
     jmethodID getPropertyMethod = GetStaticMethodIDOrDie(env, system, "getProperty",
                                                          "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;");
 
+    auto formatProperty = (jstring)env->CallStaticObjectMethod(
+            system, getPropertyMethod, env->NewStringUTF("method_binding_format"),
+            env->NewStringUTF(""));
+    const char* methodFormatChars = env->GetStringUTFChars(formatProperty, 0);
+    setJniMethodFormat(string(methodFormatChars));
+    env->ReleaseStringUTFChars(formatProperty, methodFormatChars);
+
     // Get the names of classes that need to register their native methods
     auto nativesClassesJString = (jstring)env->CallStaticObjectMethod(
             system, getPropertyMethod, env->NewStringUTF("graphics_native_classes"),
diff --git a/libs/hwui/jni/text/TextShaper.cpp b/libs/hwui/jni/text/TextShaper.cpp
index 6c05346..4563386 100644
--- a/libs/hwui/jni/text/TextShaper.cpp
+++ b/libs/hwui/jni/text/TextShaper.cpp
@@ -156,16 +156,47 @@
     return layout->layout.getFakery(i).isFakeItalic();
 }
 
+float findValueFromVariationSettings(const minikin::FontFakery& fakery, minikin::AxisTag tag) {
+    for (const minikin::FontVariation& fv : fakery.variationSettings()) {
+        if (fv.axisTag == tag) {
+            return fv.value;
+        }
+    }
+    return std::numeric_limits<float>::quiet_NaN();
+}
+
 // CriticalNative
 static jfloat TextShaper_Result_getWeightOverride(CRITICAL_JNI_PARAMS_COMMA jlong ptr, jint i) {
     const LayoutWrapper* layout = reinterpret_cast<LayoutWrapper*>(ptr);
-    return layout->layout.getFakery(i).wghtAdjustment();
+    if (text_feature::typeface_redesign()) {
+        float value =
+                findValueFromVariationSettings(layout->layout.getFakery(i), minikin::TAG_wght);
+        if (!std::isnan(value)) {
+            return value;
+        } else {
+            const std::shared_ptr<minikin::Font>& font = layout->layout.getFontRef(i);
+            return font->style().weight();
+        }
+    } else {
+        return layout->layout.getFakery(i).wghtAdjustment();
+    }
 }
 
 // CriticalNative
 static jfloat TextShaper_Result_getItalicOverride(CRITICAL_JNI_PARAMS_COMMA jlong ptr, jint i) {
     const LayoutWrapper* layout = reinterpret_cast<LayoutWrapper*>(ptr);
-    return layout->layout.getFakery(i).italAdjustment();
+    if (text_feature::typeface_redesign()) {
+        float value =
+                findValueFromVariationSettings(layout->layout.getFakery(i), minikin::TAG_ital);
+        if (!std::isnan(value)) {
+            return value;
+        } else {
+            const std::shared_ptr<minikin::Font>& font = layout->layout.getFontRef(i);
+            return font->style().isItalic();
+        }
+    } else {
+        return layout->layout.getFakery(i).italAdjustment();
+    }
 }
 
 // CriticalNative
diff --git a/libs/hwui/pipeline/skia/BackdropFilterDrawable.cpp b/libs/hwui/pipeline/skia/BackdropFilterDrawable.cpp
index e81cbfb..c0ef4b14 100644
--- a/libs/hwui/pipeline/skia/BackdropFilterDrawable.cpp
+++ b/libs/hwui/pipeline/skia/BackdropFilterDrawable.cpp
@@ -29,37 +29,6 @@
 namespace uirenderer {
 namespace skiapipeline {
 
-BackdropFilterDrawable::~BackdropFilterDrawable() {}
-
-bool BackdropFilterDrawable::prepareToDraw(SkCanvas* canvas, const RenderProperties& properties,
-                                           int backdropImageWidth, int backdropImageHeight) {
-    // the drawing bounds for blurred content.
-    mDstBounds.setWH(properties.getWidth(), properties.getHeight());
-
-    float alphaMultiplier = 1.0f;
-    RenderNodeDrawable::setViewProperties(properties, canvas, &alphaMultiplier, true);
-
-    // get proper subset for previous content.
-    canvas->getTotalMatrix().mapRect(&mImageSubset, mDstBounds);
-    SkRect imageSubset(mImageSubset);
-    // ensure the subset is inside bounds of previous content.
-    if (!mImageSubset.intersect(SkRect::MakeWH(backdropImageWidth, backdropImageHeight))) {
-        return false;
-    }
-
-    // correct the drawing bounds if subset was changed.
-    if (mImageSubset != imageSubset) {
-        SkMatrix inverse;
-        if (canvas->getTotalMatrix().invert(&inverse)) {
-            inverse.mapRect(&mDstBounds, mImageSubset);
-        }
-    }
-
-    // follow the alpha from the target RenderNode.
-    mPaint.setAlpha(properties.layerProperties().alpha() * alphaMultiplier);
-    return true;
-}
-
 void BackdropFilterDrawable::onDraw(SkCanvas* canvas) {
     const RenderProperties& properties = mTargetRenderNode->properties();
     auto* backdropFilter = properties.layerProperties().getBackdropImageFilter();
@@ -68,27 +37,43 @@
         return;
     }
 
-    auto backdropImage = surface->makeImageSnapshot();
-    // sync necessary properties from target RenderNode.
-    if (!prepareToDraw(canvas, properties, backdropImage->width(), backdropImage->height())) {
+    SkRect srcBounds = SkRect::MakeWH(properties.getWidth(), properties.getHeight());
+
+    float alphaMultiplier = 1.0f;
+    RenderNodeDrawable::setViewProperties(properties, canvas, &alphaMultiplier, true);
+    SkPaint paint;
+    paint.setAlpha(properties.layerProperties().alpha() * alphaMultiplier);
+
+    SkRect surfaceSubset;
+    canvas->getTotalMatrix().mapRect(&surfaceSubset, srcBounds);
+    if (!surfaceSubset.intersect(SkRect::MakeWH(surface->width(), surface->height()))) {
         return;
     }
 
-    auto imageSubset = mImageSubset.roundOut();
+    auto backdropImage = surface->makeImageSnapshot(surfaceSubset.roundOut());
+
+    SkIRect imageBounds = SkIRect::MakeWH(backdropImage->width(), backdropImage->height());
+    SkIPoint offset;
+    SkIRect imageSubset;
+
 #ifdef __ANDROID__
     if (canvas->recordingContext()) {
         backdropImage =
                 SkImages::MakeWithFilter(canvas->recordingContext(), backdropImage, backdropFilter,
-                                         imageSubset, imageSubset, &mOutSubset, &mOutOffset);
+                                         imageBounds, imageBounds, &imageSubset, &offset);
     } else
 #endif
     {
-        backdropImage = SkImages::MakeWithFilter(backdropImage, backdropFilter, imageSubset,
-                                                 imageSubset, &mOutSubset, &mOutOffset);
+        backdropImage = SkImages::MakeWithFilter(backdropImage, backdropFilter, imageBounds,
+                                                 imageBounds, &imageSubset, &offset);
     }
-    canvas->drawImageRect(backdropImage, SkRect::Make(mOutSubset), mDstBounds,
-                          SkSamplingOptions(SkFilterMode::kLinear), &mPaint,
-                          SkCanvas::kStrict_SrcRectConstraint);
+
+    canvas->save();
+    canvas->resetMatrix();
+    canvas->drawImageRect(backdropImage, SkRect::Make(imageSubset), surfaceSubset,
+                          SkSamplingOptions(SkFilterMode::kLinear), &paint,
+                          SkCanvas::kFast_SrcRectConstraint);
+    canvas->restore();
 }
 
 }  // namespace skiapipeline
diff --git a/libs/hwui/pipeline/skia/BackdropFilterDrawable.h b/libs/hwui/pipeline/skia/BackdropFilterDrawable.h
index 9e35837..5e216a1 100644
--- a/libs/hwui/pipeline/skia/BackdropFilterDrawable.h
+++ b/libs/hwui/pipeline/skia/BackdropFilterDrawable.h
@@ -37,23 +37,10 @@
     BackdropFilterDrawable(RenderNode* renderNode, SkCanvas* canvas)
             : mTargetRenderNode(renderNode), mBounds(canvas->getLocalClipBounds()) {}
 
-    ~BackdropFilterDrawable();
+    ~BackdropFilterDrawable() = default;
 
 private:
     RenderNode* mTargetRenderNode;
-    SkPaint mPaint;
-
-    SkRect mDstBounds;
-    SkRect mImageSubset;
-    SkIRect mOutSubset;
-    SkIPoint mOutOffset;
-
-    /**
-     * Check all necessary properties before actual drawing.
-     * Return true if ready to draw.
-     */
-    bool prepareToDraw(SkCanvas* canvas, const RenderProperties& properties, int backdropImageWidth,
-                       int backdropImageHeight);
 
 protected:
     void onDraw(SkCanvas* canvas) override;
diff --git a/libs/hwui/tests/common/scenes/BackdropBlur.cpp b/libs/hwui/tests/common/scenes/BackdropBlur.cpp
new file mode 100644
index 0000000..a1133ff
--- /dev/null
+++ b/libs/hwui/tests/common/scenes/BackdropBlur.cpp
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <SkBlendMode.h>
+
+#include "SkImageFilter.h"
+#include "SkImageFilters.h"
+#include "TestSceneBase.h"
+#include "utils/Blur.h"
+
+class BackdropBlurAnimation : public TestScene {
+private:
+    std::unique_ptr<TestScene> listView;
+
+public:
+    explicit BackdropBlurAnimation(const TestScene::Options& opts) {
+        listView.reset(TestScene::testMap()["listview"].createScene(opts));
+    }
+
+    void createContent(int width, int height, Canvas& canvas) override {
+        sp<RenderNode> list = TestUtils::createNode(
+                0, 0, width, height,
+                [this, width, height](RenderProperties& props, Canvas& canvas) {
+                    props.setClipToBounds(false);
+                    listView->createContent(width, height, canvas);
+                });
+
+        canvas.drawRenderNode(list.get());
+
+        int x = width / 8;
+        int y = height / 4;
+        sp<RenderNode> blurNode = TestUtils::createNode(
+                x, y, width - x, height - y, [](RenderProperties& props, Canvas& canvas) {
+                    props.mutableOutline().setRoundRect(0, 0, props.getWidth(), props.getHeight(),
+                                                        dp(16), 1);
+                    props.mutableOutline().setShouldClip(true);
+                    sk_sp<SkImageFilter> blurFilter = SkImageFilters::Blur(
+                            Blur::convertRadiusToSigma(dp(8)), Blur::convertRadiusToSigma(dp(8)),
+                            SkTileMode::kClamp, nullptr, nullptr);
+                    props.mutateLayerProperties().setBackdropImageFilter(blurFilter.get());
+                    canvas.drawColor(0x33000000, SkBlendMode::kSrcOver);
+                });
+
+        canvas.drawRenderNode(blurNode.get());
+    }
+
+    void doFrame(int frameNr) override { listView->doFrame(frameNr); }
+};
+
+static TestScene::Registrar _BackdropBlur(TestScene::Info{
+        "backdropblur", "A rounded rect that does a blur-behind of a sky animation.",
+        [](const TestScene::Options& opts) -> test::TestScene* {
+            return new BackdropBlurAnimation(opts);
+        }});
diff --git a/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp b/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp
index ca54087..4b29100 100644
--- a/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp
+++ b/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp
@@ -1280,7 +1280,7 @@
     canvas->drawDrawable(&backdropDrawable);
     // the drawable is still visible, ok to draw.
     EXPECT_EQ(2, canvas->mDrawCounter);
-    EXPECT_EQ(SkRect::MakeLTRB(0, 0, CANVAS_WIDTH - 30, CANVAS_HEIGHT - 30), canvas->mDstBounds);
+    EXPECT_EQ(SkRect::MakeLTRB(30, 30, CANVAS_WIDTH, CANVAS_HEIGHT), canvas->mDstBounds);
 
     canvas->translate(CANVAS_WIDTH, CANVAS_HEIGHT);
     canvas->drawDrawable(&drawable);
diff --git a/location/lib/Android.bp b/location/lib/Android.bp
index b10019a..67d5774 100644
--- a/location/lib/Android.bp
+++ b/location/lib/Android.bp
@@ -29,6 +29,10 @@
     libs: [
         "androidx.annotation_annotation",
     ],
+    stub_only_libs: [
+        // Needed for javadoc references.
+        "framework-location.stubs.system",
+    ],
     api_packages: [
         "android.location",
         "com.android.location.provider",
diff --git a/media/java/android/media/AudioFormat.java b/media/java/android/media/AudioFormat.java
index c90c441..0da8371b 100644
--- a/media/java/android/media/AudioFormat.java
+++ b/media/java/android/media/AudioFormat.java
@@ -16,6 +16,9 @@
 
 package android.media;
 
+import static android.media.audio.Flags.FLAG_DOLBY_AC4_LEVEL4_ENCODING_API;
+
+import android.annotation.FlaggedApi;
 import android.annotation.IntDef;
 import android.annotation.IntRange;
 import android.annotation.NonNull;
@@ -309,7 +312,7 @@
     public static final int ENCODING_AAC_ELD = 15;
     /** Audio data format: AAC xHE compressed */
     public static final int ENCODING_AAC_XHE = 16;
-    /** Audio data format: AC-4 sync frame transport format */
+    /** Audio data format: AC-4 (levels 0-3) sync frame transport format */
     public static final int ENCODING_AC4 = 17;
     /** Audio data format: E-AC-3-JOC compressed
      * E-AC-3-JOC streams can be decoded by downstream devices supporting {@link #ENCODING_E_AC3}.
@@ -375,6 +378,9 @@
     public static final int ENCODING_DTS_UHD_P2 = 30;
     /** Audio data format: Direct Stream Digital */
     public static final int ENCODING_DSD = 31;
+    /** Audio data format: AC-4 level 4 sync frame transport format */
+    @FlaggedApi(FLAG_DOLBY_AC4_LEVEL4_ENCODING_API)
+    public static final int ENCODING_AC4_L4 = 32;
 
     /** @hide */
     public static String toLogFriendlyEncoding(int enc) {
@@ -413,6 +419,8 @@
                 return "ENCODING_AAC_XHE";
             case ENCODING_AC4:
                 return "ENCODING_AC4";
+            case ENCODING_AC4_L4:
+                return "ENCODING_AC4_L4";
             case ENCODING_E_AC3_JOC:
                 return "ENCODING_E_AC3_JOC";
             case ENCODING_DOLBY_MAT:
@@ -823,6 +831,7 @@
             case ENCODING_AAC_ELD:
             case ENCODING_AAC_XHE:
             case ENCODING_AC4:
+            case ENCODING_AC4_L4:
             case ENCODING_E_AC3_JOC:
             case ENCODING_DOLBY_MAT:
             case ENCODING_OPUS:
@@ -863,6 +872,7 @@
             case ENCODING_AAC_ELD:
             case ENCODING_AAC_XHE:
             case ENCODING_AC4:
+            case ENCODING_AC4_L4:
             case ENCODING_E_AC3_JOC:
             case ENCODING_DOLBY_MAT:
             case ENCODING_OPUS:
@@ -908,6 +918,7 @@
             case ENCODING_AAC_ELD:
             case ENCODING_AAC_XHE:
             case ENCODING_AC4:
+            case ENCODING_AC4_L4:
             case ENCODING_E_AC3_JOC:
             case ENCODING_DOLBY_MAT:
             case ENCODING_OPUS:
@@ -950,6 +961,7 @@
             case ENCODING_AAC_ELD:
             case ENCODING_AAC_XHE:
             case ENCODING_AC4:
+            case ENCODING_AC4_L4:
             case ENCODING_E_AC3_JOC:
             case ENCODING_DOLBY_MAT:
             case ENCODING_OPUS:
@@ -1238,6 +1250,7 @@
                 case ENCODING_AAC_ELD:
                 case ENCODING_AAC_XHE:
                 case ENCODING_AC4:
+                case ENCODING_AC4_L4:
                 case ENCODING_E_AC3_JOC:
                 case ENCODING_DOLBY_MAT:
                 case ENCODING_OPUS:
@@ -1468,6 +1481,7 @@
         ENCODING_AAC_ELD,
         ENCODING_AAC_XHE,
         ENCODING_AC4,
+        ENCODING_AC4_L4,
         ENCODING_E_AC3_JOC,
         ENCODING_DOLBY_MAT,
         ENCODING_OPUS,
@@ -1506,6 +1520,7 @@
             ENCODING_AAC_ELD,
             ENCODING_AAC_XHE,
             ENCODING_AC4,
+            ENCODING_AC4_L4,
             ENCODING_E_AC3_JOC,
             ENCODING_DOLBY_MAT,
             ENCODING_OPUS,
@@ -1533,6 +1548,7 @@
             ENCODING_AAC_LC,
             ENCODING_DOLBY_TRUEHD,
             ENCODING_AC4,
+            ENCODING_AC4_L4,
             ENCODING_E_AC3_JOC,
             ENCODING_DOLBY_MAT,
             ENCODING_MPEGH_BL_L3,
@@ -1554,6 +1570,7 @@
             ENCODING_AAC_LC,
             ENCODING_DOLBY_TRUEHD,
             ENCODING_AC4,
+            ENCODING_AC4_L4,
             ENCODING_E_AC3_JOC,
             ENCODING_DOLBY_MAT,
             ENCODING_MPEGH_BL_L3,
@@ -1592,7 +1609,9 @@
             case ENCODING_DOLBY_TRUEHD:
                 return "Dolby TrueHD";
             case ENCODING_AC4:
-                return "Dolby AC-4";
+                return "Dolby AC-4 levels 0-3";
+            case ENCODING_AC4_L4:
+                return "Dolby AC-4 level 4";
             case ENCODING_E_AC3_JOC:
                 return "Dolby Atmos in Dolby Digital Plus";
             case ENCODING_DOLBY_MAT:
diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java
index ebdfd3e..a8b863b 100644
--- a/media/java/android/media/AudioSystem.java
+++ b/media/java/android/media/AudioSystem.java
@@ -542,6 +542,8 @@
                 return "AUDIO_FORMAT_AAC_LATM_HE_V2"; // (AAC_LATM | AAC_SUB_HE_V2)
             case /* AUDIO_FORMAT_E_AC3_JOC         */ 0xA000001:
                 return "AUDIO_FORMAT_E_AC3_JOC";  // (E_AC3 | E_AC3_SUB_JOC)
+            case /* AUDIO_FORMAT_AC4_L4            */ 0x22000001:
+                return "AUDIO_FORMAT_AC4_L4";  // (AC4 | AC4_SUB_L4)
             case /* AUDIO_FORMAT_MAT_1_0           */ 0x24000001:
                 return "AUDIO_FORMAT_MAT_1_0"; // (MAT | MAT_SUB_1_0)
             case /* AUDIO_FORMAT_MAT_2_0           */ 0x24000002:
diff --git a/media/java/android/media/MediaCas.java b/media/java/android/media/MediaCas.java
index 2d7db5e..b022ea1 100644
--- a/media/java/android/media/MediaCas.java
+++ b/media/java/android/media/MediaCas.java
@@ -16,6 +16,9 @@
 
 package android.media;
 
+import static com.android.media.flags.Flags.FLAG_UPDATE_CLIENT_PROFILE_PRIORITY;
+
+import android.annotation.FlaggedApi;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -131,7 +134,7 @@
     private int mCasSystemId;
     private int mUserId;
     private TunerResourceManager mTunerResourceManager = null;
-    private final Map<Session, Integer> mSessionMap = new HashMap<>();
+    private final Map<Session, Long> mSessionMap = new HashMap<>();
 
     /**
      * Scrambling modes used to open cas sessions.
@@ -970,6 +973,27 @@
         registerClient(context, tvInputServiceSessionId, priorityHint);
     }
 
+    /**
+     * Updates client priority with an arbitrary value along with a nice value.
+     *
+     * <p>Tuner resource manager (TRM) uses the client priority value to decide whether it is able
+     * to reclaim insufficient resources from another client.
+     *
+     * <p>The nice value represents how much the client intends to give up the resource when an
+     * insufficient resource situation happens.
+     *
+     * @see <a
+     *     href="https://source.android.com/docs/devices/tv/tuner-framework#priority-nice-value">
+     *     Priority value and nice value</a>
+     * @param priority the new priority. Any negative value would cause no-op on priority setting
+     *     and the API would only process nice value setting in that case.
+     * @param niceValue the nice value.
+     */
+    @FlaggedApi(FLAG_UPDATE_CLIENT_PROFILE_PRIORITY)
+    public boolean updateResourcePriority(int priority, int niceValue) {
+        return mTunerResourceManager.updateClientPriority(mClientId, priority, niceValue);
+    }
+
     IHwBinder getBinder() {
         if (mICas != null) {
             return null; // Return IHwBinder only for HIDL
@@ -1126,10 +1150,10 @@
         }
     }
 
-    private int getSessionResourceHandle() throws MediaCasException {
+    private long getSessionResourceHandle() throws MediaCasException {
         validateInternalStates();
 
-        int[] sessionResourceHandle = new int[1];
+        long[] sessionResourceHandle = new long[1];
         sessionResourceHandle[0] = -1;
         if (mTunerResourceManager != null) {
             CasSessionRequest casSessionRequest = new CasSessionRequest();
@@ -1144,8 +1168,7 @@
         return sessionResourceHandle[0];
     }
 
-    private void addSessionToResourceMap(Session session, int sessionResourceHandle) {
-
+    private void addSessionToResourceMap(Session session, long sessionResourceHandle) {
         if (sessionResourceHandle != TunerResourceManager.INVALID_RESOURCE_HANDLE) {
             synchronized (mSessionMap) {
                 mSessionMap.put(session, sessionResourceHandle);
@@ -1178,13 +1201,14 @@
      * @throws MediaCasStateException for CAS-specific state exceptions.
      */
     public Session openSession() throws MediaCasException {
-        int sessionResourceHandle = getSessionResourceHandle();
+        long sessionResourceHandle = getSessionResourceHandle();
 
         try {
             if (mICas != null) {
                 try {
                     byte[] sessionId = mICas.openSessionDefault();
                     Session session = createFromSessionId(sessionId);
+                    addSessionToResourceMap(session, sessionResourceHandle);
                     Log.d(TAG, "Write Stats Log for succeed to Open Session.");
                     FrameworkStatsLog.write(
                             FrameworkStatsLog.TV_CAS_SESSION_OPEN_STATUS,
@@ -1238,7 +1262,7 @@
     @Nullable
     public Session openSession(@SessionUsage int sessionUsage, @ScramblingMode int scramblingMode)
             throws MediaCasException {
-        int sessionResourceHandle = getSessionResourceHandle();
+        long sessionResourceHandle = getSessionResourceHandle();
 
         if (mICas != null) {
             try {
diff --git a/media/java/android/media/MediaMuxer.java b/media/java/android/media/MediaMuxer.java
index 80b606c..5e55f64 100644
--- a/media/java/android/media/MediaMuxer.java
+++ b/media/java/android/media/MediaMuxer.java
@@ -34,7 +34,7 @@
 
 /**
  * MediaMuxer facilitates muxing elementary streams. Currently MediaMuxer supports MP4, Webm
- * and 3GP file as the output. It also supports muxing B-frames in MP4 since Android Nougat.
+ * and 3GP file as the output. It also supports muxing B-frames in MP4 since Android Nougat MR1.
  * <p>
  * It is generally used like this:
  *
@@ -191,14 +191,14 @@
     <td>&#9675;</td>
     <td>&#9679;</td>
    </tr>
-    <td align="center">Muxing B-Frames(bi-directional predicted frames)</td>
+    <td align="center">Muxing B-Frames (bi-directional predicted frames)</td>
     <td>&#9675;</td>
     <td>&#9675;</td>
     <td>&#9675;</td>
     <td>&#9675;</td>
     <td>&#9675;</td>
     <td>&#9675;</td>
-    <td>&#8277;</td>
+    <td>&#9675;</td>
     <td>&#8277;</td>
     <td>&#8277;</td>
    </tr>
diff --git a/media/java/android/media/flags/media_better_together.aconfig b/media/java/android/media/flags/media_better_together.aconfig
index 7252135..1ef98f2 100644
--- a/media/java/android/media/flags/media_better_together.aconfig
+++ b/media/java/android/media/flags/media_better_together.aconfig
@@ -70,6 +70,13 @@
 }
 
 flag {
+    name: "update_client_profile_priority"
+    namespace: "media"
+    description : "Feature flag to add updateResourcePriority api to MediaCas"
+    bug: "300565729"
+}
+
+flag {
      name: "enable_built_in_speaker_route_suitability_statuses"
      is_exported: true
      namespace: "media_solutions"
diff --git a/media/java/android/media/session/PlaybackState.java b/media/java/android/media/session/PlaybackState.java
index 47637b8..290d49b 100644
--- a/media/java/android/media/session/PlaybackState.java
+++ b/media/java/android/media/session/PlaybackState.java
@@ -15,10 +15,8 @@
  */
 package android.media.session;
 
-import static com.android.media.flags.Flags.FLAG_ENABLE_NOTIFYING_ACTIVITY_MANAGER_WITH_MEDIA_SESSION_STATUS_CHANGE;
 
 import android.annotation.DrawableRes;
-import android.annotation.FlaggedApi;
 import android.annotation.IntDef;
 import android.annotation.LongDef;
 import android.annotation.Nullable;
@@ -187,13 +185,21 @@
      */
     public static final long ACTION_SET_PLAYBACK_SPEED = 1 << 22;
 
-    /**
-     * @hide
-     */
-    @IntDef({STATE_NONE, STATE_STOPPED, STATE_PAUSED, STATE_PLAYING, STATE_FAST_FORWARDING,
-            STATE_REWINDING, STATE_BUFFERING, STATE_ERROR, STATE_CONNECTING,
-            STATE_SKIPPING_TO_PREVIOUS, STATE_SKIPPING_TO_NEXT, STATE_SKIPPING_TO_QUEUE_ITEM,
-            STATE_PLAYBACK_SUPPRESSED})
+    /** @hide */
+    @IntDef({
+        STATE_NONE,
+        STATE_STOPPED,
+        STATE_PAUSED,
+        STATE_PLAYING,
+        STATE_FAST_FORWARDING,
+        STATE_REWINDING,
+        STATE_BUFFERING,
+        STATE_ERROR,
+        STATE_CONNECTING,
+        STATE_SKIPPING_TO_PREVIOUS,
+        STATE_SKIPPING_TO_NEXT,
+        STATE_SKIPPING_TO_QUEUE_ITEM
+    })
     @Retention(RetentionPolicy.SOURCE)
     public @interface State {}
 
@@ -290,19 +296,6 @@
     public static final int STATE_SKIPPING_TO_QUEUE_ITEM = 11;
 
     /**
-     * State indicating that playback is paused due to an external transient interruption, like a
-     * phone call.
-     *
-     * <p>This state is different from {@link #STATE_PAUSED} in that it is deemed transitory,
-     * possibly allowing the service associated to the session in this state to run in the
-     * foreground.
-     *
-     * @see Builder#setState
-     */
-    @FlaggedApi(FLAG_ENABLE_NOTIFYING_ACTIVITY_MANAGER_WITH_MEDIA_SESSION_STATUS_CHANGE)
-    public static final int STATE_PLAYBACK_SUPPRESSED = 12;
-
-    /**
      * Use this value for the position to indicate the position is not known.
      */
     public static final long PLAYBACK_POSITION_UNKNOWN = -1;
@@ -401,7 +394,6 @@
      * <li> {@link PlaybackState#STATE_SKIPPING_TO_PREVIOUS}</li>
      * <li> {@link PlaybackState#STATE_SKIPPING_TO_NEXT}</li>
      * <li> {@link PlaybackState#STATE_SKIPPING_TO_QUEUE_ITEM}</li>
-     * <li> {@link PlaybackState#STATE_PLAYBACK_SUPPRESSED}</li>
      * </ul>
      */
     @State
@@ -525,7 +517,6 @@
      * <li>{@link #STATE_SKIPPING_TO_NEXT}</li>
      * <li>{@link #STATE_SKIPPING_TO_PREVIOUS}</li>
      * <li>{@link #STATE_SKIPPING_TO_QUEUE_ITEM}</li>
-     * <li>{@link #STATE_PLAYBACK_SUPPRESSED}</li>
      * </ul>
      */
     public boolean isActive() {
@@ -538,7 +529,6 @@
             case PlaybackState.STATE_BUFFERING:
             case PlaybackState.STATE_CONNECTING:
             case PlaybackState.STATE_PLAYING:
-            case PlaybackState.STATE_PLAYBACK_SUPPRESSED:
                 return true;
         }
         return false;
@@ -584,8 +574,6 @@
                 return "SKIPPING_TO_NEXT";
             case STATE_SKIPPING_TO_QUEUE_ITEM:
                 return "SKIPPING_TO_QUEUE_ITEM";
-            case STATE_PLAYBACK_SUPPRESSED:
-                return "STATE_PLAYBACK_SUPPRESSED";
             default:
                 return "UNKNOWN";
         }
@@ -823,7 +811,6 @@
          * <li> {@link PlaybackState#STATE_SKIPPING_TO_PREVIOUS}</li>
          * <li> {@link PlaybackState#STATE_SKIPPING_TO_NEXT}</li>
          * <li> {@link PlaybackState#STATE_SKIPPING_TO_QUEUE_ITEM}</li>
-         * <li> {@link PlaybackState#STATE_PLAYBACK_SUPPRESSED}</li>
          * </ul>
          *
          * @param state The current state of playback.
@@ -868,7 +855,6 @@
          * <li> {@link PlaybackState#STATE_SKIPPING_TO_PREVIOUS}</li>
          * <li> {@link PlaybackState#STATE_SKIPPING_TO_NEXT}</li>
          * <li> {@link PlaybackState#STATE_SKIPPING_TO_QUEUE_ITEM}</li>
-         * <li> {@link PlaybackState#STATE_PLAYBACK_SUPPRESSED}</li>
          * </ul>
          *
          * @param state The current state of playback.
diff --git a/media/java/android/media/tv/flags/media_tv.aconfig b/media/java/android/media/tv/flags/media_tv.aconfig
index 10423b9..d49f7dd 100644
--- a/media/java/android/media/tv/flags/media_tv.aconfig
+++ b/media/java/android/media/tv/flags/media_tv.aconfig
@@ -64,3 +64,11 @@
     description: "Media Quality V1.0 APIs for Android W"
     bug: "348412562"
 }
+
+flag {
+    name: "tif_extension_standardization"
+    is_exported: true
+    namespace: "media_tv"
+    description: "Standardize AIDL Extension Interface of TIS"
+    bug: "330366987"
+}
\ No newline at end of file
diff --git a/media/java/android/media/tv/tuner/Tuner.java b/media/java/android/media/tv/tuner/Tuner.java
index 92f6eaf..cdf50ec 100644
--- a/media/java/android/media/tv/tuner/Tuner.java
+++ b/media/java/android/media/tv/tuner/Tuner.java
@@ -295,13 +295,13 @@
     private EventHandler mHandler;
     @Nullable
     private FrontendInfo mFrontendInfo;
-    private Integer mFrontendHandle;
+    private Long mFrontendHandle;
     private Tuner mFeOwnerTuner = null;
     private int mFrontendType = FrontendSettings.TYPE_UNDEFINED;
     private Integer mDesiredFrontendId = null;
     private int mUserId;
     private Lnb mLnb;
-    private Integer mLnbHandle;
+    private Long mLnbHandle;
     @Nullable
     private OnTuneEventListener mOnTuneEventListener;
     @Nullable
@@ -324,10 +324,10 @@
     private final ReentrantLock mDemuxLock = new ReentrantLock();
     private int mRequestedCiCamId;
 
-    private Integer mDemuxHandle;
-    private Integer mFrontendCiCamHandle;
+    private Long mDemuxHandle;
+    private Long mFrontendCiCamHandle;
     private Integer mFrontendCiCamId;
-    private Map<Integer, WeakReference<Descrambler>> mDescramblers = new HashMap<>();
+    private Map<Long, WeakReference<Descrambler>> mDescramblers = new HashMap<>();
     private List<WeakReference<Filter>> mFilters = new ArrayList<WeakReference<Filter>>();
 
     private final TunerResourceManager.ResourcesReclaimListener mResourceListener =
@@ -949,7 +949,7 @@
     private void releaseDescramblers() {
         synchronized (mDescramblers) {
             if (!mDescramblers.isEmpty()) {
-                for (Map.Entry<Integer, WeakReference<Descrambler>> d : mDescramblers.entrySet()) {
+                for (Map.Entry<Long, WeakReference<Descrambler>> d : mDescramblers.entrySet()) {
                     Descrambler descrambler = d.getValue().get();
                     if (descrambler != null) {
                         descrambler.close();
@@ -1010,7 +1010,7 @@
     /**
      * Native method to open frontend of the given ID.
      */
-    private native Frontend nativeOpenFrontendByHandle(int handle);
+    private native Frontend nativeOpenFrontendByHandle(long handle);
     private native int nativeShareFrontend(int id);
     private native int nativeUnshareFrontend();
     private native void nativeRegisterFeCbListener(long nativeContext);
@@ -1039,21 +1039,21 @@
     private native int nativeSetMaxNumberOfFrontends(int frontendType, int maxNumber);
     private native int nativeGetMaxNumberOfFrontends(int frontendType);
     private native int nativeRemoveOutputPid(int pid);
-    private native Lnb nativeOpenLnbByHandle(int handle);
+    private native Lnb nativeOpenLnbByHandle(long handle);
     private native Lnb nativeOpenLnbByName(String name);
     private native FrontendStatusReadiness[] nativeGetFrontendStatusReadiness(int[] statusTypes);
 
-    private native Descrambler nativeOpenDescramblerByHandle(int handle);
-    private native int nativeOpenDemuxByhandle(int handle);
+    private native Descrambler nativeOpenDescramblerByHandle(long handle);
+    private native int nativeOpenDemuxByhandle(long handle);
 
     private native DvrRecorder nativeOpenDvrRecorder(long bufferSize);
     private native DvrPlayback nativeOpenDvrPlayback(long bufferSize);
 
     private native DemuxCapabilities nativeGetDemuxCapabilities();
-    private native DemuxInfo nativeGetDemuxInfo(int demuxHandle);
+    private native DemuxInfo nativeGetDemuxInfo(long demuxHandle);
 
-    private native int nativeCloseDemux(int handle);
-    private native int nativeCloseFrontend(int handle);
+    private native int nativeCloseDemux(long handle);
+    private native int nativeCloseFrontend(long handle);
     private native int nativeClose();
 
     private static native SharedFilter nativeOpenSharedFilter(String token);
@@ -1371,7 +1371,7 @@
     }
 
     private boolean requestFrontend() {
-        int[] feHandle = new int[1];
+        long[] feHandle = new long[1];
         boolean granted = false;
         try {
             TunerFrontendRequest request = new TunerFrontendRequest();
@@ -2379,7 +2379,7 @@
     }
 
     private boolean requestLnb() {
-        int[] lnbHandle = new int[1];
+        long[] lnbHandle = new long[1];
         TunerLnbRequest request = new TunerLnbRequest();
         request.clientId = mClientId;
         boolean granted = mTunerResourceManager.requestLnb(request, lnbHandle);
@@ -2709,7 +2709,7 @@
     }
 
     private boolean requestDemux() {
-        int[] demuxHandle = new int[1];
+        long[] demuxHandle = new long[1];
         TunerDemuxRequest request = new TunerDemuxRequest();
         request.clientId = mClientId;
         request.desiredFilterTypes = mDesiredDemuxInfo.getFilterTypes();
@@ -2722,14 +2722,14 @@
     }
 
     private Descrambler requestDescrambler() {
-        int[] descramblerHandle = new int[1];
+        long[] descramblerHandle = new long[1];
         TunerDescramblerRequest request = new TunerDescramblerRequest();
         request.clientId = mClientId;
         boolean granted = mTunerResourceManager.requestDescrambler(request, descramblerHandle);
         if (!granted) {
             return null;
         }
-        int handle = descramblerHandle[0];
+        long handle = descramblerHandle[0];
         Descrambler descrambler = nativeOpenDescramblerByHandle(handle);
         if (descrambler != null) {
             synchronized (mDescramblers) {
@@ -2743,7 +2743,7 @@
     }
 
     private boolean requestFrontendCiCam(int ciCamId) {
-        int[] ciCamHandle = new int[1];
+        long[] ciCamHandle = new long[1];
         TunerCiCamRequest request = new TunerCiCamRequest();
         request.clientId = mClientId;
         request.ciCamId = ciCamId;
diff --git a/media/java/android/media/tv/tuner/filter/MediaEvent.java b/media/java/android/media/tv/tuner/filter/MediaEvent.java
index 4676dff..84a13ab 100644
--- a/media/java/android/media/tv/tuner/filter/MediaEvent.java
+++ b/media/java/android/media/tv/tuner/filter/MediaEvent.java
@@ -17,12 +17,14 @@
 package android.media.tv.tuner.filter;
 
 import android.annotation.BytesLong;
+import android.annotation.FlaggedApi;
 import android.annotation.IntRange;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.media.AudioPresentation;
 import android.media.MediaCodec.LinearBlock;
+import android.media.tv.flags.Flags;
 
 import java.util.Collections;
 import java.util.List;
@@ -57,12 +59,16 @@
     private final int mScIndexMask;
     private final AudioDescriptor mExtraMetaData;
     private final List<AudioPresentation> mAudioPresentations;
+    private final int mNumDataPieces;
+    private final int mIndexInDataGroup;
+    private final int mDataGroupId;
 
     // This constructor is used by JNI code only
     private MediaEvent(int streamId, boolean isPtsPresent, long pts, boolean isDtsPresent, long dts,
             long dataLength, long offset, LinearBlock buffer, boolean isSecureMemory, long dataId,
             int mpuSequenceNumber, boolean isPrivateData, int scIndexMask,
-            AudioDescriptor extraMetaData, List<AudioPresentation> audioPresentations) {
+            AudioDescriptor extraMetaData, List<AudioPresentation> audioPresentations,
+            int numDataPieces, int indexInDataGroup, int dataGroupId) {
         mStreamId = streamId;
         mIsPtsPresent = isPtsPresent;
         mPts = pts;
@@ -78,6 +84,9 @@
         mScIndexMask = scIndexMask;
         mExtraMetaData = extraMetaData;
         mAudioPresentations = audioPresentations;
+        mNumDataPieces = numDataPieces;
+        mIndexInDataGroup = indexInDataGroup;
+        mDataGroupId = dataGroupId;
     }
 
     /**
@@ -235,6 +244,67 @@
     }
 
     /**
+     * Gets the number of data pieces into which the original data was split.
+     *
+     * <p>The {@link #getNumDataPieces()}, {@link #getIndexInDataGroup()} and
+     * {@link #getDataGroupId()} methods should be used together to reassemble the original data if
+     * it was split into pieces. Use {@link #getLinearBlock()} to get the memory where the data
+     * pieces are stored.
+     *
+     * @return 0 or 1 if this MediaEvent object contains the complete data; otherwise the number of
+     *         pieces into which the original data was split.
+     * @see #getIndexInDataGroup()
+     * @see #getDataGroupId()
+     * @see #getLinearBlock()
+     */
+    @FlaggedApi(Flags.FLAG_TUNER_W_APIS)
+    @IntRange(from = 0)
+    public int getNumDataPieces() {
+        return mNumDataPieces;
+    }
+
+    /**
+     * Gets the index of the data piece. The index in the data group indicates the order in which
+     * this {@link MediaEvent}'s data piece should be reassembled. The result should be within the
+     * range [0, {@link #getNumDataPieces()}).
+     *
+     * <p>The {@link #getNumDataPieces()}, {@link #getIndexInDataGroup()} and
+     * {@link #getDataGroupId()} methods should be used together to reassemble the original data if
+     * it was split into pieces. Use {@link #getLinearBlock()} to get the memory where the data
+     * pieces are stored.
+     *
+     * @return The index in the data group.
+     * @see #getNumDataPieces()
+     * @see #getDataGroupId()
+     * @see #getLinearBlock()
+     */
+    @FlaggedApi(Flags.FLAG_TUNER_W_APIS)
+    @IntRange(from = 0)
+    public int getIndexInDataGroup() {
+        return mIndexInDataGroup;
+    }
+
+    /**
+     * Gets the group ID for reassembling the complete data. {@link MediaEvent}s that have the same
+     * data group ID contain different pieces of the same data. This value should be ignored if
+     * {@link #getNumDataPieces()} returns 0 or 1.
+     *
+     * <p>The {@link #getNumDataPieces()}, {@link #getIndexInDataGroup()} and
+     * {@link #getDataGroupId()} methods should be used together to reassemble the original data if
+     * it was split into pieces. Use {@link #getLinearBlock()} to get the memory where the data
+     * pieces are stored.
+     *
+     * @return The data group ID.
+     * @see #getNumDataPieces()
+     * @see #getIndexInDataGroup()
+     * @see #getLinearBlock()
+     */
+    @FlaggedApi(Flags.FLAG_TUNER_W_APIS)
+    public int getDataGroupId() {
+        return mDataGroupId;
+    }
+
+    /**
      * Finalize the MediaEvent object.
      * @hide
      */
diff --git a/media/java/android/media/tv/tunerresourcemanager/TunerResourceManager.java b/media/java/android/media/tv/tunerresourcemanager/TunerResourceManager.java
index d268aeb..bb581eb 100644
--- a/media/java/android/media/tv/tunerresourcemanager/TunerResourceManager.java
+++ b/media/java/android/media/tv/tunerresourcemanager/TunerResourceManager.java
@@ -66,7 +66,7 @@
     private static final String TAG = "TunerResourceManager";
     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
 
-    public static final int INVALID_RESOURCE_HANDLE = -1;
+    public static final long INVALID_RESOURCE_HANDLE = -1;
     public static final int INVALID_OWNER_ID = -1;
     /**
      * Tuner resource type to help generate resource handle
@@ -275,7 +275,7 @@
      * Updates the current TRM of the TunerHAL Frontend information.
      *
      * <p><strong>Note:</strong> This update must happen before the first
-     * {@link #requestFrontend(TunerFrontendRequest, int[])} and
+     * {@link #requestFrontend(TunerFrontendRequest, long[])} and
      * {@link #releaseFrontend(int, int)} call.
      *
      * @param infos an array of the available {@link TunerFrontendInfo} information.
@@ -331,7 +331,7 @@
      *
      * @param lnbIds ids of the updating lnbs.
      */
-    public void setLnbInfoList(int[] lnbIds) {
+    public void setLnbInfoList(long[] lnbIds) {
         try {
             mService.setLnbInfoList(lnbIds);
         } catch (RemoteException e) {
@@ -406,8 +406,8 @@
      *
      * @return true if there is frontend granted.
      */
-    public boolean requestFrontend(@NonNull TunerFrontendRequest request,
-                @Nullable int[] frontendHandle) {
+    public boolean requestFrontend(
+            @NonNull TunerFrontendRequest request, @Nullable long[] frontendHandle) {
         boolean result = false;
         try {
             result = mService.requestFrontend(request, frontendHandle);
@@ -511,7 +511,7 @@
      *
      * @return true if there is Demux granted.
      */
-    public boolean requestDemux(@NonNull TunerDemuxRequest request, @NonNull int[] demuxHandle) {
+    public boolean requestDemux(@NonNull TunerDemuxRequest request, @NonNull long[] demuxHandle) {
         boolean result = false;
         try {
             result = mService.requestDemux(request, demuxHandle);
@@ -544,8 +544,8 @@
      *
      * @return true if there is Descrambler granted.
      */
-    public boolean requestDescrambler(@NonNull TunerDescramblerRequest request,
-                @NonNull int[] descramblerHandle) {
+    public boolean requestDescrambler(
+            @NonNull TunerDescramblerRequest request, @NonNull long[] descramblerHandle) {
         boolean result = false;
         try {
             result = mService.requestDescrambler(request, descramblerHandle);
@@ -577,8 +577,8 @@
      *
      * @return true if there is CAS session granted.
      */
-    public boolean requestCasSession(@NonNull CasSessionRequest request,
-                @NonNull int[] casSessionHandle) {
+    public boolean requestCasSession(
+            @NonNull CasSessionRequest request, @NonNull long[] casSessionHandle) {
         boolean result = false;
         try {
             result = mService.requestCasSession(request, casSessionHandle);
@@ -610,7 +610,7 @@
      *
      * @return true if there is ciCam granted.
      */
-    public boolean requestCiCam(TunerCiCamRequest request, int[] ciCamHandle) {
+    public boolean requestCiCam(TunerCiCamRequest request, long[] ciCamHandle) {
         boolean result = false;
         try {
             result = mService.requestCiCam(request, ciCamHandle);
@@ -635,7 +635,7 @@
      * <li>If no Lnb system can be granted, the API would return false.
      * <ul>
      *
-     * <p><strong>Note:</strong> {@link #setLnbInfoList(int[])} must be called before this request.
+     * <p><strong>Note:</strong> {@link #setLnbInfoList(long[])} must be called before this request.
      *
      * @param request {@link TunerLnbRequest} information of the current request.
      * @param lnbHandle a one-element array to return the granted Lnb handle.
@@ -643,7 +643,7 @@
      *
      * @return true if there is Lnb granted.
      */
-    public boolean requestLnb(@NonNull TunerLnbRequest request, @NonNull int[] lnbHandle) {
+    public boolean requestLnb(@NonNull TunerLnbRequest request, @NonNull long[] lnbHandle) {
         boolean result = false;
         try {
             result = mService.requestLnb(request, lnbHandle);
@@ -664,7 +664,7 @@
      * @param frontendHandle the handle of the released frontend.
      * @param clientId the id of the client that is releasing the frontend.
      */
-    public void releaseFrontend(int frontendHandle, int clientId) {
+    public void releaseFrontend(long frontendHandle, int clientId) {
         try {
             mService.releaseFrontend(frontendHandle, clientId);
         } catch (RemoteException e) {
@@ -680,7 +680,7 @@
      * @param demuxHandle the handle of the released Tuner Demux.
      * @param clientId the id of the client that is releasing the demux.
      */
-    public void releaseDemux(int demuxHandle, int clientId) {
+    public void releaseDemux(long demuxHandle, int clientId) {
         try {
             mService.releaseDemux(demuxHandle, clientId);
         } catch (RemoteException e) {
@@ -696,7 +696,7 @@
      * @param descramblerHandle the handle of the released Tuner Descrambler.
      * @param clientId the id of the client that is releasing the descrambler.
      */
-    public void releaseDescrambler(int descramblerHandle, int clientId) {
+    public void releaseDescrambler(long descramblerHandle, int clientId) {
         try {
             mService.releaseDescrambler(descramblerHandle, clientId);
         } catch (RemoteException e) {
@@ -715,7 +715,7 @@
      * @param casSessionHandle the handle of the released CAS session.
      * @param clientId the id of the client that is releasing the cas session.
      */
-    public void releaseCasSession(int casSessionHandle, int clientId) {
+    public void releaseCasSession(long casSessionHandle, int clientId) {
         try {
             mService.releaseCasSession(casSessionHandle, clientId);
         } catch (RemoteException e) {
@@ -734,7 +734,7 @@
      * @param ciCamHandle the handle of the releasing CiCam.
      * @param clientId the id of the client that is releasing the CiCam.
      */
-    public void releaseCiCam(int ciCamHandle, int clientId) {
+    public void releaseCiCam(long ciCamHandle, int clientId) {
         try {
             mService.releaseCiCam(ciCamHandle, clientId);
         } catch (RemoteException e) {
@@ -747,12 +747,12 @@
      *
      * <p>Client must call this whenever it releases an Lnb.
      *
-     * <p><strong>Note:</strong> {@link #setLnbInfoList(int[])} must be called before this release.
+     * <p><strong>Note:</strong> {@link #setLnbInfoList(long[])} must be called before this release.
      *
      * @param lnbHandle the handle of the released Tuner Lnb.
      * @param clientId the id of the client that is releasing the lnb.
      */
-    public void releaseLnb(int lnbHandle, int clientId) {
+    public void releaseLnb(long lnbHandle, int clientId) {
         try {
             mService.releaseLnb(lnbHandle, clientId);
         } catch (RemoteException e) {
diff --git a/media/java/android/media/tv/tunerresourcemanager/aidl/android/media/tv/tunerresourcemanager/ITunerResourceManager.aidl b/media/java/android/media/tv/tunerresourcemanager/aidl/android/media/tv/tunerresourcemanager/ITunerResourceManager.aidl
index 5399697..109c791 100644
--- a/media/java/android/media/tv/tunerresourcemanager/aidl/android/media/tv/tunerresourcemanager/ITunerResourceManager.aidl
+++ b/media/java/android/media/tv/tunerresourcemanager/aidl/android/media/tv/tunerresourcemanager/ITunerResourceManager.aidl
@@ -149,7 +149,7 @@
      *
      * @param lnbIds ids of the updating lnbs.
      */
-    void setLnbInfoList(in int[] lnbIds);
+    void setLnbInfoList(in long[] lnbIds);
 
     /*
      * This API is used by the Tuner framework to request a frontend from the TunerHAL.
@@ -185,7 +185,7 @@
      *
      * @return true if there is frontend granted.
      */
-    boolean requestFrontend(in TunerFrontendRequest request, out int[] frontendHandle);
+    boolean requestFrontend(in TunerFrontendRequest request, out long[] frontendHandle);
 
     /*
      * Sets the maximum usable frontends number of a given frontend type. It is used to enable or
@@ -253,7 +253,7 @@
      *
      * @return true if there is demux granted.
      */
-    boolean requestDemux(in TunerDemuxRequest request, out int[] demuxHandle);
+    boolean requestDemux(in TunerDemuxRequest request, out long[] demuxHandle);
 
     /*
      * This API is used by the Tuner framework to request an available descrambler from the
@@ -277,7 +277,7 @@
      *
      * @return true if there is Descrambler granted.
      */
-    boolean requestDescrambler(in TunerDescramblerRequest request, out int[] descramblerHandle);
+    boolean requestDescrambler(in TunerDescramblerRequest request, out long[] descramblerHandle);
 
     /*
      * This API is used by the Tuner framework to request an available Cas session. This session
@@ -303,7 +303,7 @@
      *
      * @return true if there is CAS session granted.
      */
-    boolean requestCasSession(in CasSessionRequest request, out int[] casSessionHandle);
+    boolean requestCasSession(in CasSessionRequest request, out long[] casSessionHandle);
 
     /*
      * This API is used by the Tuner framework to request an available CuCam.
@@ -328,7 +328,7 @@
      *
      * @return true if there is CiCam granted.
      */
-    boolean requestCiCam(in TunerCiCamRequest request, out int[] ciCamHandle);
+    boolean requestCiCam(in TunerCiCamRequest request, out long[] ciCamHandle);
 
     /*
      * This API is used by the Tuner framework to request an available Lnb from the TunerHAL.
@@ -352,7 +352,7 @@
      *
      * @return true if there is Lnb granted.
      */
-    boolean requestLnb(in TunerLnbRequest request, out int[] lnbHandle);
+    boolean requestLnb(in TunerLnbRequest request, out long[] lnbHandle);
 
     /*
      * Notifies the TRM that the given frontend has been released.
@@ -365,7 +365,7 @@
      * @param frontendHandle the handle of the released frontend.
      * @param clientId the id of the client that is releasing the frontend.
      */
-    void releaseFrontend(in int frontendHandle, int clientId);
+    void releaseFrontend(in long frontendHandle, int clientId);
 
     /*
      * Notifies the TRM that the Demux with the given handle was released.
@@ -375,7 +375,7 @@
      * @param demuxHandle the handle of the released Tuner Demux.
      * @param clientId the id of the client that is releasing the demux.
      */
-    void releaseDemux(in int demuxHandle, int clientId);
+    void releaseDemux(in long demuxHandle, int clientId);
 
     /*
      * Notifies the TRM that the Descrambler with the given handle was released.
@@ -385,7 +385,7 @@
      * @param descramblerHandle the handle of the released Tuner Descrambler.
      * @param clientId the id of the client that is releasing the descrambler.
      */
-    void releaseDescrambler(in int descramblerHandle, int clientId);
+    void releaseDescrambler(in long descramblerHandle, int clientId);
 
     /*
      * Notifies the TRM that the given Cas session has been released.
@@ -397,7 +397,7 @@
      * @param casSessionHandle the handle of the released CAS session.
      * @param clientId the id of the client that is releasing the cas session.
      */
-    void releaseCasSession(in int casSessionHandle, int clientId);
+    void releaseCasSession(in long casSessionHandle, int clientId);
 
     /**
      * Notifies the TRM that the given CiCam has been released.
@@ -410,7 +410,7 @@
      * @param ciCamHandle the handle of the releasing CiCam.
      * @param clientId the id of the client that is releasing the CiCam.
      */
-    void releaseCiCam(in int ciCamHandle, int clientId);
+    void releaseCiCam(in long ciCamHandle, int clientId);
 
     /*
      * Notifies the TRM that the Lnb with the given handle was released.
@@ -422,7 +422,7 @@
      * @param lnbHandle the handle of the released Tuner Lnb.
      * @param clientId the id of the client that is releasing the lnb.
      */
-    void releaseLnb(in int lnbHandle, int clientId);
+    void releaseLnb(in long lnbHandle, int clientId);
 
     /*
      * Compare two clients' priority.
diff --git a/media/java/android/media/tv/tunerresourcemanager/aidl/android/media/tv/tunerresourcemanager/TunerDemuxInfo.aidl b/media/java/android/media/tv/tunerresourcemanager/aidl/android/media/tv/tunerresourcemanager/TunerDemuxInfo.aidl
index c14caf5..7984c38 100644
--- a/media/java/android/media/tv/tunerresourcemanager/aidl/android/media/tv/tunerresourcemanager/TunerDemuxInfo.aidl
+++ b/media/java/android/media/tv/tunerresourcemanager/aidl/android/media/tv/tunerresourcemanager/TunerDemuxInfo.aidl
@@ -26,7 +26,7 @@
     /**
      * Demux handle
      */
-    int handle;
+    long handle;
 
     /**
      * Supported filter types (defined in {@link android.media.tv.tuner.filter.Filter})
diff --git a/media/java/android/media/tv/tunerresourcemanager/aidl/android/media/tv/tunerresourcemanager/TunerFrontendInfo.aidl b/media/java/android/media/tv/tunerresourcemanager/aidl/android/media/tv/tunerresourcemanager/TunerFrontendInfo.aidl
index 8981ce0..274367e 100644
--- a/media/java/android/media/tv/tunerresourcemanager/aidl/android/media/tv/tunerresourcemanager/TunerFrontendInfo.aidl
+++ b/media/java/android/media/tv/tunerresourcemanager/aidl/android/media/tv/tunerresourcemanager/TunerFrontendInfo.aidl
@@ -26,7 +26,7 @@
     /**
      * Frontend Handle
      */
-    int handle;
+    long handle;
 
     /**
      * Frontend Type
diff --git a/media/jni/android_media_tv_Tuner.cpp b/media/jni/android_media_tv_Tuner.cpp
index 00b0e57..9e1e2c3 100644
--- a/media/jni/android_media_tv_Tuner.cpp
+++ b/media/jni/android_media_tv_Tuner.cpp
@@ -686,12 +686,16 @@
     } else if (mediaEvent.scIndexMask.getTag() == DemuxFilterScIndexMask::Tag::scVvc) {
         sc = mediaEvent.scIndexMask.get<DemuxFilterScIndexMask::Tag::scVvc>();
     }
+    jint numDataPieces = mediaEvent.numDataPieces;
+    jint indexInDataGroup = mediaEvent.indexInDataGroup;
+    jint dataGroupId = mediaEvent.dataGroupId;
 
     ScopedLocalRef obj(env, env->NewObject(mMediaEventClass, mMediaEventInitID, streamId,
                                            isPtsPresent, pts, isDtsPresent, dts, dataLength,
                                            offset, nullptr, isSecureMemory, avDataId,
                                            mpuSequenceNumber, isPesPrivateData, sc,
-                                           audioDescriptor.get(), presentationsJObj.get()));
+                                           audioDescriptor.get(), presentationsJObj.get(),
+                                           numDataPieces, indexInDataGroup, dataGroupId));
 
     // Protect mFilterClient from being set to null.
     android::Mutex::Autolock autoLock(mLock);
@@ -1048,7 +1052,7 @@
             "<init>",
             "(IZJZJJJLandroid/media/MediaCodec$LinearBlock;"
             "ZJIZILandroid/media/tv/tuner/filter/AudioDescriptor;"
-            "Ljava/util/List;)V");
+            "Ljava/util/List;III)V");
     mAudioDescriptorInitID = env->GetMethodID(mAudioDescriptorClass, "<init>", "(BBCBBB)V");
     mPesEventInitID = env->GetMethodID(mPesEventClass, "<init>", "(III)V");
     mTsRecordEventInitID = env->GetMethodID(mTsRecordEventClass, "<init>", "(IIIJJI)V");
@@ -1448,7 +1452,7 @@
     return obj;
 }
 
-jobject JTuner::openFrontendByHandle(int feHandle) {
+jobject JTuner::openFrontendByHandle(jlong feHandle) {
     // TODO: Handle reopening frontend with different handle
     sp<FrontendClient> feClient = sTunerClient->openFrontend(feHandle);
     if (feClient == nullptr) {
@@ -1824,7 +1828,7 @@
     return valObj;
 }
 
-jobject JTuner::openLnbByHandle(int handle) {
+jobject JTuner::openLnbByHandle(jlong handle) {
     if (sTunerClient == nullptr) {
         return nullptr;
     }
@@ -1833,7 +1837,7 @@
     sp<LnbClientCallbackImpl> callback = new LnbClientCallbackImpl();
     lnbClient = sTunerClient->openLnb(handle);
     if (lnbClient == nullptr) {
-        ALOGD("Failed to open lnb, handle = %d", handle);
+        ALOGD("Failed to open lnb, handle = %s", std::to_string(handle).c_str());
         return nullptr;
     }
 
@@ -1947,7 +1951,7 @@
     return (int)result;
 }
 
-Result JTuner::openDemux(int handle) {
+Result JTuner::openDemux(jlong handle) {
     if (sTunerClient == nullptr) {
         return Result::NOT_INITIALIZED;
     }
@@ -2215,7 +2219,7 @@
             numBytesInSectionFilter, filterCaps, filterCapsList, linkCaps, bTimeFilter);
 }
 
-jobject JTuner::getDemuxInfo(int handle) {
+jobject JTuner::getDemuxInfo(jlong handle) {
     if (sTunerClient == nullptr) {
         ALOGE("tuner is not initialized");
         return nullptr;
@@ -3768,8 +3772,8 @@
     return tuner->getFrontendIds();
 }
 
-static jobject android_media_tv_Tuner_open_frontend_by_handle(
-        JNIEnv *env, jobject thiz, jint handle) {
+static jobject android_media_tv_Tuner_open_frontend_by_handle(JNIEnv *env, jobject thiz,
+                                                              jlong handle) {
     sp<JTuner> tuner = getTuner(env, thiz);
     return tuner->openFrontendByHandle(handle);
 }
@@ -3901,7 +3905,7 @@
     return tuner->getFrontendInfo(id);
 }
 
-static jobject android_media_tv_Tuner_open_lnb_by_handle(JNIEnv *env, jobject thiz, jint handle) {
+static jobject android_media_tv_Tuner_open_lnb_by_handle(JNIEnv *env, jobject thiz, jlong handle) {
     sp<JTuner> tuner = getTuner(env, thiz);
     return tuner->openLnbByHandle(handle);
 }
@@ -4622,7 +4626,7 @@
     return (int)r;
 }
 
-static jobject android_media_tv_Tuner_open_descrambler(JNIEnv *env, jobject thiz, jint) {
+static jobject android_media_tv_Tuner_open_descrambler(JNIEnv *env, jobject thiz, jlong) {
     sp<JTuner> tuner = getTuner(env, thiz);
     return tuner->openDescrambler();
 }
@@ -4690,12 +4694,12 @@
     return tuner->getDemuxCaps();
 }
 
-static jobject android_media_tv_Tuner_get_demux_info(JNIEnv* env, jobject thiz, jint handle) {
+static jobject android_media_tv_Tuner_get_demux_info(JNIEnv *env, jobject thiz, jlong handle) {
     sp<JTuner> tuner = getTuner(env, thiz);
     return tuner->getDemuxInfo(handle);
 }
 
-static jint android_media_tv_Tuner_open_demux(JNIEnv* env, jobject thiz, jint handle) {
+static jint android_media_tv_Tuner_open_demux(JNIEnv *env, jobject thiz, jlong handle) {
     sp<JTuner> tuner = getTuner(env, thiz);
     return (jint)tuner->openDemux(handle);
 }
@@ -4706,7 +4710,7 @@
     return (jint)tuner->close();
 }
 
-static jint android_media_tv_Tuner_close_demux(JNIEnv* env, jobject thiz, jint /* handle */) {
+static jint android_media_tv_Tuner_close_demux(JNIEnv *env, jobject thiz, jlong /* handle */) {
     sp<JTuner> tuner = getTuner(env, thiz);
     return tuner->closeDemux();
 }
@@ -4766,7 +4770,7 @@
     return tuner->getFrontendStatusReadiness(types);
 }
 
-static jint android_media_tv_Tuner_close_frontend(JNIEnv* env, jobject thiz, jint /* handle */) {
+static jint android_media_tv_Tuner_close_frontend(JNIEnv *env, jobject thiz, jlong /* handle */) {
     sp<JTuner> tuner = getTuner(env, thiz);
     return tuner->closeFrontend();
 }
@@ -5035,7 +5039,7 @@
     { "nativeGetTunerVersion", "()I", (void *)android_media_tv_Tuner_native_get_tuner_version },
     { "nativeGetFrontendIds", "()Ljava/util/List;",
             (void *)android_media_tv_Tuner_get_frontend_ids },
-    { "nativeOpenFrontendByHandle", "(I)Landroid/media/tv/tuner/Tuner$Frontend;",
+    { "nativeOpenFrontendByHandle", "(J)Landroid/media/tv/tuner/Tuner$Frontend;",
             (void *)android_media_tv_Tuner_open_frontend_by_handle },
     { "nativeShareFrontend", "(I)I",
             (void *)android_media_tv_Tuner_share_frontend },
@@ -5074,11 +5078,11 @@
             (void *)android_media_tv_Tuner_open_filter },
     { "nativeOpenTimeFilter", "()Landroid/media/tv/tuner/filter/TimeFilter;",
             (void *)android_media_tv_Tuner_open_time_filter },
-    { "nativeOpenLnbByHandle", "(I)Landroid/media/tv/tuner/Lnb;",
+    { "nativeOpenLnbByHandle", "(J)Landroid/media/tv/tuner/Lnb;",
             (void *)android_media_tv_Tuner_open_lnb_by_handle },
     { "nativeOpenLnbByName", "(Ljava/lang/String;)Landroid/media/tv/tuner/Lnb;",
             (void *)android_media_tv_Tuner_open_lnb_by_name },
-    { "nativeOpenDescramblerByHandle", "(I)Landroid/media/tv/tuner/Descrambler;",
+    { "nativeOpenDescramblerByHandle", "(J)Landroid/media/tv/tuner/Descrambler;",
             (void *)android_media_tv_Tuner_open_descrambler },
     { "nativeOpenDvrRecorder", "(J)Landroid/media/tv/tuner/dvr/DvrRecorder;",
             (void *)android_media_tv_Tuner_open_dvr_recorder },
@@ -5086,12 +5090,12 @@
             (void *)android_media_tv_Tuner_open_dvr_playback },
     { "nativeGetDemuxCapabilities", "()Landroid/media/tv/tuner/DemuxCapabilities;",
             (void *)android_media_tv_Tuner_get_demux_caps },
-    { "nativeGetDemuxInfo", "(I)Landroid/media/tv/tuner/DemuxInfo;",
+    { "nativeGetDemuxInfo", "(J)Landroid/media/tv/tuner/DemuxInfo;",
             (void *)android_media_tv_Tuner_get_demux_info },
-    { "nativeOpenDemuxByhandle", "(I)I", (void *)android_media_tv_Tuner_open_demux },
+    { "nativeOpenDemuxByhandle", "(J)I", (void *)android_media_tv_Tuner_open_demux },
     { "nativeClose", "()I", (void *)android_media_tv_Tuner_close_tuner },
-    { "nativeCloseFrontend", "(I)I", (void *)android_media_tv_Tuner_close_frontend },
-    { "nativeCloseDemux", "(I)I", (void *)android_media_tv_Tuner_close_demux },
+    { "nativeCloseFrontend", "(J)I", (void *)android_media_tv_Tuner_close_frontend },
+    { "nativeCloseDemux", "(J)I", (void *)android_media_tv_Tuner_close_demux },
     { "nativeOpenSharedFilter",
             "(Ljava/lang/String;)Landroid/media/tv/tuner/filter/SharedFilter;",
             (void *)android_media_tv_Tuner_open_shared_filter},
diff --git a/media/jni/android_media_tv_Tuner.h b/media/jni/android_media_tv_Tuner.h
index 3de3ab9..7af2cd7 100644
--- a/media/jni/android_media_tv_Tuner.h
+++ b/media/jni/android_media_tv_Tuner.h
@@ -206,7 +206,7 @@
     int disconnectCiCam();
     int unlinkCiCam(jint id);
     jobject getFrontendIds();
-    jobject openFrontendByHandle(int feHandle);
+    jobject openFrontendByHandle(jlong feHandle);
     int shareFrontend(int feId);
     int unshareFrontend();
     void registerFeCbListener(JTuner* jtuner);
@@ -221,16 +221,16 @@
     int setLnb(sp<LnbClient> lnbClient);
     bool isLnaSupported();
     int setLna(bool enable);
-    jobject openLnbByHandle(int handle);
+    jobject openLnbByHandle(jlong handle);
     jobject openLnbByName(jstring name);
     jobject openFilter(DemuxFilterType type, int bufferSize);
     jobject openTimeFilter();
     jobject openDescrambler();
     jobject openDvr(DvrType type, jlong bufferSize);
     jobject getDemuxCaps();
-    jobject getDemuxInfo(int handle);
+    jobject getDemuxInfo(jlong handle);
     jobject getFrontendStatus(jintArray types);
-    Result openDemux(int handle);
+    Result openDemux(jlong handle);
     jint close();
     jint closeFrontend();
     jint closeDemux();
diff --git a/media/jni/tuner/TunerClient.cpp b/media/jni/tuner/TunerClient.cpp
index ea623d9..0097710 100644
--- a/media/jni/tuner/TunerClient.cpp
+++ b/media/jni/tuner/TunerClient.cpp
@@ -56,7 +56,7 @@
     return ids;
 }
 
-sp<FrontendClient> TunerClient::openFrontend(int32_t frontendHandle) {
+sp<FrontendClient> TunerClient::openFrontend(int64_t frontendHandle) {
     if (mTunerService != nullptr) {
         shared_ptr<ITunerFrontend> tunerFrontend;
         Status s = mTunerService->openFrontend(frontendHandle, &tunerFrontend);
@@ -94,7 +94,7 @@
     return nullptr;
 }
 
-sp<DemuxClient> TunerClient::openDemux(int32_t demuxHandle) {
+sp<DemuxClient> TunerClient::openDemux(int64_t demuxHandle) {
     if (mTunerService != nullptr) {
         shared_ptr<ITunerDemux> tunerDemux;
         Status s = mTunerService->openDemux(demuxHandle, &tunerDemux);
@@ -107,7 +107,7 @@
     return nullptr;
 }
 
-shared_ptr<DemuxInfo> TunerClient::getDemuxInfo(int32_t demuxHandle) {
+shared_ptr<DemuxInfo> TunerClient::getDemuxInfo(int64_t demuxHandle) {
     if (mTunerService != nullptr) {
         DemuxInfo aidlDemuxInfo;
         Status s = mTunerService->getDemuxInfo(demuxHandle, &aidlDemuxInfo);
@@ -141,7 +141,7 @@
     return nullptr;
 }
 
-sp<DescramblerClient> TunerClient::openDescrambler(int32_t descramblerHandle) {
+sp<DescramblerClient> TunerClient::openDescrambler(int64_t descramblerHandle) {
     if (mTunerService != nullptr) {
         shared_ptr<ITunerDescrambler> tunerDescrambler;
         Status s = mTunerService->openDescrambler(descramblerHandle, &tunerDescrambler);
@@ -154,7 +154,7 @@
     return nullptr;
 }
 
-sp<LnbClient> TunerClient::openLnb(int32_t lnbHandle) {
+sp<LnbClient> TunerClient::openLnb(int64_t lnbHandle) {
     if (mTunerService != nullptr) {
         shared_ptr<ITunerLnb> tunerLnb;
         Status s = mTunerService->openLnb(lnbHandle, &tunerLnb);
diff --git a/media/jni/tuner/TunerClient.h b/media/jni/tuner/TunerClient.h
index 6ab120b..a348586 100644
--- a/media/jni/tuner/TunerClient.h
+++ b/media/jni/tuner/TunerClient.h
@@ -65,7 +65,7 @@
      * @param frontendHandle the handle of the frontend granted by TRM.
      * @return a newly created FrontendClient interface.
      */
-    sp<FrontendClient> openFrontend(int32_t frontendHandle);
+    sp<FrontendClient> openFrontend(int64_t frontendHandle);
 
     /**
      * Retrieve the granted frontend's information.
@@ -81,7 +81,7 @@
      * @param demuxHandle the handle of the demux granted by TRM.
      * @return a newly created DemuxClient interface.
      */
-    sp<DemuxClient> openDemux(int32_t demuxHandle);
+    sp<DemuxClient> openDemux(int64_t demuxHandle);
 
     /**
      * Retrieve the DemuxInfo of a specific demux
@@ -89,7 +89,7 @@
      * @param demuxHandle the handle of the demux to query demux info for
      * @return the demux info
      */
-    shared_ptr<DemuxInfo> getDemuxInfo(int32_t demuxHandle);
+    shared_ptr<DemuxInfo> getDemuxInfo(int64_t demuxHandle);
 
     /**
      * Retrieve a list of demux info
@@ -111,7 +111,7 @@
      * @param descramblerHandle the handle of the descrambler granted by TRM.
      * @return a newly created DescramblerClient interface.
      */
-    sp<DescramblerClient> openDescrambler(int32_t descramblerHandle);
+    sp<DescramblerClient> openDescrambler(int64_t descramblerHandle);
 
     /**
      * Open a new interface of LnbClient given an lnbHandle.
@@ -119,7 +119,7 @@
      * @param lnbHandle the handle of the LNB granted by TRM.
      * @return a newly created LnbClient interface.
      */
-    sp<LnbClient> openLnb(int32_t lnbHandle);
+    sp<LnbClient> openLnb(int64_t lnbHandle);
 
     /**
      * Open a new interface of LnbClient given a LNB name.
diff --git a/nfc/Android.bp b/nfc/Android.bp
index db3dcb0..7ad8c4c 100644
--- a/nfc/Android.bp
+++ b/nfc/Android.bp
@@ -41,6 +41,10 @@
         "framework-permission-s.stubs.module_lib",
         "framework-permission.stubs.module_lib",
     ],
+    stub_only_libs: [
+        // Needed for javadoc references.
+        "framework-permission-s.stubs.module_lib",
+    ],
     static_libs: [
         "android.nfc.flags-aconfig-java",
         "android.permission.flags-aconfig-java",
diff --git a/nfc/api/system-current.txt b/nfc/api/system-current.txt
index 4428ade..24e14e6 100644
--- a/nfc/api/system-current.txt
+++ b/nfc/api/system-current.txt
@@ -63,7 +63,7 @@
     method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean isAutoChangeEnabled();
     method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean isTagPresent();
     method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void maybeTriggerFirmwareUpdate();
-    method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void overwriteRoutingTable(int, int, int);
+    method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void overwriteRoutingTable(int, int, int, int);
     method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void pausePolling(int);
     method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void registerCallback(@NonNull java.util.concurrent.Executor, @NonNull android.nfc.NfcOemExtension.Callback);
     method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void resumePolling();
diff --git a/nfc/java/android/nfc/INfcCardEmulation.aidl b/nfc/java/android/nfc/INfcCardEmulation.aidl
index 1eae3c6..8535e4a 100644
--- a/nfc/java/android/nfc/INfcCardEmulation.aidl
+++ b/nfc/java/android/nfc/INfcCardEmulation.aidl
@@ -54,5 +54,5 @@
     void setAutoChangeStatus(boolean state);
     boolean isAutoChangeEnabled();
     List<String> getRoutingStatus();
-    void overwriteRoutingTable(int userHandle, String emptyAid, String protocol, String tech);
+    void overwriteRoutingTable(int userHandle, String emptyAid, String protocol, String tech, String sc);
 }
diff --git a/nfc/java/android/nfc/NfcOemExtension.java b/nfc/java/android/nfc/NfcOemExtension.java
index fb63b5c..bc410c7 100644
--- a/nfc/java/android/nfc/NfcOemExtension.java
+++ b/nfc/java/android/nfc/NfcOemExtension.java
@@ -647,24 +647,29 @@
      *                   {@link ProtocolAndTechnologyRoute}
      * @param emptyAid Zero-length AID route destination, where the possible inputs are defined in
      *                 {@link ProtocolAndTechnologyRoute}
+     * @param systemCode System Code route destination, where the possible inputs are defined in
+     *                   {@link ProtocolAndTechnologyRoute}
      */
     @RequiresPermission(Manifest.permission.WRITE_SECURE_SETTINGS)
     @FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
     public void overwriteRoutingTable(
             @CardEmulation.ProtocolAndTechnologyRoute int protocol,
             @CardEmulation.ProtocolAndTechnologyRoute int technology,
-            @CardEmulation.ProtocolAndTechnologyRoute int emptyAid) {
+            @CardEmulation.ProtocolAndTechnologyRoute int emptyAid,
+            @CardEmulation.ProtocolAndTechnologyRoute int systemCode) {
 
         String protocolRoute = routeIntToString(protocol);
         String technologyRoute = routeIntToString(technology);
         String emptyAidRoute = routeIntToString(emptyAid);
+        String systemCodeRoute = routeIntToString(systemCode);
 
         NfcAdapter.callService(() ->
                 NfcAdapter.sCardEmulationService.overwriteRoutingTable(
                         mContext.getUser().getIdentifier(),
                         emptyAidRoute,
                         protocolRoute,
-                        technologyRoute
+                        technologyRoute,
+                        systemCodeRoute
                 ));
     }
 
diff --git a/packages/CompanionDeviceManager/res/layout/activity_confirmation.xml b/packages/CompanionDeviceManager/res/layout/activity_confirmation.xml
index 08155dd..5805332 100644
--- a/packages/CompanionDeviceManager/res/layout/activity_confirmation.xml
+++ b/packages/CompanionDeviceManager/res/layout/activity_confirmation.xml
@@ -31,6 +31,12 @@
 
             <!-- A header for selfManaged devices only. -->
             <include layout="@layout/vendor_header" />
+            <!-- A device icon for selfManaged devices only. -->
+            <ImageView
+                android:id="@+id/device_icon"
+                android:visibility="gone"
+                android:contentDescription="@null"
+                style="@style/DeviceIcon" />
 
             <!-- Do NOT change the ID of the root LinearLayout above:
             it's referenced in CTS tests. -->
diff --git a/packages/CompanionDeviceManager/res/values-af/strings.xml b/packages/CompanionDeviceManager/res/values-af/strings.xml
index 798e7d5..2a8f17b 100644
--- a/packages/CompanionDeviceManager/res/values-af/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-af/strings.xml
@@ -25,17 +25,17 @@
     <string name="confirmation_title_glasses" msgid="8288346850537727333">"Laat &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; toe om &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; te bestuur?"</string>
     <string name="profile_name_glasses" msgid="3506504967216601277">"toestel"</string>
     <string name="summary_glasses" msgid="5469208629679579157">"Hierdie app sal toegang tot hierdie toestemmings op jou <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> hê"</string>
-    <string name="title_app_streaming" msgid="6845373585257287200">"Gee &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; toestemming om jou <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> se apps na &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&amp;gt te stroom?"</string>
-    <string name="summary_app_streaming" msgid="1274464413649731829">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> sal toegang hê tot enigiets wat sigbaar is of gespeel word op die <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>, insluitend oudio, foto’s, wagwoorde en boodskappe.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_1">%1$s</xliff:g> sal apps na <xliff:g id="DEVICE_NAME">%3$s</xliff:g> kan stroom totdat jy toegang tot hierdie toestemming verwyder."</string>
-    <string name="helper_summary_app_streaming" msgid="1944832605534698562">"<xliff:g id="APP_NAME">%1$s</xliff:g> versoek toestemming namens jou <xliff:g id="DEVICE_NAME">%2$s</xliff:g> om apps tussen jou toestelle te vertoon en te stroom"</string>
+    <string name="title_app_streaming" msgid="1047090167914857893">"Gee &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; toestemming om jou <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> se apps en stelselkenmerke na &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt; te stroom?"</string>
+    <string name="summary_app_streaming" msgid="7990244299655610920">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> sal toegang hê tot enigiets wat sigbaar is of gespeel word op jou <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>, insluitend oudio, foto’s, betaalinligting, wagwoorde en boodskappe.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_1">%1$s</xliff:g> sal apps na <xliff:g id="DEVICE_NAME">%3$s</xliff:g> kan stroom totdat jy toegang tot hierdie toestemming verwyder."</string>
+    <string name="helper_summary_app_streaming" msgid="1872657107404139828">"<xliff:g id="APP_NAME">%1$s</xliff:g> versoek namens <xliff:g id="DEVICE_NAME">%2$s</xliff:g> toestemming om apps en stelselkenmerke vanaf jou <xliff:g id="DEVICE_TYPE">%3$s</xliff:g> te stroom"</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4782923323932440751">"Gee &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; toegang tot hierdie inligting op jou <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
     <string name="helper_summary_computer" msgid="2298803016482139668">"<xliff:g id="APP_NAME">%1$s</xliff:g> versoek tans namens jou <xliff:g id="DEVICE_NAME">%2$s</xliff:g> toegang tot jou <xliff:g id="DEVICE_TYPE">%3$s</xliff:g> se foto’s, media en kennisgewings"</string>
-    <string name="title_nearby_device_streaming" msgid="4295322493408411976">"Gee &lt;strong&gt;<xliff:g id="DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt; toestemming om jou <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> se apps en stelselkenmerke na &lt;strong&gt;<xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>&lt;/strong&gt; te stroom?"</string>
-    <string name="summary_nearby_device_streaming" msgid="962267343109051648">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> sal toegang hê tot enigiets wat sigbaar is of gespeel word op jou <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>, insluitend oudio, foto’s, betaalinligting, wagwoorde en boodskappe.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_1">%1$s</xliff:g> sal apps en stelselkenmerke na <xliff:g id="DEVICE_NAME">%3$s</xliff:g> kan stroom totdat jy toegang tot hierdie toestemming verwyder."</string>
-    <string name="helper_summary_nearby_device_streaming" msgid="8509848562931818793">"<xliff:g id="APP_NAME">%1$s</xliff:g> versoek tans namens jou <xliff:g id="DEVICE_NAME">%2$s</xliff:g> toestemming om apps en ander stelselkenmerke tussen jou toestelle te stroom"</string>
+    <string name="title_nearby_device_streaming" msgid="2727103756701741359">"Gee &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; toestemming om jou <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> se apps na &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&amp;gt te stroom?"</string>
+    <string name="summary_nearby_device_streaming" msgid="70434958004946884">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> sal toegang hê tot enigiets wat sigbaar is of gespeel word op <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>, insluitend oudio, foto’s, wagwoorde en boodskappe.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_2">%1$s</xliff:g> sal apps na <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> kan stroom totdat jy toegang tot hierdie toestemming verwyder."</string>
+    <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"<xliff:g id="APP_NAME">%1$s</xliff:g> versoek namens <xliff:g id="DEVICE_NAME">%2$s</xliff:g> toestemming om apps vanaf jou <xliff:g id="DEVICE_TYPE">%3$s</xliff:g> te stroom"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"toestel"</string>
     <string name="summary_generic" msgid="1761976003668044801">"Hierdie app sal inligting kan sinkroniseer, soos die naam van iemand wat bel, tussen jou foon en die gekose toestel"</string>
     <string name="consent_yes" msgid="8344487259618762872">"Laat toe"</string>
diff --git a/packages/CompanionDeviceManager/res/values-am/strings.xml b/packages/CompanionDeviceManager/res/values-am/strings.xml
index 59e1f03..b66860e 100644
--- a/packages/CompanionDeviceManager/res/values-am/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-am/strings.xml
@@ -25,17 +25,17 @@
     <string name="confirmation_title_glasses" msgid="8288346850537727333">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;ን እንዲያስተዳድር ይፈቅዳሉ?"</string>
     <string name="profile_name_glasses" msgid="3506504967216601277">"መሣሪያ"</string>
     <string name="summary_glasses" msgid="5469208629679579157">"ይህ መተግበሪያ በእርስዎ <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> ላይ እነዚህን ፈቃዶች እንዲደርስ ይፈቀድለታል"</string>
-    <string name="title_app_streaming" msgid="6845373585257287200">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; የእርስዎን <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> መተግበሪያዎች ወደ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;? በዥረት እንዲለቅ ይፍቀዱ"</string>
-    <string name="summary_app_streaming" msgid="1274464413649731829">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> ኦዲዮ፣ ፎቶዎች፣ የይለፍ ቃላት እና መልዕክቶችን ጨምሮ በ<xliff:g id="DEVICE_TYPE">%2$s</xliff:g> ላይ የሚታየውን ወይም የሚጫወተውን ማንኛውንም ነገር መዳረሻ ይኖረዋል።&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_1">%1$s</xliff:g> የዚህን መዳረሻ እስኪያስወግዱ ድረስ መተግበሪያዎችን ወደ <xliff:g id="DEVICE_NAME">%3$s</xliff:g> በዥረት መልቀቅ ይችላል።"</string>
-    <string name="helper_summary_app_streaming" msgid="1944832605534698562">"<xliff:g id="APP_NAME">%1$s</xliff:g> የእርስዎን <xliff:g id="DEVICE_NAME">%2$s</xliff:g> በመወከል በመሣሪያዎችዎ መካከል ለማሳየት እና መተግበሪያዎችን በዥረት ለመልቀቅ ፈቃድ እየጠየቀ ነው"</string>
+    <string name="title_app_streaming" msgid="1047090167914857893">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; የእርስዎን <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> መተግበሪያዎች እና የሥርዓት ባህሪያት ወደ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;? በዥረት እንዲለቅ ይፍቀዱ"</string>
+    <string name="summary_app_streaming" msgid="7990244299655610920">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> ኦዲዮ፣ ፎቶዎች፣ የክፍያ መረጃ፣ የይለፍ ቃላት እና መልዕክቶችን ጨምሮ በእርስዎ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> ላይ የሚታየውን ወይም የሚጫወተውን የማንኛውም ነገር መዳረሻ ይኖረዋል።&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_1">%1$s</xliff:g> የዚህን መዳረሻ እስኪያስወግዱ ድረስ መተግበሪያዎችን ወደ <xliff:g id="DEVICE_NAME">%3$s</xliff:g> በዥረት መልቀቅ ይችላል።"</string>
+    <string name="helper_summary_app_streaming" msgid="1872657107404139828">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="DEVICE_NAME">%2$s</xliff:g>ን በመወከል ከእርስዎ <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>የመጡ መተግበሪያዎችን እና የሥርዓት ባህሪያትን በዥረት ለመልቀቅ ፈቃድ እየጠየቀ ነው"</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4782923323932440751">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ይህን መረጃ ከእርስዎ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> እንዲደርስ ይፍቀዱ"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
     <string name="helper_summary_computer" msgid="2298803016482139668">"<xliff:g id="APP_NAME">%1$s</xliff:g> የእርስዎን <xliff:g id="DEVICE_TYPE">%3$s</xliff:g> ፎቶዎች፣ ሚዲያ እና ማሳወቂያዎች ለመድረስ የእርስዎን <xliff:g id="DEVICE_NAME">%2$s</xliff:g> ወክሎ ፈቃድ እየጠየቀ ነው"</string>
-    <string name="title_nearby_device_streaming" msgid="4295322493408411976">"&lt;strong&gt;<xliff:g id="DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt; የእርስዎን <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> መተግበሪያዎች እና የሥርዓት ባህሪያት ወደ &lt;strong&gt;<xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>&lt;/strong&gt;? በዥረት እንዲለቅ ይፍቀዱ"</string>
-    <string name="summary_nearby_device_streaming" msgid="962267343109051648">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> ኦዲዮ፣ ፎቶዎች፣ የክፍያ መረጃ፣ የይለፍ ቃላት እና መልዕክቶችን ጨምሮ በእርስዎ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> ላይ የሚታየውን ወይም የሚጫወተውን የማንኛውም ነገር መዳረሻ ይኖረዋል።&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_1">%1$s</xliff:g> የዚህን መዳረሻ እስኪያስወግዱ ድረስ መተግበሪያዎችን እና የሥርዓት ባህሪያትን ወደ <xliff:g id="DEVICE_NAME">%3$s</xliff:g> በዥረት መልቀቅ ይችላል።"</string>
-    <string name="helper_summary_nearby_device_streaming" msgid="8509848562931818793">"<xliff:g id="APP_NAME">%1$s</xliff:g> የእርስዎን <xliff:g id="DEVICE_NAME">%2$s</xliff:g> በመወከል በመሣሪያዎችዎ መካከል መተግበሪያዎችን እና ሌሎች የሥርዓት ባህሪያትን በዥረት ለመልቀቅ ፈቃድ እየጠየቀ ነው"</string>
+    <string name="title_nearby_device_streaming" msgid="2727103756701741359">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; የእርስዎን <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> መተግበሪያዎች ወደ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;? በዥረት እንዲለቅ ይፍቀዱ"</string>
+    <string name="summary_nearby_device_streaming" msgid="70434958004946884">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> ኦዲዮ፣ ፎቶዎች፣ የክፍያ መረጃ፣ የይለፍ ቃላት እና መልዕክቶችን ጨምሮ <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g> ላይ የሚታየውን ወይም የሚጫወተውን የማንኛውም ነገር መዳረሻ ይኖረዋል።&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_2">%1$s</xliff:g> የዚህን መዳረሻ እስኪያስወግዱ ድረስ መተግበሪያዎችን ወደ <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> በዥረት መልቀቅ ይችላል።"</string>
+    <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"<xliff:g id="APP_NAME">%1$s</xliff:g> መተግበሪያዎችን ከእርስዎ <xliff:g id="DEVICE_TYPE">%3$s</xliff:g> በዥረት ለመልቀቅ <xliff:g id="DEVICE_NAME">%2$s</xliff:g>ን በመወከል ፈቃድ እየጠየቀ ነው"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"መሣሪያ"</string>
     <string name="summary_generic" msgid="1761976003668044801">"ይህ መተግበሪያ እንደ የሚደውል ሰው ስም ያለ መረጃን በስልክዎ እና በተመረጠው መሣሪያ መካከል ማስመር ይችላል"</string>
     <string name="consent_yes" msgid="8344487259618762872">"ፍቀድ"</string>
diff --git a/packages/CompanionDeviceManager/res/values-ar/strings.xml b/packages/CompanionDeviceManager/res/values-ar/strings.xml
index 89c7efb..6f17676 100644
--- a/packages/CompanionDeviceManager/res/values-ar/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ar/strings.xml
@@ -25,17 +25,17 @@
     <string name="confirmation_title_glasses" msgid="8288346850537727333">"‏هل تريد السماح لتطبيق &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; بإدارة &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;؟"</string>
     <string name="profile_name_glasses" msgid="3506504967216601277">"جهاز"</string>
     <string name="summary_glasses" msgid="5469208629679579157">"سيتم السماح لهذا التطبيق باستخدام هذه الأذونات على <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
-    <string name="title_app_streaming" msgid="6845373585257287200">"‏هل تريد السماح لتطبيق &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ببث التطبيقات من <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> إلى <xliff:g id="DEVICE_NAME">%3$s</xliff:g>؟"</string>
-    <string name="summary_app_streaming" msgid="1274464413649731829">"‏سيتمكّن \"<xliff:g id="APP_NAME_0">%1$s</xliff:g>\" من الوصول إلى كل المحتوى المعروض أو الذي يتم تشغيله على <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>، بما في ذلك الملفات الصوتية والصور وكلمات المرور والرسائل.&lt;br/&gt;&lt;br/&gt;سيتمكّن \"<xliff:g id="APP_NAME_1">%1$s</xliff:g>\" من بث التطبيقات إلى <xliff:g id="DEVICE_NAME">%3$s</xliff:g> إلى أن توقف إمكانية استخدام هذا الإذن."</string>
-    <string name="helper_summary_app_streaming" msgid="1944832605534698562">"يطلب \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" الحصول على إذن نيابةً عن <xliff:g id="DEVICE_NAME">%2$s</xliff:g> لعرض التطبيقات وبثها بين أجهزتك"</string>
+    <string name="title_app_streaming" msgid="1047090167914857893">"هل تريد السماح لـ \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" ببث التطبيقات وميزات النظام من <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> إلى <xliff:g id="DEVICE_NAME">%3$s</xliff:g>؟"</string>
+    <string name="summary_app_streaming" msgid="7990244299655610920">"‏سيتمكّن \"<xliff:g id="APP_NAME_0">%1$s</xliff:g>\" من الوصول إلى كل المحتوى المعروض أو الذي يتم تشغيله على <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>، بما في ذلك الملفات الصوتية والصور ومعلومات الدفع وكلمات المرور والرسائل.&lt;br/&gt;&lt;br/&gt;سيتمكّن \"<xliff:g id="APP_NAME_1">%1$s</xliff:g>\" من بثّ التطبيقات إلى <xliff:g id="DEVICE_NAME">%3$s</xliff:g> إلى أن توقِف إمكانية استخدام هذا الإذن."</string>
+    <string name="helper_summary_app_streaming" msgid="1872657107404139828">"يطلب \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" الحصول على إذن نيابةً عن <xliff:g id="DEVICE_NAME">%2$s</xliff:g> لبثّ التطبيقات وميزات النظام من <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>"</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4782923323932440751">"‏هل تريد السماح لتطبيق &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; بالوصول إلى هذه المعلومات من <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>؟"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
     <string name="helper_summary_computer" msgid="2298803016482139668">"يطلب \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" الحصول على إذن نيابةً عن <xliff:g id="DEVICE_NAME">%2$s</xliff:g> للوصول إلى الصور والوسائط والإشعارات في <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>"</string>
-    <string name="title_nearby_device_streaming" msgid="4295322493408411976">"هل تريد السماح لجهاز <xliff:g id="DEVICE_NAME_0">%1$s</xliff:g> ببث التطبيقات وميزات النظام من <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> إلى <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>؟"</string>
-    <string name="summary_nearby_device_streaming" msgid="962267343109051648">"‏سيتمكّن \"<xliff:g id="APP_NAME_0">%1$s</xliff:g>\" من الوصول إلى كل المحتوى المعروض أو الذي يتم تشغيله على <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>، بما في ذلك الملفات الصوتية والصور ومعلومات الدفع وكلمات المرور والرسائل.&lt;br/&gt;&lt;br/&gt;سيتمكّن \"<xliff:g id="APP_NAME_1">%1$s</xliff:g>\" من بث التطبيقات وميزات النظام إلى <xliff:g id="DEVICE_NAME">%3$s</xliff:g> إلى أن توقف إمكانية استخدام هذا الإذن."</string>
-    <string name="helper_summary_nearby_device_streaming" msgid="8509848562931818793">"يطلب \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" الحصول على إذن نيابةً عن <xliff:g id="DEVICE_NAME">%2$s</xliff:g> لبثّ التطبيقات وميزات النظام الأخرى بين أجهزتك"</string>
+    <string name="title_nearby_device_streaming" msgid="2727103756701741359">"هل تريد السماح لـ \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" ببث التطبيقات من <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> إلى <xliff:g id="DEVICE_NAME">%3$s</xliff:g>؟"</string>
+    <string name="summary_nearby_device_streaming" msgid="70434958004946884">"‏سيتمكّن \"<xliff:g id="APP_NAME_0">%1$s</xliff:g>\" من الوصول إلى كل المحتوى المعروض أو الذي يتم تشغيله على <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>، بما في ذلك الملفات الصوتية والصور ومعلومات الدفع وكلمات المرور والرسائل.&lt;br/&gt;&lt;br/&gt;سيتمكّن \"<xliff:g id="APP_NAME_2">%1$s</xliff:g>\" من بثّ التطبيقات إلى <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> إلى أن توقِف إمكانية استخدام هذا الإذن."</string>
+    <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"يطلب \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" الحصول على إذن نيابةً عن <xliff:g id="DEVICE_NAME">%2$s</xliff:g> لبثّ التطبيقات من <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"جهاز"</string>
     <string name="summary_generic" msgid="1761976003668044801">"سيتمكّن هذا التطبيق من مزامنة المعلومات، مثل اسم المتصل، بين هاتفك والجهاز المحدّد."</string>
     <string name="consent_yes" msgid="8344487259618762872">"السماح"</string>
diff --git a/packages/CompanionDeviceManager/res/values-as/strings.xml b/packages/CompanionDeviceManager/res/values-as/strings.xml
index 3d252ca..8b001d1 100644
--- a/packages/CompanionDeviceManager/res/values-as/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-as/strings.xml
@@ -25,17 +25,17 @@
     <string name="confirmation_title_glasses" msgid="8288346850537727333">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;ক &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; পৰিচালনা কৰিবলৈ দিবনে?"</string>
     <string name="profile_name_glasses" msgid="3506504967216601277">"ডিভাইচ"</string>
     <string name="summary_glasses" msgid="5469208629679579157">"এই এপ্‌টোক আপোনাৰ <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>ত এই অনুমতিসমূহ এক্সেছ কৰিবলৈ অনুমতি দিয়া হ’ব"</string>
-    <string name="title_app_streaming" msgid="6845373585257287200">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;ক আপোনাৰ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>ৰ এপ্‌সমূহ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;ত ষ্ট্ৰীম কৰিবলৈ দিবনে?"</string>
-    <string name="summary_app_streaming" msgid="1274464413649731829">"<xliff:g id="APP_NAME_0">%1$s</xliff:g>এ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>ত দৃশ্যমান হোৱা বা প্লে’ কৰা অডিঅ’, ফট’ পাছৱৰ্ড আৰু বাৰ্তাকে ধৰি যিকোনো বস্তু এক্সেছ কৰিব পাৰিব।&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_1">%1$s</xliff:g>এ আপুনি এই অনুমতিৰ এক্সেছ আঁতৰাই নিদিয়া পৰ্যন্ত <xliff:g id="DEVICE_NAME">%3$s</xliff:g>ত এপ্‌সমূহ ষ্ট্ৰীম কৰিব পাৰিব।"</string>
-    <string name="helper_summary_app_streaming" msgid="1944832605534698562">"<xliff:g id="APP_NAME">%1$s</xliff:g>এ আপোনাৰ <xliff:g id="DEVICE_NAME">%2$s</xliff:g>ৰ হৈ আপোনাৰ ডিভাইচসমূহৰ মাজত এপ্‌সমূহ দেখুৱাবলৈ আৰু ষ্ট্ৰীম কৰিবলৈ অনুমতি বিচাৰি অনুৰোধ জনাইছে"</string>
+    <string name="title_app_streaming" msgid="1047090167914857893">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;ক আপোনাৰ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>ৰ এপ্‌ আৰু ছিষ্টেমৰ সুবিধাসমূহ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;ত ষ্ট্ৰীম কৰিবলৈ দিবনে?"</string>
+    <string name="summary_app_streaming" msgid="7990244299655610920">"<xliff:g id="APP_NAME_0">%1$s</xliff:g>এ আপোনাৰ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>ত দৃশ্যমান বা প্লে’ কৰা অডিঅ’, ফট’ পৰিশোধৰ তথ্য, পাছৱৰ্ড আৰু বাৰ্তাকে ধৰি যিকোনো বস্তু এক্সেছ কৰিব পাৰিব।&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_1">%1$s</xliff:g>এ আপুনি এই অনুমতিৰ এক্সেছ আঁতৰাই নিদিয়া পৰ্যন্ত <xliff:g id="DEVICE_NAME">%3$s</xliff:g>ত এপ্‌সমূহ ষ্ট্ৰীম কৰিব পাৰিব।"</string>
+    <string name="helper_summary_app_streaming" msgid="1872657107404139828">"<xliff:g id="APP_NAME">%1$s</xliff:g>এ আপোনাৰ <xliff:g id="DEVICE_NAME">%2$s</xliff:g>ৰ হৈ আপোনাৰ <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>ৰ পৰা এপ্‌ আৰু ছিষ্টেমৰ সুবিধাসমূহ ষ্ট্ৰীম কৰিবলৈ অনুমতি বিচাৰি অনুৰোধ জনাইছে"</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4782923323932440751">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;ক আপোনাৰ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>ৰ পৰা এই তথ্যখিনি এক্সেছ কৰিবলৈ দিয়ক"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
     <string name="helper_summary_computer" msgid="2298803016482139668">"<xliff:g id="APP_NAME">%1$s</xliff:g>এ আপোনাৰ <xliff:g id="DEVICE_NAME">%2$s</xliff:g>ৰ হৈ আপোনাৰ <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>ৰ ফট’, মিডিয়া আৰু জাননী এক্সেছ কৰাৰ বাবে অনুমতি বিচাৰি অনুৰোধ জনাইছে"</string>
-    <string name="title_nearby_device_streaming" msgid="4295322493408411976">"&lt;strong&gt;<xliff:g id="DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt;ক আপোনাৰ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>ৰ এপ্‌সমূহ আৰু ছিষ্টেমৰ সুবিধাসমূহ &lt;strong&gt;<xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>&lt;/strong&gt;ত ষ্ট্ৰীম কৰিবলৈ দিবনে?"</string>
-    <string name="summary_nearby_device_streaming" msgid="962267343109051648">"<xliff:g id="APP_NAME_0">%1$s</xliff:g>এ আপোনাৰ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>ত দৃশ্যমান বা প্লে’ কৰা অডিঅ’, ফট’ পৰিশোধৰ তথ্য, পাছৱৰ্ড আৰু বাৰ্তাকে ধৰি যিকোনো বস্তু এক্সেছ কৰিব পাৰিব।&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_1">%1$s</xliff:g>এ আপুনি এই অনুমতিৰ এক্সেছ আঁতৰাই নিদিয়া পৰ্যন্ত <xliff:g id="DEVICE_NAME">%3$s</xliff:g>ত এপ্‌সমূহ আৰু ছিষ্টেমৰ সুবিধাসমূহ ষ্ট্ৰীম কৰিব পাৰিব।"</string>
-    <string name="helper_summary_nearby_device_streaming" msgid="8509848562931818793">"<xliff:g id="APP_NAME">%1$s</xliff:g>এ আপোনাৰ <xliff:g id="DEVICE_NAME">%2$s</xliff:g>ৰ হৈ আপোনাৰ ডিভাইচসমূহৰ মাজত এপ্‌সমূহ আৰু আন ছিষ্টেমৰ সুবিধাসমূহ ষ্ট্ৰীম কৰিবলৈ অনুমতি বিচাৰি অনুৰোধ জনাইছে"</string>
+    <string name="title_nearby_device_streaming" msgid="2727103756701741359">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;ক আপোনাৰ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>ৰ এপ্‌সমূহ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;ত ষ্ট্ৰীম কৰিবলৈ দিবনে?"</string>
+    <string name="summary_nearby_device_streaming" msgid="70434958004946884">"<xliff:g id="APP_NAME_0">%1$s</xliff:g>এ <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>ত দৃশ্যমান হোৱা বা প্লে’ কৰা অডিঅ’, ফট’ পাছৱৰ্ড আৰু বাৰ্তাকে ধৰি যিকোনো বস্তু এক্সেছ কৰিব পাৰিব।&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_2">%1$s</xliff:g>এ আপুনি এই অনুমতিৰ এক্সেছ আঁতৰাই নিদিয়া পৰ্যন্ত <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g>ত এপ্‌সমূহ ষ্ট্ৰীম কৰিব পাৰিব।"</string>
+    <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"<xliff:g id="APP_NAME">%1$s</xliff:g>এ আপোনাৰ <xliff:g id="DEVICE_NAME">%2$s</xliff:g>ৰ হৈ আপোনাৰ <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>ৰ পৰা এপ্‌সমূহ ষ্ট্ৰীম কৰিবলৈ অনুমতি বিচাৰি অনুৰোধ জনাইছে"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"ডিভাইচ"</string>
     <string name="summary_generic" msgid="1761976003668044801">"এই এপ্‌টোৱে আপোনাৰ ফ’ন আৰু বাছনি কৰা ডিভাইচটোৰ মাজত কল কৰোঁতাৰ নামৰ দৰে তথ্য ছিংক কৰিব পাৰিব"</string>
     <string name="consent_yes" msgid="8344487259618762872">"অনুমতি দিয়ক"</string>
diff --git a/packages/CompanionDeviceManager/res/values-az/strings.xml b/packages/CompanionDeviceManager/res/values-az/strings.xml
index 2a636a9..b4fdcec 100644
--- a/packages/CompanionDeviceManager/res/values-az/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-az/strings.xml
@@ -25,17 +25,17 @@
     <string name="confirmation_title_glasses" msgid="8288346850537727333">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; tətbiqinə &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; cihazını idarə etmək icazəsi verilsin?"</string>
     <string name="profile_name_glasses" msgid="3506504967216601277">"cihazda"</string>
     <string name="summary_glasses" msgid="5469208629679579157">"Bu tətbiq <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> cihazında bu icazələrə daxil ola biləcək"</string>
-    <string name="title_app_streaming" msgid="6845373585257287200">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; üçün <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> tətbiqlərini &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt; cihazına sinxronlaşdırmaq icazəsi verilsin?"</string>
-    <string name="summary_app_streaming" msgid="1274464413649731829">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> audio, foto, parol və mesajlar daxil olmaqla <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> cihazında görünən və ya oxudulan kontentə giriş əldə edəcək.&lt;br/&gt;&lt;br/&gt;Siz bu icazəyə girişi silənə qədər <xliff:g id="APP_NAME_1">%1$s</xliff:g>tətbiqləri <xliff:g id="DEVICE_NAME">%3$s</xliff:g> cihazına yayımlaya biləcək."</string>
-    <string name="helper_summary_app_streaming" msgid="1944832605534698562">"<xliff:g id="APP_NAME">%1$s</xliff:g> tətbiqləri göstərmək və cihazlar arasında yayımlamaq üçün <xliff:g id="DEVICE_NAME">%2$s</xliff:g> adından icazə tələb edir"</string>
+    <string name="title_app_streaming" msgid="1047090167914857893">"<xliff:g id="DEVICE_TYPE">%2$s</xliff:g> cihazının tətbiq və sistem funksiyalarını &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt; cihazında yayımlamaq üçün &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; tətbiqinə icazə verilsin?"</string>
+    <string name="summary_app_streaming" msgid="7990244299655610920">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> audio, foto, ödəniş məlumatı, parol və mesajlar daxil olmaqla <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> cihazında görünən və ya oxudulan kontentə giriş əldə edəcək.&lt;br/&gt;&lt;br/&gt;Siz bu icazəyə girişi silənə qədər <xliff:g id="APP_NAME_1">%1$s</xliff:g> tətbiqləri <xliff:g id="DEVICE_NAME">%3$s</xliff:g> cihazında yayımlaya biləcək."</string>
+    <string name="helper_summary_app_streaming" msgid="1872657107404139828">"<xliff:g id="DEVICE_TYPE">%3$s</xliff:g> cihazından tətbiqləri və sistem fuksiyalarını yayımlamaq üçün <xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="DEVICE_NAME">%2$s</xliff:g> adından icazə tələb edir"</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4782923323932440751">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; tətbiqinə <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> cihazından əldə edilən bu məlumata giriş icazəsi verin"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
     <string name="helper_summary_computer" msgid="2298803016482139668">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="DEVICE_TYPE">%3$s</xliff:g> üzrə foto, media və bildirişlərə daxil olmaq üçün <xliff:g id="DEVICE_NAME">%2$s</xliff:g> adından icazə tələb edir"</string>
-    <string name="title_nearby_device_streaming" msgid="4295322493408411976">"&lt;strong&gt;<xliff:g id="DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt; üçün <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> tətbiq və sistem funksiyalarını &lt;strong&gt;<xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>&lt;/strong&gt; cihazına yayımlamaq icazəsi verilsin?"</string>
-    <string name="summary_nearby_device_streaming" msgid="962267343109051648">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> audio, foto, ödəniş məlumatı, parol və mesajlar daxil olmaqla <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> cihazında görünən və ya işə salınan kontentə giriş əldə edəcək.&lt;br/&gt;&lt;br/&gt;Siz bu icazəyə girişi silənə qədər <xliff:g id="APP_NAME_1">%1$s</xliff:g> tətbiq və sistem funksiyalarını <xliff:g id="DEVICE_NAME">%3$s</xliff:g> cihazına yayımlaya biləcək."</string>
-    <string name="helper_summary_nearby_device_streaming" msgid="8509848562931818793">"<xliff:g id="APP_NAME">%1$s</xliff:g> cihazlar arasında tətbiqləri və digər sistem funksiyalarını yayımlamaq üçün <xliff:g id="DEVICE_NAME">%2$s</xliff:g> adından icazə tələb edir"</string>
+    <string name="title_nearby_device_streaming" msgid="2727103756701741359">"<xliff:g id="DEVICE_TYPE">%2$s</xliff:g> cihazının tətbiqlərini &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt; cihazına yayımlamaq üçün &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; tətbiqinə icazə verilsin?"</string>
+    <string name="summary_nearby_device_streaming" msgid="70434958004946884">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> audio, foto, ödəniş məlumatı, parol və mesajlar daxil olmaqla <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g> cihazında görünən və ya oxudulan kontentə giriş əldə edəcək.&lt;br/&gt;&lt;br/&gt;Siz bu icazəyə girişi silənə qədər <xliff:g id="APP_NAME_2">%1$s</xliff:g> tətbiqləri <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> cihazında yayımlaya biləcək."</string>
+    <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"<xliff:g id="DEVICE_TYPE">%3$s</xliff:g> cihazından tətbiqləri yayımlamaq üçün <xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="DEVICE_NAME">%2$s</xliff:g> adından icazə tələb edir"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"cihaz"</string>
     <string name="summary_generic" msgid="1761976003668044801">"Tətbiq zəng edənin adı kimi məlumatları telefon ilə seçilmiş cihaz arasında sinxronlaşdıracaq"</string>
     <string name="consent_yes" msgid="8344487259618762872">"İcazə verin"</string>
diff --git a/packages/CompanionDeviceManager/res/values-b+sr+Latn/strings.xml b/packages/CompanionDeviceManager/res/values-b+sr+Latn/strings.xml
index 010b59a..ef97da9 100644
--- a/packages/CompanionDeviceManager/res/values-b+sr+Latn/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-b+sr+Latn/strings.xml
@@ -25,17 +25,17 @@
     <string name="confirmation_title_glasses" msgid="8288346850537727333">"Želite li da dozvolite da &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; upravlja uređajem &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
     <string name="profile_name_glasses" msgid="3506504967216601277">"uređaj"</string>
     <string name="summary_glasses" msgid="5469208629679579157">"Ovoj aplikaciji će biti dozvoljeno da pristupa ovim dozvolama na uređaju <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
-    <string name="title_app_streaming" msgid="6845373585257287200">"Želite li da dozvolite da &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; strimuje aplikacije uređaja <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> na &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;?"</string>
-    <string name="summary_app_streaming" msgid="1274464413649731829">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> će imati pristup svemu što se vidi ili pušta na uređaju <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>, uključujući zvuk, slike, lozinke i poruke.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_1">%1$s</xliff:g> će moći da strimuje aplikacije na <xliff:g id="DEVICE_NAME">%3$s</xliff:g> dok ne uklonite pristup ovoj dozvoli."</string>
-    <string name="helper_summary_app_streaming" msgid="1944832605534698562">"<xliff:g id="APP_NAME">%1$s</xliff:g> traži dozvolu u ime uređaja <xliff:g id="DEVICE_NAME">%2$s</xliff:g> da prikazuje i strimuje aplikacije između uređaja"</string>
+    <string name="title_app_streaming" msgid="1047090167914857893">"Želite da dozvolite da &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; strimuje aplikacije i sistemske funkcije uređaja <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> na &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;?"</string>
+    <string name="summary_app_streaming" msgid="7990244299655610920">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> će imati pristup svemu što se vidi ili pušta na uređaju <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>, uključujući zvuk, slike, informacije o plaćanju, lozinke i poruke.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_1">%1$s</xliff:g> će moći da strimuje aplikacije na <xliff:g id="DEVICE_NAME">%3$s</xliff:g> dok ne uklonite pristup ovoj dozvoli."</string>
+    <string name="helper_summary_app_streaming" msgid="1872657107404139828">"<xliff:g id="APP_NAME">%1$s</xliff:g> traži dozvolu u ime uređaja <xliff:g id="DEVICE_NAME">%2$s</xliff:g> da strimuje aplikacije i sistemske funkcije sa uređaja <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>"</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4782923323932440751">"Dozvolite da &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; pristupa ovim informacijama sa uređaja <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
     <string name="helper_summary_computer" msgid="2298803016482139668">"<xliff:g id="APP_NAME">%1$s</xliff:g> traži dozvolu u ime uređaja <xliff:g id="DEVICE_NAME">%2$s</xliff:g> da pristupa slikama, medijskom sadržaju i obaveštenjima sa uređaja <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>"</string>
-    <string name="title_nearby_device_streaming" msgid="4295322493408411976">"Želite li da dozvolite da &lt;strong&gt;<xliff:g id="DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt; strimuje aplikacije i sistemske funkcije uređaja <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> na &lt;strong&gt;<xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>&lt;/strong&gt;?"</string>
-    <string name="summary_nearby_device_streaming" msgid="962267343109051648">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> će imati pristup svemu što se vidi ili pušta na uređaju <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>, uključujući zvuk, slike, informacije o plaćanju, lozinke i poruke.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_1">%1$s</xliff:g> će moći da strimuje aplikacije i sistemske funkcije na <xliff:g id="DEVICE_NAME">%3$s</xliff:g> dok ne uklonite pristup ovoj dozvoli."</string>
-    <string name="helper_summary_nearby_device_streaming" msgid="8509848562931818793">"<xliff:g id="APP_NAME">%1$s</xliff:g> traži dozvolu u ime uređaja <xliff:g id="DEVICE_NAME">%2$s</xliff:g> da strimuje aplikacije i druge sistemske funkcije između uređaja"</string>
+    <string name="title_nearby_device_streaming" msgid="2727103756701741359">"Želite da dozvolite da &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; strimuje aplikacije uređaja <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> na &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;?"</string>
+    <string name="summary_nearby_device_streaming" msgid="70434958004946884">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> će imati pristup svemu što se vidi ili pušta na uređaju <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>, uključujući zvuk, slike, informacije o plaćanju, lozinke i poruke.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_2">%1$s</xliff:g> će moći da strimuje aplikacije na <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> dok ne uklonite pristup ovoj dozvoli."</string>
+    <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"<xliff:g id="APP_NAME">%1$s</xliff:g> traži dozvolu u ime uređaja <xliff:g id="DEVICE_NAME">%2$s</xliff:g> da strimuje aplikacije sa uređaja <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"uređaj"</string>
     <string name="summary_generic" msgid="1761976003668044801">"Ova aplikacija će moći da sinhronizuje podatke, poput imena osobe koja upućuje poziv, između telefona i odabranog uređaja"</string>
     <string name="consent_yes" msgid="8344487259618762872">"Dozvoli"</string>
diff --git a/packages/CompanionDeviceManager/res/values-be/strings.xml b/packages/CompanionDeviceManager/res/values-be/strings.xml
index 5cc26a7..c0aaac9 100644
--- a/packages/CompanionDeviceManager/res/values-be/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-be/strings.xml
@@ -25,17 +25,17 @@
     <string name="confirmation_title_glasses" msgid="8288346850537727333">"Дазволіць праграме &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; кіраваць прыладай &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
     <string name="profile_name_glasses" msgid="3506504967216601277">"прылада"</string>
     <string name="summary_glasses" msgid="5469208629679579157">"Гэта праграма будзе мець на вашай прыладзе тыпу \"<xliff:g id="DEVICE_TYPE">%1$s</xliff:g>\" наступныя дазволы"</string>
-    <string name="title_app_streaming" msgid="6845373585257287200">"Дазволіць праграме &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; трансліраваць праграмы прылады тыпу \"<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>\" на прыладу &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;?"</string>
-    <string name="summary_app_streaming" msgid="1274464413649731829">"Праграма \"<xliff:g id="APP_NAME_0">%1$s</xliff:g>\" будзе мець доступ да ўсяго, што паказваецца ці прайграецца на прыладзе тыпу \"<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>\", у тым ліку да аўдыя, фота, пароляў і паведамленняў.&lt;br/&gt;&lt;br/&gt;Праграма \"<xliff:g id="APP_NAME_1">%1$s</xliff:g>\" зможа трансліраваць праграмы на прыладу \"<xliff:g id="DEVICE_NAME">%3$s</xliff:g>\", пакуль вы не адклічаце гэты дазвол."</string>
-    <string name="helper_summary_app_streaming" msgid="1944832605534698562">"Праграма \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" запытвае дазвол ад імя вашай прылады \"<xliff:g id="DEVICE_NAME">%2$s</xliff:g>\" на паказ і трансляцыю праграм паміж прыладамі"</string>
+    <string name="title_app_streaming" msgid="1047090167914857893">"Дазволіць прыладзе &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; трансліраваць праграмы і сістэмныя функцыі прылады тыпу \"<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>\" на прыладу &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;?"</string>
+    <string name="summary_app_streaming" msgid="7990244299655610920">"Праграма \"<xliff:g id="APP_NAME_0">%1$s</xliff:g>\" будзе мець доступ да ўсяго, што паказваецца ці прайграецца на прыладзе тыпу \"<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>\", у тым ліку да аўдыя, фота, плацежнай інфармацыі, пароляў і паведамленняў.&lt;br/&gt;&lt;br/&gt;Праграма \"<xliff:g id="APP_NAME_1">%1$s</xliff:g>\" зможа трансліраваць праграмы на прыладу \"<xliff:g id="DEVICE_NAME">%3$s</xliff:g>\", пакуль вы не адклічаце гэты дазвол."</string>
+    <string name="helper_summary_app_streaming" msgid="1872657107404139828">"Праграма \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" запытвае дазвол ад імя прылады \"<xliff:g id="DEVICE_NAME">%2$s</xliff:g>\" на трансляцыю праграмы і сістэмных функцый з прылады тыпу \"<xliff:g id="DEVICE_TYPE">%3$s</xliff:g>\""</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4782923323932440751">"Дазвольце праграме &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; мець доступ да гэтай інфармацыі з прылады тыпу \"<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>\""</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
     <string name="helper_summary_computer" msgid="2298803016482139668">"Праграма \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" запытвае дазвол ад імя вашай прылады \"<xliff:g id="DEVICE_NAME">%2$s</xliff:g>\" на доступ да фота, медыяфайлаў і апавяшчэнняў на прыладзе тыпу \"<xliff:g id="DEVICE_TYPE">%3$s</xliff:g>\""</string>
-    <string name="title_nearby_device_streaming" msgid="4295322493408411976">"Дазволіць прыладзе &lt;strong&gt;<xliff:g id="DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt; трансліраваць праграмы і сістэмныя функцыі прылады тыпу \"<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>\" на прыладу &lt;strong&gt;<xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>&lt;/strong&gt;?"</string>
-    <string name="summary_nearby_device_streaming" msgid="962267343109051648">"Праграма \"<xliff:g id="APP_NAME_0">%1$s</xliff:g>\" будзе мець доступ да ўсяго, што паказваецца ці прайграецца на прыладзе тыпу \"<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>\", у тым ліку да аўдыя, фота, пароляў і паведамленняў.&lt;br/&gt;&lt;br/&gt;Праграма \"<xliff:g id="APP_NAME_1">%1$s</xliff:g>\" зможа трансліраваць праграмы і сістэмныя функцыі на прыладу \"<xliff:g id="DEVICE_NAME">%3$s</xliff:g>\", пакуль вы не адклічаце гэты дазвол."</string>
-    <string name="helper_summary_nearby_device_streaming" msgid="8509848562931818793">"Праграма \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" запытвае дазвол ад імя вашай прылады \"<xliff:g id="DEVICE_NAME">%2$s</xliff:g>\" на трансляцыю праграм і іншых сістэмных функцый паміж прыладамі"</string>
+    <string name="title_nearby_device_streaming" msgid="2727103756701741359">"Дазволіць праграме &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; трансліраваць праграмы прылады тыпу \"<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>\" на прыладу &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;?"</string>
+    <string name="summary_nearby_device_streaming" msgid="70434958004946884">"Праграма \"<xliff:g id="APP_NAME_0">%1$s</xliff:g>\" будзе мець доступ да ўсяго, што паказваецца ці прайграецца на прыладзе \"<xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>\", у тым ліку да аўдыя, фота, плацежнай інфармацыі, пароляў і паведамленняў.&lt;br/&gt;&lt;br/&gt;Праграма \"<xliff:g id="APP_NAME_2">%1$s</xliff:g>\" зможа трансліраваць праграмы на прыладу \"<xliff:g id="DEVICE_NAME_3">%3$s</xliff:g>\", пакуль вы не адклічаце гэты дазвол."</string>
+    <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"Праграма \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" запытвае дазвол ад імя прылады \"<xliff:g id="DEVICE_NAME">%2$s</xliff:g>\" на трансляцыю праграм з прылады тыпу \"<xliff:g id="DEVICE_TYPE">%3$s</xliff:g>\""</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"прылада"</string>
     <string name="summary_generic" msgid="1761976003668044801">"Гэта праграма зможа сінхранізаваць інфармацыю (напрыклад, імя таго, хто звоніць) паміж тэлефонам і выбранай прыладай"</string>
     <string name="consent_yes" msgid="8344487259618762872">"Дазволіць"</string>
diff --git a/packages/CompanionDeviceManager/res/values-bg/strings.xml b/packages/CompanionDeviceManager/res/values-bg/strings.xml
index 747a071..0fa98ef 100644
--- a/packages/CompanionDeviceManager/res/values-bg/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-bg/strings.xml
@@ -25,17 +25,17 @@
     <string name="confirmation_title_glasses" msgid="8288346850537727333">"Разрешавате ли на &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; да управлява устройството &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
     <string name="profile_name_glasses" msgid="3506504967216601277">"устройство"</string>
     <string name="summary_glasses" msgid="5469208629679579157">"Това приложение ще има достъп до следните разрешения за вашите <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
-    <string name="title_app_streaming" msgid="6845373585257287200">"Да се разреши ли на &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; да предава поточно към &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt; приложенията на устройството ви от тип <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>?"</string>
-    <string name="summary_app_streaming" msgid="1274464413649731829">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> ще има достъп до всичко, което се показва или възпроизвежда на устройството ви от тип <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>, включително аудио, снимки, пароли и съобщения.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_1">%1$s</xliff:g> ще може да предава поточно приложения към устройството ви <xliff:g id="DEVICE_NAME">%3$s</xliff:g>, докато не премахнете това разрешение."</string>
-    <string name="helper_summary_app_streaming" msgid="1944832605534698562">"<xliff:g id="APP_NAME">%1$s</xliff:g> иска разрешение от името на ваше устройство (<xliff:g id="DEVICE_NAME">%2$s</xliff:g>) да показва и да предава поточно приложения между устройствата ви"</string>
+    <string name="title_app_streaming" msgid="1047090167914857893">"Да се разреши ли на &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; да предава поточно към &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt; приложенията и системните функции на устройството ви от тип <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>?"</string>
+    <string name="summary_app_streaming" msgid="7990244299655610920">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> ще има достъп до всичко, което се показва или възпроизвежда на устройството ви от тип <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>, включително аудио, снимки, данни за плащане, пароли и съобщения.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_1">%1$s</xliff:g> ще може да предава поточно приложения към устройството ви <xliff:g id="DEVICE_NAME">%3$s</xliff:g>, докато не премахнете това разрешение."</string>
+    <string name="helper_summary_app_streaming" msgid="1872657107404139828">"<xliff:g id="APP_NAME">%1$s</xliff:g> иска разрешение от името на <xliff:g id="DEVICE_NAME">%2$s</xliff:g> да предава поточно приложения и системни функции от устройството ви от тип <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>"</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4782923323932440751">"Разрешете на &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; да осъществява достъп до тази информация от вашия <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
     <string name="helper_summary_computer" msgid="2298803016482139668">"<xliff:g id="APP_NAME">%1$s</xliff:g> иска разрешение от името на ваше устройство (<xliff:g id="DEVICE_NAME">%2$s</xliff:g>) за достъп до снимките, мултимедията и известията на вашия <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>"</string>
-    <string name="title_nearby_device_streaming" msgid="4295322493408411976">"Да се разреши ли на &lt;strong&gt;<xliff:g id="DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt; да предава поточно към &lt;strong&gt;<xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>&lt;/strong&gt; приложенията и системните функции на устройството ви от тип <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>?"</string>
-    <string name="summary_nearby_device_streaming" msgid="962267343109051648">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> ще има достъп до всичко, което се показва или възпроизвежда на устройството ви от тип <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>, включително аудио, снимки, данни за плащане, пароли и съобщения.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_1">%1$s</xliff:g> ще може да предава поточно приложения и системни функции към устройството ви <xliff:g id="DEVICE_NAME">%3$s</xliff:g>, докато не премахнете това разрешение."</string>
-    <string name="helper_summary_nearby_device_streaming" msgid="8509848562931818793">"<xliff:g id="APP_NAME">%1$s</xliff:g> иска разрешение от името на ваше устройство (<xliff:g id="DEVICE_NAME">%2$s</xliff:g>) да предава поточно приложения и други системни функции между устройствата ви"</string>
+    <string name="title_nearby_device_streaming" msgid="2727103756701741359">"Да се разреши ли на &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; да предава поточно към &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt; приложенията на устройството ви от тип <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>?"</string>
+    <string name="summary_nearby_device_streaming" msgid="70434958004946884">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> ще има достъп до всичко, което се показва или възпроизвежда на устройството ви <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>, включително аудио, снимки, пароли и съобщения.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_2">%1$s</xliff:g> ще може да предава поточно приложения към устройството ви <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g>, докато не премахнете това разрешение."</string>
+    <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"<xliff:g id="APP_NAME">%1$s</xliff:g> иска разрешение от името на <xliff:g id="DEVICE_NAME">%2$s</xliff:g> да предава поточно приложения от устройството ви от тип <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"устройство"</string>
     <string name="summary_generic" msgid="1761976003668044801">"Това приложение ще може да синхронизира различна информация, като например името на обаждащия се, между телефона ви и избраното устройство"</string>
     <string name="consent_yes" msgid="8344487259618762872">"Разрешаване"</string>
diff --git a/packages/CompanionDeviceManager/res/values-bn/strings.xml b/packages/CompanionDeviceManager/res/values-bn/strings.xml
index ef9fddd..d2a0353 100644
--- a/packages/CompanionDeviceManager/res/values-bn/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-bn/strings.xml
@@ -25,17 +25,23 @@
     <string name="confirmation_title_glasses" msgid="8288346850537727333">"আপনি কি &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ম্যানেজ করার জন্য &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;-কে অনুমতি দেবেন?"</string>
     <string name="profile_name_glasses" msgid="3506504967216601277">"ডিভাইস"</string>
     <string name="summary_glasses" msgid="5469208629679579157">"<xliff:g id="DEVICE_TYPE">%1$s</xliff:g>-এ এইসব অনুমতি অ্যাক্সেস করার জন্য এই অ্যাপকে অনুমতি দেওয়া হবে"</string>
-    <string name="title_app_streaming" msgid="6845373585257287200">"আপনার <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>-এর অ্যাপ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;?-এ স্ট্রিম করার জন্য &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;-কে অনুমতি দেবেন?"</string>
-    <string name="summary_app_streaming" msgid="1274464413649731829">"অডিও, ফটো, পাসওয়ার্ড ও মেসেজ সহ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>-এ দেখা ও চালানো যায় এমন সব কিছু <xliff:g id="APP_NAME_0">%1$s</xliff:g> অ্যাক্সেস করতে পারবে।&lt;br/&gt;&lt;br/&gt;আপনি এই অনুমতি না সরানো পর্যন্ত <xliff:g id="APP_NAME_1">%1$s</xliff:g>, <xliff:g id="DEVICE_NAME">%3$s</xliff:g>-এ অ্যাপ স্ট্রিম করতে পারবে।"</string>
-    <string name="helper_summary_app_streaming" msgid="1944832605534698562">"আপনার বিভিন্ন ডিভাইসের মধ্যে অ্যাপ, ডিসপ্লে এবং স্ট্রিম করার জন্য আপনার <xliff:g id="DEVICE_NAME">%2$s</xliff:g>-এর হয়ে <xliff:g id="APP_NAME">%1$s</xliff:g> অনুমতি চাইছে"</string>
+    <!-- no translation found for title_app_streaming (1047090167914857893) -->
+    <skip />
+    <!-- no translation found for summary_app_streaming (7990244299655610920) -->
+    <skip />
+    <!-- no translation found for helper_summary_app_streaming (1872657107404139828) -->
+    <skip />
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4782923323932440751">"আপনার <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> থেকে এই তথ্য অ্যাক্সেস করার জন্য &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;-কে অনুমতি দিন"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
     <string name="helper_summary_computer" msgid="2298803016482139668">"আপনার <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>-এর ফটো, মিডিয়া ও বিজ্ঞপ্তি অ্যাক্সেস করার জন্য, আপনার <xliff:g id="DEVICE_NAME">%2$s</xliff:g>-এর হয়ে <xliff:g id="APP_NAME">%1$s</xliff:g> অনুমতি চাইছে"</string>
-    <string name="title_nearby_device_streaming" msgid="4295322493408411976">"আপনার <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>-এর অ্যাপ ও সিস্টেমের ফিচার &lt;strong&gt;<xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>&lt;/strong&gt;?-এ স্ট্রিম করার জন্য &lt;strong&gt;<xliff:g id="DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt;-কে অনুমতি দেবেন?"</string>
-    <string name="summary_nearby_device_streaming" msgid="962267343109051648">"অডিও, ফটো, পেমেন্টের তথ্য, পাসওয়ার্ড ও মেসেজ সহ আপনার <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>-এ দেখা ও চালানো যায় এমন সব কিছু <xliff:g id="APP_NAME_0">%1$s</xliff:g> অ্যাক্সেস করতে পারবে।&lt;br/&gt;&lt;br/&gt;আপনি এই অনুমতি না সরানো পর্যন্ত <xliff:g id="APP_NAME_1">%1$s</xliff:g>, <xliff:g id="DEVICE_NAME">%3$s</xliff:g>-এ অ্যাপ ও সিস্টেমের ফিচার স্ট্রিম করতে পারবে।"</string>
-    <string name="helper_summary_nearby_device_streaming" msgid="8509848562931818793">"আপনার বিভিন্ন ডিভাইসের মধ্যে অ্যাপ ও সিস্টেমের অন্যান্য ফিচার স্ট্রিম করার জন্য, আপনার <xliff:g id="DEVICE_NAME">%2$s</xliff:g>-এর হয়ে <xliff:g id="APP_NAME">%1$s</xliff:g> অনুমতি চাইছে"</string>
+    <!-- no translation found for title_nearby_device_streaming (2727103756701741359) -->
+    <skip />
+    <!-- no translation found for summary_nearby_device_streaming (70434958004946884) -->
+    <skip />
+    <!-- no translation found for helper_summary_nearby_device_streaming (4712712177819370967) -->
+    <skip />
     <string name="profile_name_generic" msgid="6851028682723034988">"ডিভাইস"</string>
     <string name="summary_generic" msgid="1761976003668044801">"এই অ্যাপ, আপনার ফোন এবং বেছে নেওয়া ডিভাইসের মধ্যে তথ্য সিঙ্ক করতে পারবে, যেমন কোনও কলারের নাম"</string>
     <string name="consent_yes" msgid="8344487259618762872">"অনুমতি দিন"</string>
diff --git a/packages/CompanionDeviceManager/res/values-bs/strings.xml b/packages/CompanionDeviceManager/res/values-bs/strings.xml
index 69ae96f..183bdc8 100644
--- a/packages/CompanionDeviceManager/res/values-bs/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-bs/strings.xml
@@ -25,17 +25,17 @@
     <string name="confirmation_title_glasses" msgid="8288346850537727333">"Dozvoliti aplikaciji &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; da upravlja uređajem &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
     <string name="profile_name_glasses" msgid="3506504967216601277">"uređaj"</string>
     <string name="summary_glasses" msgid="5469208629679579157">"Aplikaciji će biti dozvoljen pristup ovim odobrenjima koje sadržava vaš <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
-    <string name="title_app_streaming" msgid="6845373585257287200">"Dozvoliti aplikaciji &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; da prenosi aplikacije koje sadržava vaš <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> na uređaju &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;?"</string>
-    <string name="summary_app_streaming" msgid="1274464413649731829">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> će imati pristup svemu što <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> reproducira ili je vidljivo na njemu, uključujući zvukove, fotografije, lozinke i poruke.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_1">%1$s</xliff:g> će moći prenositi aplikacije na uređaju <xliff:g id="DEVICE_NAME">%3$s</xliff:g> dok ne uklonite pristup ovom odobrenju."</string>
-    <string name="helper_summary_app_streaming" msgid="1944832605534698562">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> traži odobrenje u ime vašeg uređaja <xliff:g id="DEVICE_NAME">%2$s</xliff:g> da prikazuje i prenosi aplikacije između vaših uređaja"</string>
+    <string name="title_app_streaming" msgid="1047090167914857893">"Dozvoliti aplikaciji &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; da prenosi aplikacije i funkcije sistema koje sadržava vaš <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> na uređaju &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;?"</string>
+    <string name="summary_app_streaming" msgid="7990244299655610920">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> će imati pristup svemu što <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> reproducira ili je vidljivo na njemu, uključujući zvukove, fotografije, podatke o plaćanju, lozinke i poruke.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_1">%1$s</xliff:g> će moći prenositi aplikacije na uređaju <xliff:g id="DEVICE_NAME">%3$s</xliff:g> dok ne uklonite pristup ovom odobrenju."</string>
+    <string name="helper_summary_app_streaming" msgid="1872657107404139828">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> traži odobrenje u ime uređaja <xliff:g id="DEVICE_NAME">%2$s</xliff:g> da prenosi aplikacije i funkcije sistema s uređaja vrste \"<xliff:g id="DEVICE_TYPE">%3$s</xliff:g>\""</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4782923323932440751">"Dozvolite aplikaciji &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; da pristupa ovim informacijama koje sadržava vaš <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
     <string name="helper_summary_computer" msgid="2298803016482139668">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> traži odobrenje u ime vašeg uređaja <xliff:g id="DEVICE_NAME">%2$s</xliff:g> da pristupa fotografijama, medijima i obavještenjima koje sadržava vaš <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>"</string>
-    <string name="title_nearby_device_streaming" msgid="4295322493408411976">"Dozvoliti uređaju &lt;strong&gt;<xliff:g id="DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt; da prenosi aplikacije i funkcije sistema koje sadržava vaš <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> na uređaju &lt;strong&gt;<xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>&lt;/strong&gt;?"</string>
-    <string name="summary_nearby_device_streaming" msgid="962267343109051648">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> će imati pristup svemu što <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> reproducira ili je vidljivo na njemu, uključujući zvukove, fotografije, podatke o plaćanju, lozinke i poruke.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_1">%1$s</xliff:g> će moći prenositi aplikacije i funkcije sistema na uređaju <xliff:g id="DEVICE_NAME">%3$s</xliff:g> dok ne uklonite pristup ovom odobrenju."</string>
-    <string name="helper_summary_nearby_device_streaming" msgid="8509848562931818793">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> traži odobrenje u ime vašeg uređaja <xliff:g id="DEVICE_NAME">%2$s</xliff:g> da prenosi aplikacije i druge funkcije sistema između vaših uređaja"</string>
+    <string name="title_nearby_device_streaming" msgid="2727103756701741359">"Dozvoliti aplikaciji &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; da prenosi aplikacije koje sadržava vaš <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> na uređaju &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;?"</string>
+    <string name="summary_nearby_device_streaming" msgid="70434958004946884">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> će imati pristup svemu što <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g> reproducira ili je vidljivo na njemu, uključujući zvukove, fotografije, podatke o plaćanju, lozinke i poruke.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_2">%1$s</xliff:g> će moći prenositi aplikacije na uređaju <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> dok ne uklonite pristup ovom odobrenju."</string>
+    <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> traži odobrenje u ime uređaja <xliff:g id="DEVICE_NAME">%2$s</xliff:g> da prenosi aplikacije s uređaja vrste \"<xliff:g id="DEVICE_TYPE">%3$s</xliff:g>\""</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"uređaj"</string>
     <string name="summary_generic" msgid="1761976003668044801">"Ova aplikacija će moći sinhronizirati informacije, kao što je ime osobe koja upućuje poziv, između vašeg telefona i odabranog uređaja"</string>
     <string name="consent_yes" msgid="8344487259618762872">"Dozvoli"</string>
diff --git a/packages/CompanionDeviceManager/res/values-ca/strings.xml b/packages/CompanionDeviceManager/res/values-ca/strings.xml
index f8c4084..9b321a8 100644
--- a/packages/CompanionDeviceManager/res/values-ca/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ca/strings.xml
@@ -25,19 +25,17 @@
     <string name="confirmation_title_glasses" msgid="8288346850537727333">"Permet que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; gestioni &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="profile_name_glasses" msgid="3506504967216601277">"dispositiu"</string>
     <string name="summary_glasses" msgid="5469208629679579157">"Aquesta aplicació podrà accedir a aquests permisos del <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
-    <string name="title_app_streaming" msgid="6845373585257287200">"Vols permetre que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; reprodueixi en continu les aplicacions del <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> a &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;strong&gt;?"</string>
-    <string name="summary_app_streaming" msgid="1274464413649731829">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> podrà accedir a qualsevol cosa que sigui visible o que es reprodueixi al <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>, inclosos àudios, fotos, contrasenyes i missatges.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_1">%1$s</xliff:g> podrà reproduir en continu aplicacions a <xliff:g id="DEVICE_NAME">%3$s</xliff:g> fins que suprimeixis l\'accés a aquest permís."</string>
-    <string name="helper_summary_app_streaming" msgid="1944832605534698562">"<xliff:g id="APP_NAME">%1$s</xliff:g> demana permís en nom del teu dispositiu <xliff:g id="DEVICE_NAME">%2$s</xliff:g> per mostrar i reproduir en continu aplicacions entre els dispositius"</string>
+    <string name="title_app_streaming" msgid="1047090167914857893">"Vols permetre que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; reprodueixi en continu les aplicacions i les funcions del sistema del dispositiu (<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>) a <xliff:g id="DEVICE_NAME">%3$s</xliff:g>?"</string>
+    <string name="summary_app_streaming" msgid="7990244299655610920">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> podrà accedir a qualsevol cosa que sigui visible o que es reprodueixi al teu dispositiu (<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>), inclosos àudios, fotos, informació de pagament, contrasenyes i missatges.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_1">%1$s</xliff:g> podrà reproduir en continu aplicacions al dispositiu <xliff:g id="DEVICE_NAME">%3$s</xliff:g> fins que suprimeixis l\'accés a aquest permís."</string>
+    <string name="helper_summary_app_streaming" msgid="1872657107404139828">"<xliff:g id="APP_NAME">%1$s</xliff:g> demana permís en nom del dispositiu <xliff:g id="DEVICE_NAME">%2$s</xliff:g> per reproduir en continu aplicacions i funcions del sistema del teu dispositiu (<xliff:g id="DEVICE_TYPE">%3$s</xliff:g>)"</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4782923323932440751">"Permet que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; accedeixi a aquesta informació del <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
     <string name="helper_summary_computer" msgid="2298803016482139668">"<xliff:g id="APP_NAME">%1$s</xliff:g> demana permís en nom del teu dispositiu <xliff:g id="DEVICE_NAME">%2$s</xliff:g> per accedir a les fotos, el contingut multimèdia i les notificacions del <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>"</string>
-    <string name="title_nearby_device_streaming" msgid="4295322493408411976">"Vols permetre que &lt;strong&gt;<xliff:g id="DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt; reprodueixi en continu les aplicacions i les funcions del sistema del <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> a <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>?"</string>
-    <!-- String.format failed for translation -->
-    <!-- no translation found for summary_nearby_device_streaming (962267343109051648) -->
-    <skip />
-    <string name="helper_summary_nearby_device_streaming" msgid="8509848562931818793">"<xliff:g id="APP_NAME">%1$s</xliff:g> demana permís en nom del teu dispositiu <xliff:g id="DEVICE_NAME">%2$s</xliff:g> per reproduir en continu aplicacions i altres funcions del sistema entre els dispositius"</string>
+    <string name="title_nearby_device_streaming" msgid="2727103756701741359">"Vols permetre que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; reprodueixi en continu les aplicacions del dispositiu (<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>) a &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;strong&gt;?"</string>
+    <string name="summary_nearby_device_streaming" msgid="70434958004946884">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> podrà accedir a qualsevol cosa que sigui visible o que es reprodueixi al dispositiu <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>, inclosos àudios, fotos, informació de pagament, contrasenyes i missatges.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_2">%1$s</xliff:g> podrà reproduir en continu aplicacions al dispositiu <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> fins que suprimeixis l\'accés a aquest permís."</string>
+    <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"<xliff:g id="APP_NAME">%1$s</xliff:g> demana permís en nom del dispositiu <xliff:g id="DEVICE_NAME">%2$s</xliff:g> per reproduir en continu aplicacions del teu dispositiu (<xliff:g id="DEVICE_TYPE">%3$s</xliff:g>)"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"dispositiu"</string>
     <string name="summary_generic" msgid="1761976003668044801">"Aquesta aplicació podrà sincronitzar informació, com ara el nom d\'algú que truca, entre el teu telèfon i el dispositiu triat"</string>
     <string name="consent_yes" msgid="8344487259618762872">"Permet"</string>
diff --git a/packages/CompanionDeviceManager/res/values-cs/strings.xml b/packages/CompanionDeviceManager/res/values-cs/strings.xml
index 04e7380..b08081b 100644
--- a/packages/CompanionDeviceManager/res/values-cs/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-cs/strings.xml
@@ -25,17 +25,17 @@
     <string name="confirmation_title_glasses" msgid="8288346850537727333">"Povolit aplikaci &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; spravovat zařízení &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
     <string name="profile_name_glasses" msgid="3506504967216601277">"zařízení"</string>
     <string name="summary_glasses" msgid="5469208629679579157">"Tato aplikace bude mít na zařízení typu <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> přístup k následujícím oprávněním"</string>
-    <string name="title_app_streaming" msgid="6845373585257287200">"Povolit aplikaci &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; streamovat aplikace na zařízení typu <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> do zařízení &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;?"</string>
-    <string name="summary_app_streaming" msgid="1274464413649731829">"Aplikace <xliff:g id="APP_NAME_0">%1$s</xliff:g> bude mít přístup ke všemu, co na zařízení typu <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> zobrazíte nebo přehrajete, včetně zvuku, fotek, hesel a zpráv.&lt;br/&gt;&lt;br/&gt;Aplikace <xliff:g id="APP_NAME_1">%1$s</xliff:g> bude moct streamovat aplikace do zařízení typu <xliff:g id="DEVICE_NAME">%3$s</xliff:g>, dokud přístup k tomuto oprávnění neodeberete."</string>
-    <string name="helper_summary_app_streaming" msgid="1944832605534698562">"Aplikace <xliff:g id="APP_NAME">%1$s</xliff:g> požaduje za vaše zařízení <xliff:g id="DEVICE_NAME">%2$s</xliff:g> oprávnění k zobrazení a streamování obsahu mezi zařízeními"</string>
+    <string name="title_app_streaming" msgid="1047090167914857893">"Povolit aplikaci &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; streamovat aplikace a systémové funkce ze zařízení typu <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> do zařízení &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;?"</string>
+    <string name="summary_app_streaming" msgid="7990244299655610920">"Aplikace <xliff:g id="APP_NAME_0">%1$s</xliff:g> bude mít přístup ke všemu, co na zařízení typu <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> zobrazíte nebo přehrajete, včetně zvuku, fotek, platebních údajů, hesel a zpráv.&lt;br/&gt;&lt;br/&gt;Aplikace <xliff:g id="APP_NAME_1">%1$s</xliff:g> bude moct streamovat aplikace do zařízení typu <xliff:g id="DEVICE_NAME">%3$s</xliff:g>, dokud přístup k tomuto oprávnění neodeberete."</string>
+    <string name="helper_summary_app_streaming" msgid="1872657107404139828">"Aplikace <xliff:g id="APP_NAME">%1$s</xliff:g> žádá jménem zařízení <xliff:g id="DEVICE_NAME">%2$s</xliff:g> o oprávnění streamovat aplikace a systémové funkce z vašeho zařízení typu <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>"</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4782923323932440751">"Povolte aplikaci &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; přístup k těmto informacím z vašeho zařízení typu <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
     <string name="helper_summary_computer" msgid="2298803016482139668">"Aplikace <xliff:g id="APP_NAME">%1$s</xliff:g> požaduje za vaše zařízení <xliff:g id="DEVICE_NAME">%2$s</xliff:g> oprávnění k přístupu k fotkám, médiím a oznámením na zařízení typu <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>"</string>
-    <string name="title_nearby_device_streaming" msgid="4295322493408411976">"Povolit aplikaci &lt;strong&gt;<xliff:g id="DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt; streamovat aplikace a systémové funkce ze zařízení typu <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> do zařízení &lt;strong&gt;<xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>&lt;/strong&gt;?"</string>
-    <string name="summary_nearby_device_streaming" msgid="962267343109051648">"Aplikace <xliff:g id="APP_NAME_0">%1$s</xliff:g> bude mít přístup ke všemu, co na zařízení typu <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> zobrazíte nebo přehrajete, včetně zvuku, fotek, platebních údajů, hesel a zpráv.&lt;br/&gt;&lt;br/&gt;Aplikace <xliff:g id="APP_NAME_1">%1$s</xliff:g> bude moct streamovat aplikace a systémové funkce do zařízení typu <xliff:g id="DEVICE_NAME">%3$s</xliff:g>, dokud přístup k tomuto oprávnění neodeberete."</string>
-    <string name="helper_summary_nearby_device_streaming" msgid="8509848562931818793">"Aplikace <xliff:g id="APP_NAME">%1$s</xliff:g> požaduje za vaše zařízení <xliff:g id="DEVICE_NAME">%2$s</xliff:g> oprávnění ke streamování aplikací a dalších systémových funkcí mezi zařízeními"</string>
+    <string name="title_nearby_device_streaming" msgid="2727103756701741359">"Povolit aplikaci &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; streamovat aplikace na zařízení typu <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> do zařízení &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;?"</string>
+    <string name="summary_nearby_device_streaming" msgid="70434958004946884">"Aplikace <xliff:g id="APP_NAME_0">%1$s</xliff:g> bude mít přístup ke všemu, co na zařízení typu <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g> zobrazíte nebo přehrajete, včetně zvuku, fotek, platebních údajů, hesel a zpráv.&lt;br/&gt;&lt;br/&gt;Aplikace <xliff:g id="APP_NAME_2">%1$s</xliff:g> bude moct streamovat aplikace do zařízení typu <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g>, dokud přístup k tomuto oprávnění neodeberete."</string>
+    <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"Aplikace <xliff:g id="APP_NAME">%1$s</xliff:g> žádá jménem zařízení <xliff:g id="DEVICE_NAME">%2$s</xliff:g> o oprávnění streamovat aplikace z vašeho zařízení typu <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"zařízení"</string>
     <string name="summary_generic" msgid="1761976003668044801">"Tato aplikace bude moci synchronizovat údaje, jako je jméno volajícího, mezi vaším telefonem a vybraným zařízením"</string>
     <string name="consent_yes" msgid="8344487259618762872">"Povolit"</string>
diff --git a/packages/CompanionDeviceManager/res/values-da/strings.xml b/packages/CompanionDeviceManager/res/values-da/strings.xml
index d948804..da3b261 100644
--- a/packages/CompanionDeviceManager/res/values-da/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-da/strings.xml
@@ -25,17 +25,17 @@
     <string name="confirmation_title_glasses" msgid="8288346850537727333">"Vil du tillade, at &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; administrerer &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
     <string name="profile_name_glasses" msgid="3506504967216601277">"enhed"</string>
     <string name="summary_glasses" msgid="5469208629679579157">"Denne app får adgang til disse tilladelser på din <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
-    <string name="title_app_streaming" msgid="6845373585257287200">"Vil du give &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; tilladelse til at streame apps fra din <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> til &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;?"</string>
-    <string name="summary_app_streaming" msgid="1274464413649731829">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> får adgang til alt, der er synligt eller afspilles på din <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>, herunder lyd, billeder, adgangskoder og beskeder.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_1">%1$s</xliff:g> kan streame apps til <xliff:g id="DEVICE_NAME">%3$s</xliff:g>, indtil du fjerner adgangen til denne tilladelse."</string>
-    <string name="helper_summary_app_streaming" msgid="1944832605534698562">"<xliff:g id="APP_NAME">%1$s</xliff:g> anmoder om tilladelse på vegne af din <xliff:g id="DEVICE_NAME">%2$s</xliff:g> til at vise og streame apps mellem dine enheder"</string>
+    <string name="title_app_streaming" msgid="1047090167914857893">"Vil du give &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; tilladelse til at streame apps og systemfunktioner fra din <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> til &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;?"</string>
+    <string name="summary_app_streaming" msgid="7990244299655610920">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> får adgang til alt, der er synligt eller afspilles på din <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>, herunder lyd, billeder, betalingsoplysninger, adgangskoder og beskeder.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_1">%1$s</xliff:g> kan streame apps til <xliff:g id="DEVICE_NAME">%3$s</xliff:g>, indtil du fjerner adgangen til denne tilladelse."</string>
+    <string name="helper_summary_app_streaming" msgid="1872657107404139828">"<xliff:g id="APP_NAME">%1$s</xliff:g> anmoder om tilladelse på vegne af <xliff:g id="DEVICE_NAME">%2$s</xliff:g> til at streame apps og systemfunktioner fra din <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>"</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4782923323932440751">"Giv &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; adgang til disse oplysninger fra din <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
     <string name="helper_summary_computer" msgid="2298803016482139668">"<xliff:g id="APP_NAME">%1$s</xliff:g> anmoder om tilladelse på vegne af din <xliff:g id="DEVICE_NAME">%2$s</xliff:g> til at få adgang til billeder, medier og notifikationer på din <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>"</string>
-    <string name="title_nearby_device_streaming" msgid="4295322493408411976">"Vil du give &lt;strong&gt;<xliff:g id="DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt; tilladelse til at streame apps og systemfunktioner fra din <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> til &lt;strong&gt;<xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>&lt;/strong&gt;?"</string>
-    <string name="summary_nearby_device_streaming" msgid="962267343109051648">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> får adgang til alt, der er synligt eller afspilles på din <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>, herunder lyd, billeder, betalingsoplysninger, adgangskoder og beskeder.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_1">%1$s</xliff:g> kan streame apps og systemfunktioner til <xliff:g id="DEVICE_NAME">%3$s</xliff:g>, indtil du fjerner adgangen til denne tilladelse."</string>
-    <string name="helper_summary_nearby_device_streaming" msgid="8509848562931818793">"<xliff:g id="APP_NAME">%1$s</xliff:g> anmoder om tilladelse på vegne af din <xliff:g id="DEVICE_NAME">%2$s</xliff:g> til at streame apps og andre systemfunktioner mellem dine enheder"</string>
+    <string name="title_nearby_device_streaming" msgid="2727103756701741359">"Vil du give &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; tilladelse til at streame apps fra din <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> til &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;?"</string>
+    <string name="summary_nearby_device_streaming" msgid="70434958004946884">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> får adgang til alt, der er synligt eller afspilles på <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>, herunder lyd, billeder, betalingsoplysninger, adgangskoder og beskeder.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_2">%1$s</xliff:g> kan streame apps til <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g>, indtil du fjerner adgangen til denne tilladelse."</string>
+    <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"<xliff:g id="APP_NAME">%1$s</xliff:g> anmoder om tilladelse på vegne af <xliff:g id="DEVICE_NAME">%2$s</xliff:g> til at streame apps fra din <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"enhed"</string>
     <string name="summary_generic" msgid="1761976003668044801">"Denne app vil kunne synkronisere oplysninger som f.eks. navnet på en person, der ringer, mellem din telefon og den valgte enhed"</string>
     <string name="consent_yes" msgid="8344487259618762872">"Tillad"</string>
diff --git a/packages/CompanionDeviceManager/res/values-de/strings.xml b/packages/CompanionDeviceManager/res/values-de/strings.xml
index 8d65f68..725a42d 100644
--- a/packages/CompanionDeviceManager/res/values-de/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-de/strings.xml
@@ -25,17 +25,23 @@
     <string name="confirmation_title_glasses" msgid="8288346850537727333">"Zulassen, dass &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; das Gerät &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; verwalten darf?"</string>
     <string name="profile_name_glasses" msgid="3506504967216601277">"Gerät"</string>
     <string name="summary_glasses" msgid="5469208629679579157">"Diese App darf dann auf diese Berechtigungen auf deinem Gerät (<xliff:g id="DEVICE_TYPE">%1$s</xliff:g>) zugreifen:"</string>
-    <string name="title_app_streaming" msgid="6845373585257287200">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; erlauben, die Apps auf deinem Gerät (<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>) auf &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt; zu streamen?"</string>
-    <string name="summary_app_streaming" msgid="1274464413649731829">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> hat dann Zugriff auf alle Inhalte, die auf deinem Gerät (<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>) sichtbar sind oder abgespielt werden, einschließlich Audioinhalten, Fotos, Zahlungsinformationen, Passwörter und Nachrichten.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_1">%1$s</xliff:g> kann so lange Apps auf „<xliff:g id="DEVICE_NAME">%3$s</xliff:g>“ streamen, bis du diese Berechtigung entfernst."</string>
-    <string name="helper_summary_app_streaming" msgid="1944832605534698562">"<xliff:g id="APP_NAME">%1$s</xliff:g> bittet im Namen von „<xliff:g id="DEVICE_NAME">%2$s</xliff:g>“ um die Berechtigung, Apps zwischen deinen Geräten anzuzeigen und zu streamen"</string>
+    <!-- no translation found for title_app_streaming (1047090167914857893) -->
+    <skip />
+    <!-- no translation found for summary_app_streaming (7990244299655610920) -->
+    <skip />
+    <!-- no translation found for helper_summary_app_streaming (1872657107404139828) -->
+    <skip />
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4782923323932440751">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; Zugriff auf diese Informationen von deinem Gerät (<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>) gewähren"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
     <string name="helper_summary_computer" msgid="2298803016482139668">"<xliff:g id="APP_NAME">%1$s</xliff:g> bittet im Namen von „<xliff:g id="DEVICE_NAME">%2$s</xliff:g>“ um die Berechtigung, auf die Fotos, Medien und Benachrichtigungen auf deinem Gerät (<xliff:g id="DEVICE_TYPE">%3$s</xliff:g>) zuzugreifen"</string>
-    <string name="title_nearby_device_streaming" msgid="4295322493408411976">"&lt;strong&gt;<xliff:g id="DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt; erlauben, die Apps und Systemfunktionen auf deinem Gerät (<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>) auf &lt;strong&gt;<xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>&lt;/strong&gt; zu streamen?"</string>
-    <string name="summary_nearby_device_streaming" msgid="962267343109051648">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> hat dann Zugriff auf alle Inhalte, die auf deinem Gerät (<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>) sichtbar sind oder abgespielt werden, einschließlich Audioinhalten, Fotos, Zahlungsinformationen, Passwörter und Nachrichten.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_1">%1$s</xliff:g> kann so lange Apps und Systemfunktionen auf „<xliff:g id="DEVICE_NAME">%3$s</xliff:g>“ streamen, bis du diese Berechtigung entfernst."</string>
-    <string name="helper_summary_nearby_device_streaming" msgid="8509848562931818793">"<xliff:g id="APP_NAME">%1$s</xliff:g> bittet im Namen von „<xliff:g id="DEVICE_NAME">%2$s</xliff:g>“ um die Berechtigung, Apps und andere Systemfunktionen zwischen deinen Geräten zu streamen"</string>
+    <!-- no translation found for title_nearby_device_streaming (2727103756701741359) -->
+    <skip />
+    <!-- no translation found for summary_nearby_device_streaming (70434958004946884) -->
+    <skip />
+    <!-- no translation found for helper_summary_nearby_device_streaming (4712712177819370967) -->
+    <skip />
     <string name="profile_name_generic" msgid="6851028682723034988">"Gerät"</string>
     <string name="summary_generic" msgid="1761976003668044801">"Diese App kann dann Daten wie den Namen eines Anrufers zwischen deinem Smartphone und dem ausgewählten Gerät synchronisieren"</string>
     <string name="consent_yes" msgid="8344487259618762872">"Zulassen"</string>
diff --git a/packages/CompanionDeviceManager/res/values-el/strings.xml b/packages/CompanionDeviceManager/res/values-el/strings.xml
index 4a186d5..e465a38 100644
--- a/packages/CompanionDeviceManager/res/values-el/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-el/strings.xml
@@ -25,17 +25,17 @@
     <string name="confirmation_title_glasses" msgid="8288346850537727333">"Να επιτρέπεται στην εφαρμογή &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; να διαχειρίζεται τη συσκευή &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ;"</string>
     <string name="profile_name_glasses" msgid="3506504967216601277">"συσκευή"</string>
     <string name="summary_glasses" msgid="5469208629679579157">"Αυτή η εφαρμογή θα μπορεί να έχει πρόσβαση σε αυτές τις άδειες στη συσκευή <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
-    <string name="title_app_streaming" msgid="6845373585257287200">"Να επιτρέπεται στην εφαρμογή &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; να κάνει ροή των εφαρμογών της συσκευής <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> στη συσκευή &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;;"</string>
-    <string name="summary_app_streaming" msgid="1274464413649731829">"Η εφαρμογή <xliff:g id="APP_NAME_0">%1$s</xliff:g> θα έχει πρόσβαση σε οτιδήποτε είναι ορατό ή αναπαράγεται στη συσκευή <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>, συμπεριλαμβανομένων ήχων, φωτογραφιών, κωδικών πρόσβασης και μηνυμάτων.&lt;br/&gt;&lt;br/&gt;Η εφαρμογή <xliff:g id="APP_NAME_1">%1$s</xliff:g> θα μπορεί να κάνει ροή εφαρμογών στη συσκευή <xliff:g id="DEVICE_NAME">%3$s</xliff:g>, μέχρι να καταργήσετε την πρόσβαση σε αυτή την άδεια."</string>
-    <string name="helper_summary_app_streaming" msgid="1944832605534698562">"Η εφαρμογή <xliff:g id="APP_NAME">%1$s</xliff:g> ζητά άδεια εκ μέρους της συσκευής <xliff:g id="DEVICE_NAME">%2$s</xliff:g> για προβολή και ροή εφαρμογών μεταξύ των συσκευών σας"</string>
+    <string name="title_app_streaming" msgid="1047090167914857893">"Να επιτρέπεται στο &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; η δυνατότητα ροής εφαρμογών και λειτουργιών συστήματος του <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> στο &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;;"</string>
+    <string name="summary_app_streaming" msgid="7990244299655610920">"Το <xliff:g id="APP_NAME_0">%1$s</xliff:g> θα έχει πρόσβαση σε οτιδήποτε είναι ορατό ή αναπαράγεται στο <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> σας, συμπεριλαμβανομένων ήχων, φωτογραφιών, στοιχείων πληρωμής, κωδικών πρόσβασης και μηνυμάτων.&lt;br/&gt;&lt;br/&gt;Το <xliff:g id="APP_NAME_1">%1$s</xliff:g> θα έχει τη δυνατότητα ροής εφαρμογών στο <xliff:g id="DEVICE_NAME">%3$s</xliff:g>, μέχρι να καταργήσετε την πρόσβαση σε αυτή την άδεια."</string>
+    <string name="helper_summary_app_streaming" msgid="1872657107404139828">"Το <xliff:g id="APP_NAME">%1$s</xliff:g> ζητά άδεια εκ μέρους του <xliff:g id="DEVICE_NAME">%2$s</xliff:g> για τη ροή εφαρμογών και λειτουργιών συστήματος από το <xliff:g id="DEVICE_TYPE">%3$s</xliff:g> σας"</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4782923323932440751">"Να επιτρέπεται στην εφαρμογή &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; η πρόσβαση σε αυτές τις πληροφορίες από τη συσκευή σας <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>."</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
     <string name="helper_summary_computer" msgid="2298803016482139668">"Η εφαρμογή <xliff:g id="APP_NAME">%1$s</xliff:g> ζητά άδεια εκ μέρους της συσκευής σας <xliff:g id="DEVICE_NAME">%2$s</xliff:g>, για πρόσβαση στις φωτογραφίες, τα αρχεία μέσων και τις ειδοποιήσεις της συσκευής <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>"</string>
-    <string name="title_nearby_device_streaming" msgid="4295322493408411976">"Να επιτρέπεται στη συσκευή &lt;strong&gt;<xliff:g id="DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt; να κάνει ροή των εφαρμογών και των λειτουργιών συστήματος της συσκευής <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> στη συσκευή &lt;strong&gt;<xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>&lt;/strong&gt;;"</string>
-    <string name="summary_nearby_device_streaming" msgid="962267343109051648">"Η εφαρμογή <xliff:g id="APP_NAME_0">%1$s</xliff:g> θα έχει πρόσβαση σε οτιδήποτε είναι ορατό ή αναπαράγεται στη συσκευή <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>, συμπεριλαμβανομένων ήχων, φωτογραφιών, στοιχείων πληρωμής, κωδικών πρόσβασης και μηνυμάτων.&lt;br/&gt;&lt;br/&gt;Η εφαρμογή <xliff:g id="APP_NAME_1">%1$s</xliff:g> θα μπορεί να κάνει ροή εφαρμογών και λειτουργιών συστήματος στη συσκευή <xliff:g id="DEVICE_NAME">%3$s</xliff:g>, μέχρι να καταργήσετε την πρόσβαση σε αυτή την άδεια."</string>
-    <string name="helper_summary_nearby_device_streaming" msgid="8509848562931818793">"Η εφαρμογή <xliff:g id="APP_NAME">%1$s</xliff:g> ζητά άδεια εκ μέρους της συσκευής σας <xliff:g id="DEVICE_NAME">%2$s</xliff:g> για ροή εφαρμογών και άλλων λειτουργιών συστήματος μεταξύ των συσκευών σας"</string>
+    <string name="title_nearby_device_streaming" msgid="2727103756701741359">"Να επιτρέπεται στο &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; η δυνατότητα ροής εφαρμογών του <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> σας στο &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;;"</string>
+    <string name="summary_nearby_device_streaming" msgid="70434958004946884">"Το <xliff:g id="APP_NAME_0">%1$s</xliff:g> θα έχει πρόσβαση σε οτιδήποτε είναι ορατό ή αναπαράγεται στο <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>, συμπεριλαμβανομένων ήχων, φωτογραφιών, στοιχείων πληρωμής, κωδικών πρόσβασης και μηνυμάτων.&lt;br/&gt;&lt;br/&gt;Το <xliff:g id="APP_NAME_2">%1$s</xliff:g> θα έχει τη δυνατότητα ροής εφαρμογών στο <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g>, μέχρι να καταργήσετε την πρόσβαση σε αυτή την άδεια."</string>
+    <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"Το <xliff:g id="APP_NAME">%1$s</xliff:g> ζητά άδεια εκ μέρους του <xliff:g id="DEVICE_NAME">%2$s</xliff:g> για τη ροή εφαρμογών από το <xliff:g id="DEVICE_TYPE">%3$s</xliff:g> σας"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"συσκευή"</string>
     <string name="summary_generic" msgid="1761976003668044801">"Αυτή η εφαρμογή θα μπορεί να συγχρονίζει πληροφορίες μεταξύ του τηλεφώνου και της επιλεγμένης συσκευής σας, όπως το όνομα ενός ατόμου που σας καλεί."</string>
     <string name="consent_yes" msgid="8344487259618762872">"Να επιτρέπεται"</string>
diff --git a/packages/CompanionDeviceManager/res/values-en-rAU/strings.xml b/packages/CompanionDeviceManager/res/values-en-rAU/strings.xml
index 346758a..92f0a1b 100644
--- a/packages/CompanionDeviceManager/res/values-en-rAU/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-en-rAU/strings.xml
@@ -25,17 +25,17 @@
     <string name="confirmation_title_glasses" msgid="8288346850537727333">"Allow &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; to manage &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
     <string name="profile_name_glasses" msgid="3506504967216601277">"device"</string>
     <string name="summary_glasses" msgid="5469208629679579157">"This app will be allowed to access these permissions on your <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
-    <string name="title_app_streaming" msgid="6845373585257287200">"Allow &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; to stream your <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>\'s apps to &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;?"</string>
-    <string name="summary_app_streaming" msgid="1274464413649731829">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> will have access to anything that\'s visible or played on the <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>, including audio, photos, passwords and messages.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_1">%1$s</xliff:g> will be able to stream apps to <xliff:g id="DEVICE_NAME">%3$s</xliff:g> until you remove access to this permission."</string>
-    <string name="helper_summary_app_streaming" msgid="1944832605534698562">"<xliff:g id="APP_NAME">%1$s</xliff:g> is requesting permission on behalf of your <xliff:g id="DEVICE_NAME">%2$s</xliff:g> to display and stream apps between your devices"</string>
+    <string name="title_app_streaming" msgid="1047090167914857893">"Allow &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; to stream your <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>\'s apps and system features to &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;?"</string>
+    <string name="summary_app_streaming" msgid="7990244299655610920">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> will have access to anything that\'s visible or played on your <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>, including audio, photos, payment info, passwords and messages.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_1">%1$s</xliff:g> will be able to stream apps to <xliff:g id="DEVICE_NAME">%3$s</xliff:g> until you remove access to this permission."</string>
+    <string name="helper_summary_app_streaming" msgid="1872657107404139828">"<xliff:g id="APP_NAME">%1$s</xliff:g> is requesting permission on behalf of <xliff:g id="DEVICE_NAME">%2$s</xliff:g> to stream apps and system features from your <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>"</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4782923323932440751">"Allow &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; to access this information from your <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
     <string name="helper_summary_computer" msgid="2298803016482139668">"<xliff:g id="APP_NAME">%1$s</xliff:g> is requesting permission on behalf of your <xliff:g id="DEVICE_NAME">%2$s</xliff:g> to access your <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>\'s photos, media and notifications"</string>
-    <string name="title_nearby_device_streaming" msgid="4295322493408411976">"Allow &lt;strong&gt;<xliff:g id="DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt; to stream your <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>\'s apps and system features to &lt;strong&gt;<xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>&lt;/strong&gt;?"</string>
-    <string name="summary_nearby_device_streaming" msgid="962267343109051648">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> will have access to anything that\'s visible or played on your <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>, including audio, photos, payment info, passwords and messages.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_1">%1$s</xliff:g> will be able to stream apps and system features to <xliff:g id="DEVICE_NAME">%3$s</xliff:g> until you remove access to this permission."</string>
-    <string name="helper_summary_nearby_device_streaming" msgid="8509848562931818793">"<xliff:g id="APP_NAME">%1$s</xliff:g> is requesting permission on behalf of your <xliff:g id="DEVICE_NAME">%2$s</xliff:g> to stream apps and other system features between your devices"</string>
+    <string name="title_nearby_device_streaming" msgid="2727103756701741359">"Allow &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; to stream your <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>\'s apps to &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;?"</string>
+    <string name="summary_nearby_device_streaming" msgid="70434958004946884">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> will have access to anything that\'s visible or played on <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>, including audio, photos, payment info, passwords and messages.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_2">%1$s</xliff:g> will be able to stream apps to <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> until you remove access to this permission."</string>
+    <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"<xliff:g id="APP_NAME">%1$s</xliff:g> is requesting permission on behalf of <xliff:g id="DEVICE_NAME">%2$s</xliff:g> to stream apps from your <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"device"</string>
     <string name="summary_generic" msgid="1761976003668044801">"This app will be able to sync info, like the name of someone calling, between your phone and the chosen device"</string>
     <string name="consent_yes" msgid="8344487259618762872">"Allow"</string>
diff --git a/packages/CompanionDeviceManager/res/values-en-rCA/strings.xml b/packages/CompanionDeviceManager/res/values-en-rCA/strings.xml
index 5716476..c40018f 100644
--- a/packages/CompanionDeviceManager/res/values-en-rCA/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-en-rCA/strings.xml
@@ -25,17 +25,17 @@
     <string name="confirmation_title_glasses" msgid="8288346850537727333">"Allow &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; to manage &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
     <string name="profile_name_glasses" msgid="3506504967216601277">"device"</string>
     <string name="summary_glasses" msgid="5469208629679579157">"This app will be allowed to access these permissions on your <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
-    <string name="title_app_streaming" msgid="6845373585257287200">"Allow &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; to stream your <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>’s apps to &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;?"</string>
-    <string name="summary_app_streaming" msgid="1274464413649731829">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> will have access to anything that’s visible or played on the <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>, including audio, photos, passwords, and messages.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_1">%1$s</xliff:g> will be able to stream apps to <xliff:g id="DEVICE_NAME">%3$s</xliff:g> until you remove access to this permission."</string>
-    <string name="helper_summary_app_streaming" msgid="1944832605534698562">"<xliff:g id="APP_NAME">%1$s</xliff:g> is requesting permission on behalf of your <xliff:g id="DEVICE_NAME">%2$s</xliff:g> to display and stream apps between your devices"</string>
+    <string name="title_app_streaming" msgid="1047090167914857893">"Allow &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; to stream your <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>’s apps and system features to &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;?"</string>
+    <string name="summary_app_streaming" msgid="7990244299655610920">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> will have access to anything that’s visible or played on your <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>, including audio, photos, payment info, passwords, and messages.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_1">%1$s</xliff:g> will be able to stream apps to <xliff:g id="DEVICE_NAME">%3$s</xliff:g> until you remove access to this permission."</string>
+    <string name="helper_summary_app_streaming" msgid="1872657107404139828">"<xliff:g id="APP_NAME">%1$s</xliff:g> is requesting permission on behalf of <xliff:g id="DEVICE_NAME">%2$s</xliff:g> to stream apps and system features from your <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>"</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4782923323932440751">"Allow &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; to access this information from your <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
     <string name="helper_summary_computer" msgid="2298803016482139668">"<xliff:g id="APP_NAME">%1$s</xliff:g> is requesting permission on behalf of your <xliff:g id="DEVICE_NAME">%2$s</xliff:g> to access your <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>’s photos, media, and notifications"</string>
-    <string name="title_nearby_device_streaming" msgid="4295322493408411976">"Allow &lt;strong&gt;<xliff:g id="DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt; to stream your <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>’s apps and system features to &lt;strong&gt;<xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>&lt;/strong&gt;?"</string>
-    <string name="summary_nearby_device_streaming" msgid="962267343109051648">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> will have access to anything that’s visible or played on your <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>, including audio, photos, payment info, passwords, and messages.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_1">%1$s</xliff:g> will be able to stream apps and system features to <xliff:g id="DEVICE_NAME">%3$s</xliff:g> until you remove access to this permission."</string>
-    <string name="helper_summary_nearby_device_streaming" msgid="8509848562931818793">"<xliff:g id="APP_NAME">%1$s</xliff:g> is requesting permission on behalf of your <xliff:g id="DEVICE_NAME">%2$s</xliff:g> to stream apps and other system features between your devices"</string>
+    <string name="title_nearby_device_streaming" msgid="2727103756701741359">"Allow &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; to stream your <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>’s apps to &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;?"</string>
+    <string name="summary_nearby_device_streaming" msgid="70434958004946884">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> will have access to anything that’s visible or played on <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>, including audio, photos, payment info, passwords, and messages.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_2">%1$s</xliff:g> will be able to stream apps to <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> until you remove access to this permission."</string>
+    <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"<xliff:g id="APP_NAME">%1$s</xliff:g> is requesting permission on behalf of <xliff:g id="DEVICE_NAME">%2$s</xliff:g> to stream apps from your <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"device"</string>
     <string name="summary_generic" msgid="1761976003668044801">"This app will be able to sync info, like the name of someone calling, between your phone and the chosen device"</string>
     <string name="consent_yes" msgid="8344487259618762872">"Allow"</string>
diff --git a/packages/CompanionDeviceManager/res/values-en-rGB/strings.xml b/packages/CompanionDeviceManager/res/values-en-rGB/strings.xml
index 346758a..92f0a1b 100644
--- a/packages/CompanionDeviceManager/res/values-en-rGB/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-en-rGB/strings.xml
@@ -25,17 +25,17 @@
     <string name="confirmation_title_glasses" msgid="8288346850537727333">"Allow &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; to manage &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
     <string name="profile_name_glasses" msgid="3506504967216601277">"device"</string>
     <string name="summary_glasses" msgid="5469208629679579157">"This app will be allowed to access these permissions on your <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
-    <string name="title_app_streaming" msgid="6845373585257287200">"Allow &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; to stream your <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>\'s apps to &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;?"</string>
-    <string name="summary_app_streaming" msgid="1274464413649731829">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> will have access to anything that\'s visible or played on the <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>, including audio, photos, passwords and messages.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_1">%1$s</xliff:g> will be able to stream apps to <xliff:g id="DEVICE_NAME">%3$s</xliff:g> until you remove access to this permission."</string>
-    <string name="helper_summary_app_streaming" msgid="1944832605534698562">"<xliff:g id="APP_NAME">%1$s</xliff:g> is requesting permission on behalf of your <xliff:g id="DEVICE_NAME">%2$s</xliff:g> to display and stream apps between your devices"</string>
+    <string name="title_app_streaming" msgid="1047090167914857893">"Allow &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; to stream your <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>\'s apps and system features to &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;?"</string>
+    <string name="summary_app_streaming" msgid="7990244299655610920">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> will have access to anything that\'s visible or played on your <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>, including audio, photos, payment info, passwords and messages.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_1">%1$s</xliff:g> will be able to stream apps to <xliff:g id="DEVICE_NAME">%3$s</xliff:g> until you remove access to this permission."</string>
+    <string name="helper_summary_app_streaming" msgid="1872657107404139828">"<xliff:g id="APP_NAME">%1$s</xliff:g> is requesting permission on behalf of <xliff:g id="DEVICE_NAME">%2$s</xliff:g> to stream apps and system features from your <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>"</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4782923323932440751">"Allow &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; to access this information from your <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
     <string name="helper_summary_computer" msgid="2298803016482139668">"<xliff:g id="APP_NAME">%1$s</xliff:g> is requesting permission on behalf of your <xliff:g id="DEVICE_NAME">%2$s</xliff:g> to access your <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>\'s photos, media and notifications"</string>
-    <string name="title_nearby_device_streaming" msgid="4295322493408411976">"Allow &lt;strong&gt;<xliff:g id="DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt; to stream your <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>\'s apps and system features to &lt;strong&gt;<xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>&lt;/strong&gt;?"</string>
-    <string name="summary_nearby_device_streaming" msgid="962267343109051648">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> will have access to anything that\'s visible or played on your <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>, including audio, photos, payment info, passwords and messages.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_1">%1$s</xliff:g> will be able to stream apps and system features to <xliff:g id="DEVICE_NAME">%3$s</xliff:g> until you remove access to this permission."</string>
-    <string name="helper_summary_nearby_device_streaming" msgid="8509848562931818793">"<xliff:g id="APP_NAME">%1$s</xliff:g> is requesting permission on behalf of your <xliff:g id="DEVICE_NAME">%2$s</xliff:g> to stream apps and other system features between your devices"</string>
+    <string name="title_nearby_device_streaming" msgid="2727103756701741359">"Allow &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; to stream your <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>\'s apps to &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;?"</string>
+    <string name="summary_nearby_device_streaming" msgid="70434958004946884">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> will have access to anything that\'s visible or played on <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>, including audio, photos, payment info, passwords and messages.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_2">%1$s</xliff:g> will be able to stream apps to <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> until you remove access to this permission."</string>
+    <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"<xliff:g id="APP_NAME">%1$s</xliff:g> is requesting permission on behalf of <xliff:g id="DEVICE_NAME">%2$s</xliff:g> to stream apps from your <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"device"</string>
     <string name="summary_generic" msgid="1761976003668044801">"This app will be able to sync info, like the name of someone calling, between your phone and the chosen device"</string>
     <string name="consent_yes" msgid="8344487259618762872">"Allow"</string>
diff --git a/packages/CompanionDeviceManager/res/values-en-rIN/strings.xml b/packages/CompanionDeviceManager/res/values-en-rIN/strings.xml
index 346758a..92f0a1b 100644
--- a/packages/CompanionDeviceManager/res/values-en-rIN/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-en-rIN/strings.xml
@@ -25,17 +25,17 @@
     <string name="confirmation_title_glasses" msgid="8288346850537727333">"Allow &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; to manage &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
     <string name="profile_name_glasses" msgid="3506504967216601277">"device"</string>
     <string name="summary_glasses" msgid="5469208629679579157">"This app will be allowed to access these permissions on your <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
-    <string name="title_app_streaming" msgid="6845373585257287200">"Allow &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; to stream your <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>\'s apps to &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;?"</string>
-    <string name="summary_app_streaming" msgid="1274464413649731829">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> will have access to anything that\'s visible or played on the <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>, including audio, photos, passwords and messages.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_1">%1$s</xliff:g> will be able to stream apps to <xliff:g id="DEVICE_NAME">%3$s</xliff:g> until you remove access to this permission."</string>
-    <string name="helper_summary_app_streaming" msgid="1944832605534698562">"<xliff:g id="APP_NAME">%1$s</xliff:g> is requesting permission on behalf of your <xliff:g id="DEVICE_NAME">%2$s</xliff:g> to display and stream apps between your devices"</string>
+    <string name="title_app_streaming" msgid="1047090167914857893">"Allow &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; to stream your <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>\'s apps and system features to &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;?"</string>
+    <string name="summary_app_streaming" msgid="7990244299655610920">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> will have access to anything that\'s visible or played on your <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>, including audio, photos, payment info, passwords and messages.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_1">%1$s</xliff:g> will be able to stream apps to <xliff:g id="DEVICE_NAME">%3$s</xliff:g> until you remove access to this permission."</string>
+    <string name="helper_summary_app_streaming" msgid="1872657107404139828">"<xliff:g id="APP_NAME">%1$s</xliff:g> is requesting permission on behalf of <xliff:g id="DEVICE_NAME">%2$s</xliff:g> to stream apps and system features from your <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>"</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4782923323932440751">"Allow &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; to access this information from your <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
     <string name="helper_summary_computer" msgid="2298803016482139668">"<xliff:g id="APP_NAME">%1$s</xliff:g> is requesting permission on behalf of your <xliff:g id="DEVICE_NAME">%2$s</xliff:g> to access your <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>\'s photos, media and notifications"</string>
-    <string name="title_nearby_device_streaming" msgid="4295322493408411976">"Allow &lt;strong&gt;<xliff:g id="DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt; to stream your <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>\'s apps and system features to &lt;strong&gt;<xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>&lt;/strong&gt;?"</string>
-    <string name="summary_nearby_device_streaming" msgid="962267343109051648">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> will have access to anything that\'s visible or played on your <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>, including audio, photos, payment info, passwords and messages.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_1">%1$s</xliff:g> will be able to stream apps and system features to <xliff:g id="DEVICE_NAME">%3$s</xliff:g> until you remove access to this permission."</string>
-    <string name="helper_summary_nearby_device_streaming" msgid="8509848562931818793">"<xliff:g id="APP_NAME">%1$s</xliff:g> is requesting permission on behalf of your <xliff:g id="DEVICE_NAME">%2$s</xliff:g> to stream apps and other system features between your devices"</string>
+    <string name="title_nearby_device_streaming" msgid="2727103756701741359">"Allow &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; to stream your <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>\'s apps to &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;?"</string>
+    <string name="summary_nearby_device_streaming" msgid="70434958004946884">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> will have access to anything that\'s visible or played on <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>, including audio, photos, payment info, passwords and messages.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_2">%1$s</xliff:g> will be able to stream apps to <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> until you remove access to this permission."</string>
+    <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"<xliff:g id="APP_NAME">%1$s</xliff:g> is requesting permission on behalf of <xliff:g id="DEVICE_NAME">%2$s</xliff:g> to stream apps from your <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"device"</string>
     <string name="summary_generic" msgid="1761976003668044801">"This app will be able to sync info, like the name of someone calling, between your phone and the chosen device"</string>
     <string name="consent_yes" msgid="8344487259618762872">"Allow"</string>
diff --git a/packages/CompanionDeviceManager/res/values-en-rXC/strings.xml b/packages/CompanionDeviceManager/res/values-en-rXC/strings.xml
index 6c6a000..80b02cb 100644
--- a/packages/CompanionDeviceManager/res/values-en-rXC/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-en-rXC/strings.xml
@@ -25,17 +25,17 @@
     <string name="confirmation_title_glasses" msgid="8288346850537727333">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‏‏‎‎‎‎‎‏‏‎‎‎‎‏‏‏‏‏‏‎‎‎‏‏‎‎‎‎‎‎‏‎‎‏‏‎‎‎‎‏‏‏‎‏‏‎‎‏‎‏‎‏‏‎‎‏‎‏‎Allow &lt;strong&gt;‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/strong&gt; to manage &lt;strong&gt;‎‏‎‎‏‏‎<xliff:g id="DEVICE_NAME">%2$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/strong&gt;?‎‏‎‎‏‎"</string>
     <string name="profile_name_glasses" msgid="3506504967216601277">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‎‎‏‎‏‎‏‎‎‏‏‎‎‏‏‎‏‏‏‎‏‏‎‎‎‎‎‏‏‏‏‏‏‎‎‎‎‏‎‏‏‎‏‎‎‏‏‎‎‎‏‎‏‏‏‏‎‏‎device‎‏‎‎‏‎"</string>
     <string name="summary_glasses" msgid="5469208629679579157">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‎‏‏‏‏‏‎‎‏‏‎‏‎‎‎‏‎‎‎‎‏‎‎‎‏‎‏‏‎‎‎‎‏‏‎‏‎‎‎‏‏‎‏‎‏‏‎‎‎‎‎‎‎‎‏‎‏‎‏‎This app will be allowed to access these permissions on your ‎‏‎‎‏‏‎<xliff:g id="DEVICE_TYPE">%1$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
-    <string name="title_app_streaming" msgid="6845373585257287200">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‏‎‏‏‏‏‏‏‏‏‏‎‏‎‎‏‏‏‎‎‎‎‎‎‎‏‏‏‏‎‏‎‎‎‎‎‎‏‏‎‏‎‎‏‎‎‏‏‏‎‎‎‏‎‎‎‎‎‎Allow &lt;strong&gt;‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/strong&gt; to stream your ‎‏‎‎‏‏‎<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>‎‏‎‎‏‏‏‎’s apps to &lt;strong&gt;‎‏‎‎‏‏‎<xliff:g id="DEVICE_NAME">%3$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/strong&gt;?‎‏‎‎‏‎"</string>
-    <string name="summary_app_streaming" msgid="1274464413649731829">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‎‎‏‏‎‏‎‏‏‏‏‏‏‎‎‏‏‏‎‏‎‏‎‎‎‎‏‏‎‏‏‏‏‏‎‎‏‏‏‏‎‎‎‎‎‎‎‎‎‎‎‏‏‏‏‎‏‎‏‎‎‏‎‎‏‏‎<xliff:g id="APP_NAME_0">%1$s</xliff:g>‎‏‎‎‏‏‏‎ will have access to anything that’s visible or played on the ‎‏‎‎‏‏‎<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>‎‏‎‎‏‏‏‎, including audio, photos, passwords, and messages.&lt;br/&gt;&lt;br/&gt;‎‏‎‎‏‏‎<xliff:g id="APP_NAME_1">%1$s</xliff:g>‎‏‎‎‏‏‏‎ will be able to stream apps to ‎‏‎‎‏‏‎<xliff:g id="DEVICE_NAME">%3$s</xliff:g>‎‏‎‎‏‏‏‎ until you remove access to this permission.‎‏‎‎‏‎"</string>
-    <string name="helper_summary_app_streaming" msgid="1944832605534698562">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‏‎‏‏‏‏‏‏‎‏‎‏‏‎‏‏‏‎‏‏‏‏‎‎‏‏‎‏‎‏‏‎‎‎‎‏‏‏‏‏‏‎‎‎‏‏‏‏‎‎‎‏‎‎‎‎‏‎‎‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎ is requesting permission on behalf of your ‎‏‎‎‏‏‎<xliff:g id="DEVICE_NAME">%2$s</xliff:g>‎‏‎‎‏‏‏‎ to display and stream apps between your devices‎‏‎‎‏‎"</string>
+    <string name="title_app_streaming" msgid="1047090167914857893">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‏‎‏‎‎‎‏‎‎‎‎‎‎‎‎‎‏‎‏‏‏‏‎‏‎‏‏‏‎‎‎‎‏‎‎‏‎‏‏‏‏‎‏‎‎‎‎‏‎‏‏‎‏‎‎‏‎‏‎Allow &lt;strong&gt;‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/strong&gt; to stream your ‎‏‎‎‏‏‎<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>‎‏‎‎‏‏‏‎’s apps and system features to &lt;strong&gt;‎‏‎‎‏‏‎<xliff:g id="DEVICE_NAME">%3$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/strong&gt;?‎‏‎‎‏‎"</string>
+    <string name="summary_app_streaming" msgid="7990244299655610920">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‏‎‏‏‏‎‎‎‏‏‎‎‎‎‏‏‎‎‏‏‎‏‏‎‏‏‎‎‏‏‏‏‎‏‏‎‎‏‎‎‎‎‎‎‎‎‎‎‏‎‎‎‏‎‏‎‎‎‎‎‏‎‎‏‏‎<xliff:g id="APP_NAME_0">%1$s</xliff:g>‎‏‎‎‏‏‏‎ will have access to anything that’s visible or played on your ‎‏‎‎‏‏‎<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>‎‏‎‎‏‏‏‎, including audio, photos, payment info, passwords, and messages.&lt;br/&gt;&lt;br/&gt;‎‏‎‎‏‏‎<xliff:g id="APP_NAME_1">%1$s</xliff:g>‎‏‎‎‏‏‏‎ will be able to stream apps to ‎‏‎‎‏‏‎<xliff:g id="DEVICE_NAME">%3$s</xliff:g>‎‏‎‎‏‏‏‎ until you remove access to this permission.‎‏‎‎‏‎"</string>
+    <string name="helper_summary_app_streaming" msgid="1872657107404139828">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‎‏‏‏‏‏‏‏‎‏‎‎‎‎‎‎‏‏‏‎‏‏‎‏‏‏‏‎‏‎‏‎‎‎‏‏‏‎‏‏‏‏‎‎‏‎‏‏‎‏‎‎‏‏‎‏‎‎‎‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎ is requesting permission on behalf of ‎‏‎‎‏‏‎<xliff:g id="DEVICE_NAME">%2$s</xliff:g>‎‏‎‎‏‏‏‎ to stream apps and system features from your ‎‏‎‎‏‏‎<xliff:g id="DEVICE_TYPE">%3$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4782923323932440751">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‎‏‎‎‏‏‎‎‎‎‎‎‏‎‏‏‎‏‏‎‏‏‎‏‏‎‎‎‎‎‎‏‏‏‎‏‏‏‎‏‏‎‎‎‏‏‏‏‎‎‎‏‎‏‎‏‏‏‏‎Allow &lt;strong&gt;‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/strong&gt; to access this information from your ‎‏‎‎‏‏‎<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
     <string name="helper_summary_computer" msgid="2298803016482139668">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‏‏‏‏‏‎‎‏‏‎‏‏‏‏‏‏‎‏‎‎‏‎‏‎‎‏‏‏‏‏‎‏‏‎‎‎‎‎‎‎‏‏‏‎‏‎‏‏‏‎‎‎‎‏‎‏‎‎‎‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎ is requesting permission on behalf of your ‎‏‎‎‏‏‎<xliff:g id="DEVICE_NAME">%2$s</xliff:g>‎‏‎‎‏‏‏‎ to access your ‎‏‎‎‏‏‎<xliff:g id="DEVICE_TYPE">%3$s</xliff:g>‎‏‎‎‏‏‏‎’s photos, media, and notifications‎‏‎‎‏‎"</string>
-    <string name="title_nearby_device_streaming" msgid="4295322493408411976">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‎‏‏‏‎‎‏‏‏‎‎‎‎‎‎‏‏‎‏‎‎‎‎‏‏‎‎‏‏‎‏‎‏‏‏‎‏‎‏‏‎‏‎‏‎‎‎‎‎‎‏‎‏‎‎‏‎‎‎‎Allow &lt;strong&gt;‎‏‎‎‏‏‎<xliff:g id="DEVICE_NAME_0">%1$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/strong&gt; to stream your ‎‏‎‎‏‏‎<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>‎‏‎‎‏‏‏‎’s apps and system features to &lt;strong&gt;‎‏‎‎‏‏‎<xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/strong&gt;?‎‏‎‎‏‎"</string>
-    <string name="summary_nearby_device_streaming" msgid="962267343109051648">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‎‏‎‏‎‏‏‎‏‎‏‎‏‎‏‎‎‏‎‎‎‎‏‏‎‎‏‏‎‏‏‏‎‎‏‏‏‏‏‎‎‏‎‏‎‏‎‏‎‏‎‎‎‎‎‎‎‎‎‎‏‎‎‏‏‎<xliff:g id="APP_NAME_0">%1$s</xliff:g>‎‏‎‎‏‏‏‎ will have access to anything that’s visible or played on your ‎‏‎‎‏‏‎<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>‎‏‎‎‏‏‏‎, including audio, photos, payment info, passwords, and messages.&lt;br/&gt;&lt;br/&gt;‎‏‎‎‏‏‎<xliff:g id="APP_NAME_1">%1$s</xliff:g>‎‏‎‎‏‏‏‎ will be able to stream apps and system features to ‎‏‎‎‏‏‎<xliff:g id="DEVICE_NAME">%3$s</xliff:g>‎‏‎‎‏‏‏‎ until you remove access to this permission.‎‏‎‎‏‎"</string>
-    <string name="helper_summary_nearby_device_streaming" msgid="8509848562931818793">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‏‏‎‎‎‎‏‏‎‎‏‎‎‎‎‏‏‏‎‎‎‏‎‏‏‏‎‎‏‎‎‏‏‎‏‏‏‏‎‏‎‏‏‎‏‏‎‎‎‎‏‎‎‏‎‏‎‎‏‎‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎ is requesting permission on behalf of your ‎‏‎‎‏‏‎<xliff:g id="DEVICE_NAME">%2$s</xliff:g>‎‏‎‎‏‏‏‎ to stream apps and other system features between your devices‎‏‎‎‏‎"</string>
+    <string name="title_nearby_device_streaming" msgid="2727103756701741359">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‎‏‏‏‎‏‏‎‎‎‏‎‎‏‏‏‏‎‎‏‏‎‏‎‏‎‏‏‏‏‏‎‏‏‏‏‎‏‎‏‏‏‎‎‏‏‎‎‎‏‎‎‏‎‏‏‏‏‎Allow &lt;strong&gt;‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/strong&gt; to stream your ‎‏‎‎‏‏‎<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>‎‏‎‎‏‏‏‎’s apps to &lt;strong&gt;‎‏‎‎‏‏‎<xliff:g id="DEVICE_NAME">%3$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/strong&gt;?‎‏‎‎‏‎"</string>
+    <string name="summary_nearby_device_streaming" msgid="70434958004946884">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‎‎‏‏‏‏‏‎‏‎‎‎‏‏‏‏‎‎‎‎‏‏‏‎‎‎‏‎‎‏‏‎‏‏‏‎‏‎‎‏‏‏‏‎‎‎‎‏‏‏‏‏‎‎‎‏‎‎‎‎‏‎‎‏‏‎<xliff:g id="APP_NAME_0">%1$s</xliff:g>‎‏‎‎‏‏‏‎ will have access to anything that’s visible or played on ‎‏‎‎‏‏‎<xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>‎‏‎‎‏‏‏‎, including audio, photos, payment info, passwords, and messages.&lt;br/&gt;&lt;br/&gt;‎‏‎‎‏‏‎<xliff:g id="APP_NAME_2">%1$s</xliff:g>‎‏‎‎‏‏‏‎ will be able to stream apps to ‎‏‎‎‏‏‎<xliff:g id="DEVICE_NAME_3">%3$s</xliff:g>‎‏‎‎‏‏‏‎ until you remove access to this permission.‎‏‎‎‏‎"</string>
+    <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‎‎‏‎‏‏‎‎‏‏‎‏‏‏‎‏‎‏‎‏‏‎‎‎‎‎‏‏‎‏‏‎‏‏‏‏‎‎‏‎‏‎‎‏‏‎‎‎‏‎‏‏‏‎‏‎‏‏‏‎‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎ is requesting permission on behalf of ‎‏‎‎‏‏‎<xliff:g id="DEVICE_NAME">%2$s</xliff:g>‎‏‎‎‏‏‏‎ to stream apps from your ‎‏‎‎‏‏‎<xliff:g id="DEVICE_TYPE">%3$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‏‏‎‎‎‏‎‎‏‏‏‎‏‏‏‏‏‎‎‏‎‎‏‎‎‏‏‏‏‎‎‎‏‏‏‎‏‏‏‎‎‎‎‎‎‎‎‏‏‏‎‏‏‎‏‏‎‎‎device‎‏‎‎‏‎"</string>
     <string name="summary_generic" msgid="1761976003668044801">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‎‎‎‏‏‏‎‎‏‏‏‏‎‎‏‎‏‏‏‏‎‏‎‏‏‏‎‎‎‎‏‎‎‏‎‏‏‎‎‏‎‏‎‏‏‎‏‏‎‎‎‎‎‎‎‎‎‏‎This app will be able to sync info, like the name of someone calling, between your phone and the chosen device‎‏‎‎‏‎"</string>
     <string name="consent_yes" msgid="8344487259618762872">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‏‏‏‏‎‎‏‏‎‏‏‎‎‏‎‎‏‎‏‏‏‏‎‎‏‏‏‎‎‏‏‏‏‎‎‏‎‏‏‎‎‏‎‏‏‎‎‎‎‎‎‏‏‏‏‎‎‎‎Allow‎‏‎‎‏‎"</string>
diff --git a/packages/CompanionDeviceManager/res/values-es-rUS/strings.xml b/packages/CompanionDeviceManager/res/values-es-rUS/strings.xml
index 63d57c4..9f62192 100644
--- a/packages/CompanionDeviceManager/res/values-es-rUS/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-es-rUS/strings.xml
@@ -25,17 +25,23 @@
     <string name="confirmation_title_glasses" msgid="8288346850537727333">"Permite que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; administre &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
     <string name="profile_name_glasses" msgid="3506504967216601277">"dispositivo"</string>
     <string name="summary_glasses" msgid="5469208629679579157">"Esta app podrá acceder a los siguientes permisos en tu <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
-    <string name="title_app_streaming" msgid="6845373585257287200">"¿Quieres permitir que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; transmita las apps de <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> a &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;?"</string>
-    <string name="summary_app_streaming" msgid="1274464413649731829">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> tendrá acceso a todo el contenido visible o que se reproduzca en <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>, lo que incluye audio, fotos, contraseñas y mensajes.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_1">%1$s</xliff:g> podrá transmitir apps a <xliff:g id="DEVICE_NAME">%3$s</xliff:g> hasta que se quite el acceso a este permiso."</string>
-    <string name="helper_summary_app_streaming" msgid="1944832605534698562">"<xliff:g id="APP_NAME">%1$s</xliff:g> solicita tu permiso en nombre de <xliff:g id="DEVICE_NAME">%2$s</xliff:g> para mostrar y transmitir apps entre dispositivos"</string>
+    <!-- no translation found for title_app_streaming (1047090167914857893) -->
+    <skip />
+    <!-- no translation found for summary_app_streaming (7990244299655610920) -->
+    <skip />
+    <!-- no translation found for helper_summary_app_streaming (1872657107404139828) -->
+    <skip />
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4782923323932440751">"Permite que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; acceda a esta información de tu <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
     <string name="helper_summary_computer" msgid="2298803016482139668">"<xliff:g id="APP_NAME">%1$s</xliff:g> solicita tu permiso en nombre de <xliff:g id="DEVICE_NAME">%2$s</xliff:g> para acceder a las fotos, el contenido multimedia y las notificaciones de tu <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>"</string>
-    <string name="title_nearby_device_streaming" msgid="4295322493408411976">"¿Quieres permitir que &lt;strong&gt;<xliff:g id="DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt; transmita las apps y las funciones del sistema de <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> a &lt;strong&gt;<xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>&lt;/strong&gt;?"</string>
-    <string name="summary_nearby_device_streaming" msgid="962267343109051648">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> tendrá acceso a todo el contenido visible o que se reproduzca en tu <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>, lo que incluye audio, fotos, información de pago, contraseñas y mensajes.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_1">%1$s</xliff:g> podrá transmitir apps y funciones del sistema a <xliff:g id="DEVICE_NAME">%3$s</xliff:g> hasta que se quite el acceso a este permiso."</string>
-    <string name="helper_summary_nearby_device_streaming" msgid="8509848562931818793">"<xliff:g id="APP_NAME">%1$s</xliff:g> solicita tu permiso en nombre de <xliff:g id="DEVICE_NAME">%2$s</xliff:g> para transmitir apps y otras funciones del sistema entre dispositivos"</string>
+    <!-- no translation found for title_nearby_device_streaming (2727103756701741359) -->
+    <skip />
+    <!-- no translation found for summary_nearby_device_streaming (70434958004946884) -->
+    <skip />
+    <!-- no translation found for helper_summary_nearby_device_streaming (4712712177819370967) -->
+    <skip />
     <string name="profile_name_generic" msgid="6851028682723034988">"dispositivo"</string>
     <string name="summary_generic" msgid="1761976003668044801">"Esta app podrá sincronizar información, como el nombre de la persona que llama, entre el teléfono y el dispositivo elegido"</string>
     <string name="consent_yes" msgid="8344487259618762872">"Permitir"</string>
diff --git a/packages/CompanionDeviceManager/res/values-es/strings.xml b/packages/CompanionDeviceManager/res/values-es/strings.xml
index f929d24..44474b9 100644
--- a/packages/CompanionDeviceManager/res/values-es/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-es/strings.xml
@@ -25,17 +25,23 @@
     <string name="confirmation_title_glasses" msgid="8288346850537727333">"¿Permitir que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; gestione &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
     <string name="profile_name_glasses" msgid="3506504967216601277">"dispositivo"</string>
     <string name="summary_glasses" msgid="5469208629679579157">"Esta aplicación podrá acceder a estos permisos de tu <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
-    <string name="title_app_streaming" msgid="6845373585257287200">"¿Permitir que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; emita las aplicaciones de tu <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> en &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;?"</string>
-    <string name="summary_app_streaming" msgid="1274464413649731829">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> tendrá acceso a todo lo que se vea o se reproduzca en tu <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>, incluidos audio, fotos, contraseñas y mensajes.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_1">%1$s</xliff:g> podrá emitir aplicaciones en <xliff:g id="DEVICE_NAME">%3$s</xliff:g> hasta que quites el acceso a este permiso."</string>
-    <string name="helper_summary_app_streaming" msgid="1944832605534698562">"<xliff:g id="APP_NAME">%1$s</xliff:g> está pidiendo permiso en nombre de tu <xliff:g id="DEVICE_NAME">%2$s</xliff:g> para mostrar y emitir aplicaciones en otros dispositivos tuyos"</string>
+    <!-- no translation found for title_app_streaming (1047090167914857893) -->
+    <skip />
+    <!-- no translation found for summary_app_streaming (7990244299655610920) -->
+    <skip />
+    <!-- no translation found for helper_summary_app_streaming (1872657107404139828) -->
+    <skip />
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4782923323932440751">"Permitir que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; acceda a esta información de tu <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
     <string name="helper_summary_computer" msgid="2298803016482139668">"<xliff:g id="APP_NAME">%1$s</xliff:g> está pidiendo permiso en nombre de tu <xliff:g id="DEVICE_NAME">%2$s</xliff:g> para acceder a las fotos, los archivos multimedia y las notificaciones de tu <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>"</string>
-    <string name="title_nearby_device_streaming" msgid="4295322493408411976">"¿Permitir que &lt;strong&gt;<xliff:g id="DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt; emita las aplicaciones y funciones del sistema de tu<xliff:g id="DEVICE_TYPE">%2$s</xliff:g> en &lt;strong&gt;<xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>&lt;/strong&gt;?"</string>
-    <string name="summary_nearby_device_streaming" msgid="962267343109051648">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> tendrá acceso a todo lo que se vea o se reproduzca en tu <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>, incluidos audio, fotos, información para pagos, contraseñas y mensajes.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_1">%1$s</xliff:g> podrá emitir aplicaciones y funciones del sistema en <xliff:g id="DEVICE_NAME">%3$s</xliff:g> hasta que quites el acceso a este permiso."</string>
-    <string name="helper_summary_nearby_device_streaming" msgid="8509848562931818793">"<xliff:g id="APP_NAME">%1$s</xliff:g> está pidiendo permiso en nombre de tu <xliff:g id="DEVICE_NAME">%2$s</xliff:g> para emitir aplicaciones y otras funciones del sistema en otros dispositivos tuyos"</string>
+    <!-- no translation found for title_nearby_device_streaming (2727103756701741359) -->
+    <skip />
+    <!-- no translation found for summary_nearby_device_streaming (70434958004946884) -->
+    <skip />
+    <!-- no translation found for helper_summary_nearby_device_streaming (4712712177819370967) -->
+    <skip />
     <string name="profile_name_generic" msgid="6851028682723034988">"dispositivo"</string>
     <string name="summary_generic" msgid="1761976003668044801">"Esta aplicación podrá sincronizar información (por ejemplo, el nombre de la persona que te llama) entre tu teléfono y el dispositivo que elijas"</string>
     <string name="consent_yes" msgid="8344487259618762872">"Permitir"</string>
diff --git a/packages/CompanionDeviceManager/res/values-et/strings.xml b/packages/CompanionDeviceManager/res/values-et/strings.xml
index 5fcadcc..8099537 100644
--- a/packages/CompanionDeviceManager/res/values-et/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-et/strings.xml
@@ -25,17 +25,17 @@
     <string name="confirmation_title_glasses" msgid="8288346850537727333">"Lubage rakendusel &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; hallata seadet &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
     <string name="profile_name_glasses" msgid="3506504967216601277">"seade"</string>
     <string name="summary_glasses" msgid="5469208629679579157">"Sellel rakendusel lubatakse juurde pääseda nendele lubadele, mille asukoht on teie <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
-    <string name="title_app_streaming" msgid="6845373585257287200">"Kas lubate rakendusel &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; voogesitada seadmes &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt; rakendusi, mille asukoht on teie <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>?"</string>
-    <string name="summary_app_streaming" msgid="1274464413649731829">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> saab juurdepääsu kõigele, mida teie <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> saab kuvada või esitada sh heli, fotod, paroolid ja sõnumid.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_1">%1$s</xliff:g> saab voogesitada rakendusi ja süsteemifunktsioone seadmes <xliff:g id="DEVICE_NAME">%3$s</xliff:g>, kuni eemaldate juurdepääsu sellele loale."</string>
-    <string name="helper_summary_app_streaming" msgid="1944832605534698562">"Rakendus <xliff:g id="APP_NAME">%1$s</xliff:g> taotleb teie seadme <xliff:g id="DEVICE_NAME">%2$s</xliff:g> nimel luba teie seadmete vahel rakendusi kuvada ja voogesitada"</string>
+    <string name="title_app_streaming" msgid="1047090167914857893">"Kas lubada rakendusel &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; teie seadme &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt; rakendusi ja süsteemifunktsioone seadmesse <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> voogesitada?"</string>
+    <string name="summary_app_streaming" msgid="7990244299655610920">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> saab juurdepääsu kõigele, mida teie seadmes <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> saab kuvada või esitada, sh helile, fotodele, makseteabele, paroolidele ja sõnumitele.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_1">%1$s</xliff:g> saab rakendusi seadmesse <xliff:g id="DEVICE_NAME">%3$s</xliff:g> voogesitada seni, kuni juurdepääsu sellele loale eemaldate."</string>
+    <string name="helper_summary_app_streaming" msgid="1872657107404139828">"Rakendus <xliff:g id="APP_NAME">%1$s</xliff:g> taotleb teie seadme <xliff:g id="DEVICE_NAME">%2$s</xliff:g> nimel luba rakenduste ja süsteemifunktsioonide voogesitamiseks teie seadmest <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>"</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4782923323932440751">"Lubage rakendusel &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; pääseda juurde sellele teabele, mille asukoht on teie <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
     <string name="helper_summary_computer" msgid="2298803016482139668">"Rakendus <xliff:g id="APP_NAME">%1$s</xliff:g> taotleb teie seadme <xliff:g id="DEVICE_NAME">%2$s</xliff:g> nimel luba pääseda juurde fotodele, meediale ja märguannetele, mille asukoht on teie <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>"</string>
-    <string name="title_nearby_device_streaming" msgid="4295322493408411976">"Kas lubate rakendusel &lt;strong&gt;<xliff:g id="DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt; voogesitada seadmes &lt;strong&gt;<xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>&lt;/strong&gt; rakendusi ja süsteemifunktsioone, mille asukoht on teie <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>?"</string>
-    <string name="summary_nearby_device_streaming" msgid="962267343109051648">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> saab juurdepääsu kõigele, mida teie <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> saab kuvada või esitada, sh heli, fotod, makseteave, paroolid ja sõnumid.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_1">%1$s</xliff:g> saab voogesitada rakendusi ja süsteemifunktsioone seadmes <xliff:g id="DEVICE_NAME">%3$s</xliff:g>, kuni eemaldate juurdepääsu sellele loale."</string>
-    <string name="helper_summary_nearby_device_streaming" msgid="8509848562931818793">"Rakendus <xliff:g id="APP_NAME">%1$s</xliff:g> taotleb teie seadme <xliff:g id="DEVICE_NAME">%2$s</xliff:g> nimel luba voogesitada teie seadmete vahel rakendusi ja muid süsteemifunktsioone"</string>
+    <string name="title_nearby_device_streaming" msgid="2727103756701741359">"Kas lubada rakendusel &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; teie seadme &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt; rakendusi seadmesse <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> voogesitada?"</string>
+    <string name="summary_nearby_device_streaming" msgid="70434958004946884">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> saab juurdepääsu kõigele, mida teie seadmes <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g> saab kuvada või esitada, sh helile, fotodele, makseteabele, paroolidele ja sõnumitele.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_2">%1$s</xliff:g> saab rakendusi seadmesse <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> voogesitada seni, kuni juurdepääsu sellele loale eemaldate."</string>
+    <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"Rakendus <xliff:g id="APP_NAME">%1$s</xliff:g> taotleb teie seadme <xliff:g id="DEVICE_NAME">%2$s</xliff:g> nimel luba rakenduste voogesitamiseks teie seadmest <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"seade"</string>
     <string name="summary_generic" msgid="1761976003668044801">"See rakendus saab sünkroonida teavet, näiteks helistaja nime, teie telefoni ja valitud seadme vahel"</string>
     <string name="consent_yes" msgid="8344487259618762872">"Luba"</string>
diff --git a/packages/CompanionDeviceManager/res/values-eu/strings.xml b/packages/CompanionDeviceManager/res/values-eu/strings.xml
index 46da125..dd9b47c 100644
--- a/packages/CompanionDeviceManager/res/values-eu/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-eu/strings.xml
@@ -25,17 +25,17 @@
     <string name="confirmation_title_glasses" msgid="8288346850537727333">"&lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; kudeatzeko baimena eman nahi diozu &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; aplikazioari?"</string>
     <string name="profile_name_glasses" msgid="3506504967216601277">"gailua"</string>
     <string name="summary_glasses" msgid="5469208629679579157">"Baimen hauek izango ditu aplikazioak <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> erabiltzean:"</string>
-    <string name="title_app_streaming" msgid="6845373585257287200">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; aplikazioari zure <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> gailuko aplikazioak <xliff:g id="DEVICE_NAME">%3$s</xliff:g> gailura zuzenean igortzeko baimena eman nahi diozu?"</string>
-    <string name="summary_app_streaming" msgid="1274464413649731829">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> aplikazioak <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> gailuan ikusgai dagoen edo erreproduzitzen den eduki guztia atzitu ahal izango du, audioa, argazkiak, pasahitzak eta mezuak barne.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_1">%1$s</xliff:g> <xliff:g id="DEVICE_NAME">%3$s</xliff:g> gailura aplikazioak zuzenean igortzeko gai izango da, baimen hori kentzen diozun arte."</string>
-    <string name="helper_summary_app_streaming" msgid="1944832605534698562">"Aplikazioak gailuen artean bistaratzeko eta zuzenean igortzeko baimena eskatzen ari da <xliff:g id="APP_NAME">%1$s</xliff:g>, <xliff:g id="DEVICE_NAME">%2$s</xliff:g> gailuaren izenean"</string>
+    <string name="title_app_streaming" msgid="1047090167914857893">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; aplikazioari zure <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> gailuko aplikazioak eta sistemaren eginbideak <xliff:g id="DEVICE_NAME">%3$s</xliff:g> gailura zuzenean igortzeko baimena eman nahi diozu?"</string>
+    <string name="summary_app_streaming" msgid="7990244299655610920">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> aplikazioak <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> gailuan ikusgai dagoen edo erreproduzitzen den eduki guztia atzitu ahal izango du, audioa, argazkiak, ordainketa-informazioa, pasahitzak eta mezuak barne.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_1">%1$s</xliff:g> <xliff:g id="DEVICE_NAME">%3$s</xliff:g> gailura aplikazioak zuzenean igortzeko gai izango da, baimen hori kentzen diozun arte."</string>
+    <string name="helper_summary_app_streaming" msgid="1872657107404139828">"<xliff:g id="DEVICE_TYPE">%3$s</xliff:g> gailutik aplikazioak eta sistemaren eginbideak zuzenean igortzeko baimena eskatzen ari da <xliff:g id="APP_NAME">%1$s</xliff:g>, <xliff:g id="DEVICE_NAME">%2$s</xliff:g> gailuaren izenean"</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4782923323932440751">"Eman informazioa <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> gailutik hartzeko baimena &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; aplikazioari"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
     <string name="helper_summary_computer" msgid="2298803016482139668">"<xliff:g id="DEVICE_TYPE">%3$s</xliff:g> gailuko argazkiak, multimedia-edukia eta jakinarazpenak atzitzeko baimena eskatzen ari da <xliff:g id="APP_NAME">%1$s</xliff:g>, <xliff:g id="DEVICE_NAME">%2$s</xliff:g> gailuaren izenean"</string>
-    <string name="title_nearby_device_streaming" msgid="4295322493408411976">"&lt;strong&gt;<xliff:g id="DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt; aplikazioari zure <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> gailuko aplikazioak eta sistemaren eginbideak <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g> gailura zuzenean igortzeko baimena eman nahi diozu?"</string>
-    <string name="summary_nearby_device_streaming" msgid="962267343109051648">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> aplikazioak <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> gailuan ikusgai dagoen edo erreproduzitzen den eduki guztia atzitu ahal izango du, audioa, argazkiak, ordainketa-informazioa, pasahitzak eta mezuak barne.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_1">%1$s</xliff:g> <xliff:g id="DEVICE_NAME">%3$s</xliff:g> gailura aplikazioak eta sistemaren eginbideak zuzenean igortzeko gai izango da, baimen hori kentzen diozun arte."</string>
-    <string name="helper_summary_nearby_device_streaming" msgid="8509848562931818793">"Aplikazioak eta sistemaren beste eginbide batzuk zure gailuen artean igortzeko baimena eskatzen ari da <xliff:g id="APP_NAME">%1$s</xliff:g>, <xliff:g id="DEVICE_NAME">%2$s</xliff:g> gailuaren izenean"</string>
+    <string name="title_nearby_device_streaming" msgid="2727103756701741359">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; aplikazioari zure <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> gailuko aplikazioak <xliff:g id="DEVICE_NAME">%3$s</xliff:g> gailura zuzenean igortzeko baimena eman nahi diozu?"</string>
+    <string name="summary_nearby_device_streaming" msgid="70434958004946884">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> aplikazioak <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g> gailuan ikusgai dagoen edo erreproduzitzen den eduki guztia atzitu ahal izango du, audioa, argazkiak, ordainketa-informazioa, pasahitzak eta mezuak barne.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_2">%1$s</xliff:g> <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> gailura aplikazioak zuzenean igortzeko gai izango da, baimen hori kentzen diozun arte."</string>
+    <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"<xliff:g id="DEVICE_TYPE">%3$s</xliff:g> gailutik aplikazioak zuzenean igortzeko baimena eskatzen ari da <xliff:g id="APP_NAME">%1$s</xliff:g>, <xliff:g id="DEVICE_NAME">%2$s</xliff:g> gailuaren izenean"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"gailua"</string>
     <string name="summary_generic" msgid="1761976003668044801">"Telefonoaren eta hautatutako gailuaren artean informazioa sinkronizatzeko gai izango da aplikazioa (esate baterako, deitzaileen izenak)"</string>
     <string name="consent_yes" msgid="8344487259618762872">"Eman baimena"</string>
diff --git a/packages/CompanionDeviceManager/res/values-fa/strings.xml b/packages/CompanionDeviceManager/res/values-fa/strings.xml
index 6a651d9..7b013bf 100644
--- a/packages/CompanionDeviceManager/res/values-fa/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-fa/strings.xml
@@ -25,17 +25,17 @@
     <string name="confirmation_title_glasses" msgid="8288346850537727333">"‏به &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; اجازه داده شود &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; را مدیریت کند؟"</string>
     <string name="profile_name_glasses" msgid="3506504967216601277">"دستگاه"</string>
     <string name="summary_glasses" msgid="5469208629679579157">"این برنامه قادر خواهد بود به این اجازه‌ها در <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> شما دسترسی پیدا کند"</string>
-    <string name="title_app_streaming" msgid="6845373585257287200">"‏به &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; اجازه می‌دهید برنامه‌های <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> را در &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt; جاری‌سازی کند؟"</string>
-    <string name="summary_app_streaming" msgid="1274464413649731829">"‏‫<xliff:g id="APP_NAME_0">%1$s</xliff:g> به هرچیزی که در <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> نمایان است یا پخش می‌شود، ازجمله صداها، عکس‌ها، گذرواژه‌ها، و پیام‌ها دسترسی خواهد داشت.&lt;br/&gt;&lt;br/&gt;تا زمانی‌که دسترسی به این اجازه را حذف نکنید، <xliff:g id="APP_NAME_1">%1$s</xliff:g> می‌تواند برنامه‌ها را در <xliff:g id="DEVICE_NAME">%3$s</xliff:g> جاری‌سازی کند."</string>
-    <string name="helper_summary_app_streaming" msgid="1944832605534698562">"‫<xliff:g id="APP_NAME">%1$s</xliff:g> ازطرف <xliff:g id="DEVICE_NAME">%2$s</xliff:g> اجازه می‌خواهد برنامه‌ها را بین دستگاه‌های شما نمایش دهد و جاری‌سازی کند"</string>
+    <string name="title_app_streaming" msgid="1047090167914857893">"‏به &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; اجازه می‌دهید برنامه‌ها و ویژگی‌های سیستم <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> را در &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt; جاری‌سازی کند؟"</string>
+    <string name="summary_app_streaming" msgid="7990244299655610920">"‏‫<xliff:g id="APP_NAME_0">%1$s</xliff:g> به هرچیزی که در <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> شما نمایان است یا پخش می‌شود، ازجمله صداها، عکس‌ها، اطلاعات پرداخت، گذرواژه‌ها، و پیام‌ها دسترسی خواهد داشت.&lt;br/&gt;&lt;br/&gt;تا زمانی‌که دسترسی به این اجازه را حذف نکنید، <xliff:g id="APP_NAME_1">%1$s</xliff:g> می‌تواند برنامه‌ها را در <xliff:g id="DEVICE_NAME">%3$s</xliff:g> جاری‌سازی کند."</string>
+    <string name="helper_summary_app_streaming" msgid="1872657107404139828">"‫<xliff:g id="APP_NAME">%1$s</xliff:g> ازطرف <xliff:g id="DEVICE_NAME">%2$s</xliff:g> اجازه می‌خواهد برنامه‌ها و ویژگی‌های سیستم را از <xliff:g id="DEVICE_TYPE">%3$s</xliff:g> شما جاری‌سازی کند"</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4782923323932440751">"‏اجازه دادن به &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; برای دسترسی به این اطلاعات در <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> شما"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
     <string name="helper_summary_computer" msgid="2298803016482139668">"‫<xliff:g id="APP_NAME">%1$s</xliff:g> ازطرف <xliff:g id="DEVICE_NAME">%2$s</xliff:g> اجازه می‌خواهد به عکس‌ها، رسانه‌ها، و اعلان‌های <xliff:g id="DEVICE_TYPE">%3$s</xliff:g> شما دسترسی پیدا کند"</string>
-    <string name="title_nearby_device_streaming" msgid="4295322493408411976">"‏به &lt;strong&gt;<xliff:g id="DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt; اجازه می‌دهید برنامه‌ها و ویژگی‌های سیستم <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> را در &lt;strong&gt;<xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>&lt;/strong&gt; جاری‌سازی کند؟"</string>
-    <string name="summary_nearby_device_streaming" msgid="962267343109051648">"‏‫<xliff:g id="APP_NAME_0">%1$s</xliff:g> به هرچیزی که در <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> شما نمایان است یا پخش می‌شود، ازجمله صداها، عکس‌ها، اطلاعات پرداخت، گذرواژه‌ها، و پیام‌ها دسترسی خواهد داشت.&lt;br/&gt;&lt;br/&gt;تا زمانی‌که دسترسی به این اجازه را حذف نکنید، <xliff:g id="APP_NAME_1">%1$s</xliff:g> می‌تواند برنامه‌ها و ویژگی‌های سیستم را در <xliff:g id="DEVICE_NAME">%3$s</xliff:g> جاری‌سازی کند."</string>
-    <string name="helper_summary_nearby_device_streaming" msgid="8509848562931818793">"‫<xliff:g id="APP_NAME">%1$s</xliff:g> ازطرف <xliff:g id="DEVICE_NAME">%2$s</xliff:g> اجازه می‌خواهد برنامه‌ها و دیگر ویژگی‌های سیستم را بین دستگاه‌های شما جاری‌سازی کند"</string>
+    <string name="title_nearby_device_streaming" msgid="2727103756701741359">"‏به &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; اجازه می‌دهید برنامه‌های <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> را در &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt; جاری‌سازی کند؟"</string>
+    <string name="summary_nearby_device_streaming" msgid="70434958004946884">"‏‫<xliff:g id="APP_NAME_0">%1$s</xliff:g> به هرچیزی که در <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g> شما نمایان است یا پخش می‌شود، ازجمله صداها، عکس‌ها، اطلاعات پرداخت، گذرواژه‌ها، و پیام‌ها دسترسی خواهد داشت.&lt;br/&gt;&lt;br/&gt;تا زمانی‌که دسترسی به این اجازه را حذف نکنید، <xliff:g id="APP_NAME_2">%1$s</xliff:g> می‌تواند برنامه‌ها را در <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> جاری‌سازی کند."</string>
+    <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"‫<xliff:g id="APP_NAME">%1$s</xliff:g> ازطرف <xliff:g id="DEVICE_NAME">%2$s</xliff:g> اجازه می‌خواهد برنامه‌ها را از <xliff:g id="DEVICE_TYPE">%3$s</xliff:g> شما جاری‌سازی کند"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"دستگاه"</string>
     <string name="summary_generic" msgid="1761976003668044801">"این برنامه مجاز می‌شود اطلاعتی مثل نام شخصی را که تماس می‌گیرد بین تلفن شما و دستگاه انتخاب‌شده همگام‌سازی کند"</string>
     <string name="consent_yes" msgid="8344487259618762872">"اجازه دادن"</string>
diff --git a/packages/CompanionDeviceManager/res/values-fi/strings.xml b/packages/CompanionDeviceManager/res/values-fi/strings.xml
index 5626f0a..f20b71b 100644
--- a/packages/CompanionDeviceManager/res/values-fi/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-fi/strings.xml
@@ -25,17 +25,17 @@
     <string name="confirmation_title_glasses" msgid="8288346850537727333">"Salli, että &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; saa ylläpitää laitetta: &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="profile_name_glasses" msgid="3506504967216601277">"laite"</string>
     <string name="summary_glasses" msgid="5469208629679579157">"Sovellus saa käyttää näitä lupia <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
-    <string name="title_app_streaming" msgid="6845373585257287200">"Saako &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; striimata <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> olevia sovelluksia laitteelle (&lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;)?"</string>
-    <string name="summary_app_streaming" msgid="1274464413649731829">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> saa pääsyn kaikkeen <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> näkyvään tai pelattavaan sisältöön, mukaan lukien audioon, kuviin, salasanoihin ja viesteihin.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_1">%1$s</xliff:g> voi striimata sovelluksia laitteelle (<xliff:g id="DEVICE_NAME">%3$s</xliff:g>), kunnes poistat luvan."</string>
-    <string name="helper_summary_app_streaming" msgid="1944832605534698562">"<xliff:g id="APP_NAME">%1$s</xliff:g> pyytää laitteesi (<xliff:g id="DEVICE_NAME">%2$s</xliff:g>) puolesta lupaa näyttää ja striimata sovelluksia laitteidesi välillä"</string>
+    <string name="title_app_streaming" msgid="1047090167914857893">"Saako &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; striimata <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> olevia sovelluksia ja järjestelmäominaisuuksia laitteelle (&lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;)?"</string>
+    <string name="summary_app_streaming" msgid="7990244299655610920">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> saa pääsyn kaikkeen <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> näkyvään tai pelattavaan sisältöön, mukaan lukien audioon, kuviin, maksutietoihin, salasanoihin ja viesteihin.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_1">%1$s</xliff:g> voi striimata sovelluksia laitteelle (<xliff:g id="DEVICE_NAME">%3$s</xliff:g>), kunnes poistat luvan."</string>
+    <string name="helper_summary_app_streaming" msgid="1872657107404139828">"<xliff:g id="APP_NAME">%1$s</xliff:g> pyytää laitteelta (<xliff:g id="DEVICE_NAME">%2$s</xliff:g>) lupaa striimata sovelluksia ja järjestelmän ominaisuuksia laitteeltasi (<xliff:g id="DEVICE_TYPE">%3$s</xliff:g>)"</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4782923323932440751">"Salli, että &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; saa pääsyn näihin <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> oleviin tietoihin"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
     <string name="helper_summary_computer" msgid="2298803016482139668">"<xliff:g id="APP_NAME">%1$s</xliff:g> pyytää laitteesi (<xliff:g id="DEVICE_NAME">%2$s</xliff:g>) puolesta lupaa päästä <xliff:g id="DEVICE_TYPE">%3$s</xliff:g> oleviin kuviin, mediaan ja ilmoituksiin"</string>
-    <string name="title_nearby_device_streaming" msgid="4295322493408411976">"Saako &lt;strong&gt;<xliff:g id="DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt; striimata <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> olevia sovelluksia ja järjestelmäominaisuuksia laitteelle (&lt;strong&gt;<xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>&lt;/strong&gt;)?"</string>
-    <string name="summary_nearby_device_streaming" msgid="962267343109051648">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> saa pääsyn kaikkeen <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> näkyvään tai pelattavaan sisältöön, mukaan lukien audioon, kuviin, maksutietoihin, salasanoihin ja viesteihin.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_1">%1$s</xliff:g> voi striimata sovelluksia ja järjestelmäominaisuuksia laitteelle (<xliff:g id="DEVICE_NAME">%3$s</xliff:g>), kunnes poistat luvan."</string>
-    <string name="helper_summary_nearby_device_streaming" msgid="8509848562931818793">"<xliff:g id="APP_NAME">%1$s</xliff:g> pyytää laitteesi (<xliff:g id="DEVICE_NAME">%2$s</xliff:g>) puolesta lupaa striimata sovelluksia ja muita järjestelmän ominaisuuksia laitteidesi välillä"</string>
+    <string name="title_nearby_device_streaming" msgid="2727103756701741359">"Saako &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; striimata <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> olevia sovelluksia laitteelle (&lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;)?"</string>
+    <string name="summary_nearby_device_streaming" msgid="70434958004946884">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> saa pääsyn kaikkeen <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g> näkyvään tai pelattavaan sisältöön, mukaan lukien audioon, kuviin, salasanoihin ja viesteihin.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_2">%1$s</xliff:g> voi striimata sovelluksia laitteelle (<xliff:g id="DEVICE_NAME_3">%3$s</xliff:g>), kunnes poistat luvan."</string>
+    <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"<xliff:g id="APP_NAME">%1$s</xliff:g> pyytää lapsen (<xliff:g id="DEVICE_NAME">%2$s</xliff:g>) puolesta lupaa striimata sovelluksia laitteeltasi (<xliff:g id="DEVICE_TYPE">%3$s</xliff:g>)"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"laite"</string>
     <string name="summary_generic" msgid="1761976003668044801">"Sovellus voi synkronoida tietoja (esimerkiksi soittajan nimen) puhelimesi ja valitun laitteen välillä"</string>
     <string name="consent_yes" msgid="8344487259618762872">"Salli"</string>
diff --git a/packages/CompanionDeviceManager/res/values-fr-rCA/strings.xml b/packages/CompanionDeviceManager/res/values-fr-rCA/strings.xml
index 61a8b73..b5de650 100644
--- a/packages/CompanionDeviceManager/res/values-fr-rCA/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-fr-rCA/strings.xml
@@ -25,17 +25,23 @@
     <string name="confirmation_title_glasses" msgid="8288346850537727333">"Autoriser &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; à gérer &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
     <string name="profile_name_glasses" msgid="3506504967216601277">"appareil"</string>
     <string name="summary_glasses" msgid="5469208629679579157">"Cette appli pourra accéder à ces autorisations sur votre <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
-    <string name="title_app_streaming" msgid="6845373585257287200">"Autoriser &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; à diffuser les applis de votre <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> vers &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;?"</string>
-    <string name="summary_app_streaming" msgid="1274464413649731829">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> aura accès à tout ce qui est visible ou lu sur votre<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>, y compris le contenu audio, les photos, les mots de passe et les messages.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_1">%1$s</xliff:g> pourra diffuser des applis vers <xliff:g id="DEVICE_NAME">%3$s</xliff:g> jusqu\'à ce que vous retiriez l\'accès à cette autorisation."</string>
-    <string name="helper_summary_app_streaming" msgid="1944832605534698562">"<xliff:g id="APP_NAME">%1$s</xliff:g> demande l\'autorisation au nom de votre <xliff:g id="DEVICE_NAME">%2$s</xliff:g> pour afficher et diffuser des applis entre vos appareils"</string>
+    <!-- no translation found for title_app_streaming (1047090167914857893) -->
+    <skip />
+    <!-- no translation found for summary_app_streaming (7990244299655610920) -->
+    <skip />
+    <!-- no translation found for helper_summary_app_streaming (1872657107404139828) -->
+    <skip />
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4782923323932440751">"Autoriser &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; à accéder à ces informations à partir de votre <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
     <string name="helper_summary_computer" msgid="2298803016482139668">"<xliff:g id="APP_NAME">%1$s</xliff:g> demande l\'autorisation au nom de votre <xliff:g id="DEVICE_NAME">%2$s</xliff:g> pour accéder aux photos, aux fichiers multimédias et aux notifications de votre <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>"</string>
-    <string name="title_nearby_device_streaming" msgid="4295322493408411976">"Autoriser &lt;strong&gt;<xliff:g id="DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt; à diffuser les applis et les fonctionnalités du système de votre <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> vers &lt;strong&gt;<xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>&lt;/strong&gt;?"</string>
-    <string name="summary_nearby_device_streaming" msgid="962267343109051648">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> aura accès à tout ce qui est visible ou lu sur votre <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>, y compris le contenu audio, les photos, les infos de paiement, les mots de passe et les messages.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_1">%1$s</xliff:g> pourra diffuser des applis et des fonctionnalités du système vers <xliff:g id="DEVICE_NAME">%3$s</xliff:g> jusqu\'à ce que vous retiriez l\'accès à cette autorisation."</string>
-    <string name="helper_summary_nearby_device_streaming" msgid="8509848562931818793">"<xliff:g id="APP_NAME">%1$s</xliff:g> demande l\'autorisation au nom de votre <xliff:g id="DEVICE_NAME">%2$s</xliff:g> pour diffuser des applis et d\'autres fonctionnalités du système entre vos appareils"</string>
+    <!-- no translation found for title_nearby_device_streaming (2727103756701741359) -->
+    <skip />
+    <!-- no translation found for summary_nearby_device_streaming (70434958004946884) -->
+    <skip />
+    <!-- no translation found for helper_summary_nearby_device_streaming (4712712177819370967) -->
+    <skip />
     <string name="profile_name_generic" msgid="6851028682723034988">"appareil"</string>
     <string name="summary_generic" msgid="1761976003668044801">"Cette appli pourra synchroniser des informations, comme le nom de l\'appelant, entre votre téléphone et l\'appareil sélectionné"</string>
     <string name="consent_yes" msgid="8344487259618762872">"Autoriser"</string>
diff --git a/packages/CompanionDeviceManager/res/values-fr/strings.xml b/packages/CompanionDeviceManager/res/values-fr/strings.xml
index b319364..b4933ee2 100644
--- a/packages/CompanionDeviceManager/res/values-fr/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-fr/strings.xml
@@ -25,17 +25,23 @@
     <string name="confirmation_title_glasses" msgid="8288346850537727333">"Autoriser &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; à gérer &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ?"</string>
     <string name="profile_name_glasses" msgid="3506504967216601277">"appareil"</string>
     <string name="summary_glasses" msgid="5469208629679579157">"Cette appli sera autorisée à accéder à ces autorisations sur votre <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
-    <string name="title_app_streaming" msgid="6845373585257287200">"Autoriser &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; à caster les applis de votre <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> sur &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt; ?"</string>
-    <string name="summary_app_streaming" msgid="1274464413649731829">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> aura accès à tout ce qui est visible ou lu sur votre <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>, y compris les contenus audio, les photos, les mots de passe et les messages.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_1">%1$s</xliff:g> pourra caster des applis sur <xliff:g id="DEVICE_NAME">%3$s</xliff:g> jusqu\'à ce que vous supprimiez l\'accès à cette autorisation."</string>
-    <string name="helper_summary_app_streaming" msgid="1944832605534698562">"<xliff:g id="APP_NAME">%1$s</xliff:g> demande l\'autorisation au nom de votre <xliff:g id="DEVICE_NAME">%2$s</xliff:g> pour afficher et caster des applis d\'un appareil à l\'autre"</string>
+    <!-- no translation found for title_app_streaming (1047090167914857893) -->
+    <skip />
+    <!-- no translation found for summary_app_streaming (7990244299655610920) -->
+    <skip />
+    <!-- no translation found for helper_summary_app_streaming (1872657107404139828) -->
+    <skip />
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4782923323932440751">"Autoriser &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; à accéder à ces informations depuis votre <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
     <string name="helper_summary_computer" msgid="2298803016482139668">"<xliff:g id="APP_NAME">%1$s</xliff:g> demande l\'autorisation au nom de votre <xliff:g id="DEVICE_NAME">%2$s</xliff:g> pour accéder aux photos, multimédias et notifications de votre <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>"</string>
-    <string name="title_nearby_device_streaming" msgid="4295322493408411976">"Autoriser &lt;strong&gt;<xliff:g id="DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt; à caster les applis et les fonctionnalités système de votre <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> sur &lt;strong&gt;<xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>&lt;/strong&gt; ?"</string>
-    <string name="summary_nearby_device_streaming" msgid="962267343109051648">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> aura accès à tout ce qui est visible ou lu sur votre <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>, y compris les contenus audio, les photos, les infos de paiement, les mots de passe et les messages.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_1">%1$s</xliff:g> pourra caster des applis et des fonctionnalités système sur <xliff:g id="DEVICE_NAME">%3$s</xliff:g> jusqu\'à ce que vous supprimiez l\'accès à cette autorisation."</string>
-    <string name="helper_summary_nearby_device_streaming" msgid="8509848562931818793">"<xliff:g id="APP_NAME">%1$s</xliff:g> demande l\'autorisation au nom de votre <xliff:g id="DEVICE_NAME">%2$s</xliff:g> pour caster des applis et d\'autres fonctionnalités système d\'un appareil à l\'autre"</string>
+    <!-- no translation found for title_nearby_device_streaming (2727103756701741359) -->
+    <skip />
+    <!-- no translation found for summary_nearby_device_streaming (70434958004946884) -->
+    <skip />
+    <!-- no translation found for helper_summary_nearby_device_streaming (4712712177819370967) -->
+    <skip />
     <string name="profile_name_generic" msgid="6851028682723034988">"appareil"</string>
     <string name="summary_generic" msgid="1761976003668044801">"Cette appli pourra synchroniser des infos, comme le nom de l\'appelant, entre votre téléphone et l\'appareil choisi"</string>
     <string name="consent_yes" msgid="8344487259618762872">"Autoriser"</string>
diff --git a/packages/CompanionDeviceManager/res/values-gl/strings.xml b/packages/CompanionDeviceManager/res/values-gl/strings.xml
index ccab521..a2bd0f8 100644
--- a/packages/CompanionDeviceManager/res/values-gl/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-gl/strings.xml
@@ -25,17 +25,17 @@
     <string name="confirmation_title_glasses" msgid="8288346850537727333">"Queres permitir que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; xestione o dispositivo (&lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;)?"</string>
     <string name="profile_name_glasses" msgid="3506504967216601277">"dispositivo"</string>
     <string name="summary_glasses" msgid="5469208629679579157">"Esta aplicación poderá acceder a estes permisos do dispositivo (<xliff:g id="DEVICE_TYPE">%1$s</xliff:g>)"</string>
-    <string name="title_app_streaming" msgid="6845373585257287200">"Queres permitir que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; emita as aplicacións do dispositivo (<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>) en &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;?"</string>
-    <string name="summary_app_streaming" msgid="1274464413649731829">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> terá acceso a todo o que se vexa ou reproduza no dispositivo (<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>), como audio, fotos, contrasinais e mensaxes.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_1">%1$s</xliff:g> poderá emitir aplicacións en <xliff:g id="DEVICE_NAME">%3$s</xliff:g> ata que quites o acceso a este permiso."</string>
-    <string name="helper_summary_app_streaming" msgid="1944832605534698562">"<xliff:g id="APP_NAME">%1$s</xliff:g> está solicitando permiso en nome do teu dispositivo (<xliff:g id="DEVICE_NAME">%2$s</xliff:g>) para mostrar e emitir aplicacións entre dispositivos"</string>
+    <string name="title_app_streaming" msgid="1047090167914857893">"Queres permitir que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; emita as aplicacións e as funcións do sistema do dispositivo (<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>) en &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;?"</string>
+    <string name="summary_app_streaming" msgid="7990244299655610920">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> terá acceso a todo o que se vexa ou reproduza no teu dispositivo (<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>), como audio, fotos, información de pago, contrasinais e mensaxes.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_1">%1$s</xliff:g> poderá emitir aplicacións en <xliff:g id="DEVICE_NAME">%3$s</xliff:g> ata que quites o acceso a este permiso."</string>
+    <string name="helper_summary_app_streaming" msgid="1872657107404139828">"<xliff:g id="APP_NAME">%1$s</xliff:g> está solicitando permiso en nome dun dispositivo (<xliff:g id="DEVICE_NAME">%2$s</xliff:g>) para emitir aplicacións e funcións do sistema do seguinte aparello: <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>"</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4782923323932440751">"Permitir que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; acceda a esta información do dispositivo (<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>)"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
     <string name="helper_summary_computer" msgid="2298803016482139668">"<xliff:g id="APP_NAME">%1$s</xliff:g> está solicitando permiso en nome do teu dispositivo (<xliff:g id="DEVICE_NAME">%2$s</xliff:g>) para acceder ás fotos, ao contido multimedia e ás notificacións do seguinte aparello: <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>"</string>
-    <string name="title_nearby_device_streaming" msgid="4295322493408411976">"Queres permitir que &lt;strong&gt;<xliff:g id="DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt; emita as aplicacións e as funcións do sistema do dispositivo (<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>) en &lt;strong&gt;<xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>&lt;/strong&gt;?"</string>
-    <string name="summary_nearby_device_streaming" msgid="962267343109051648">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> terá acceso a todo o que se vexa ou reproduza no dispositivo (<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>), como audio, fotos, contrasinais e mensaxes.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_1">%1$s</xliff:g> poderá emitir aplicacións e outras funcións do sistema en <xliff:g id="DEVICE_NAME">%3$s</xliff:g> ata que quites o acceso a este permiso."</string>
-    <string name="helper_summary_nearby_device_streaming" msgid="8509848562931818793">"<xliff:g id="APP_NAME">%1$s</xliff:g> está solicitando permiso en nome do teu dispositivo (<xliff:g id="DEVICE_NAME">%2$s</xliff:g>) para emitir aplicacións e outras funcións do sistema entre dispositivos"</string>
+    <string name="title_nearby_device_streaming" msgid="2727103756701741359">"Queres permitir que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; emita as aplicacións do dispositivo (<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>) en &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;?"</string>
+    <string name="summary_nearby_device_streaming" msgid="70434958004946884">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> terá acceso a todo o que se vexa ou reproduza no teu dispositivo (<xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>), como audio, fotos, información de pago, contrasinais e mensaxes.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_2">%1$s</xliff:g> poderá emitir aplicacións en <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> ata que quites o acceso a este permiso."</string>
+    <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"<xliff:g id="APP_NAME">%1$s</xliff:g> está solicitando permiso en nome dun dispositivo (<xliff:g id="DEVICE_NAME">%2$s</xliff:g>) para emitir aplicacións do seguinte aparello: <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"dispositivo"</string>
     <string name="summary_generic" msgid="1761976003668044801">"Esta aplicación poderá sincronizar información (por exemplo, o nome de quen chama) entre o teléfono e o dispositivo escollido"</string>
     <string name="consent_yes" msgid="8344487259618762872">"Permitir"</string>
diff --git a/packages/CompanionDeviceManager/res/values-gu/strings.xml b/packages/CompanionDeviceManager/res/values-gu/strings.xml
index 816717b..c18ebc0 100644
--- a/packages/CompanionDeviceManager/res/values-gu/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-gu/strings.xml
@@ -25,17 +25,17 @@
     <string name="confirmation_title_glasses" msgid="8288346850537727333">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;ને &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; મેનેજ કરવા માટે મંજૂરી આપીએ?"</string>
     <string name="profile_name_glasses" msgid="3506504967216601277">"ડિવાઇસ"</string>
     <string name="summary_glasses" msgid="5469208629679579157">"આ ઍપને તમારા <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> પર આ પરવાનગીઓ ઍક્સેસ કરવાની મંજૂરી મળશે"</string>
-    <string name="title_app_streaming" msgid="6845373585257287200">"શું &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;ને <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>ની ઍપને &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt; પર સ્ટ્રીમ કરવાની મંજૂરી આપીએ?"</string>
-    <string name="summary_app_streaming" msgid="1274464413649731829">"<xliff:g id="APP_NAME_0">%1$s</xliff:g>ની પાસે એવી બધી બાબતોનો ઍક્સેસ રહેશે જે <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> પર જોઈ શકાતી કે ચલાવી શકાતી હોય, જેમાં ઑડિયો, ફોટા, પાસવર્ડ અને મેસેજ શામેલ છે.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_1">%1$s</xliff:g> ત્યાં સુધી ઍપને <xliff:g id="DEVICE_NAME">%3$s</xliff:g> પર સ્ટ્રીમ કરી શકશે, જ્યાં સુધી તમે આ પરવાનગીનો ઍક્સેસ કાઢી નહીં નાખો."</string>
-    <string name="helper_summary_app_streaming" msgid="1944832605534698562">"તમારા એક ડિવાઇસ પરથી બીજા ડિવાઇસ પર ઍપને ડિસ્પ્લે તેમજ સ્ટ્રીમ કરવા માટે, <xliff:g id="APP_NAME">%1$s</xliff:g> તમારા <xliff:g id="DEVICE_NAME">%2$s</xliff:g> વતી પરવાનગી માગી રહી છે"</string>
+    <string name="title_app_streaming" msgid="1047090167914857893">"શું &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;ને <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>ની ઍપ અને સિસ્ટમની સુવિધાઓને &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt; પર સ્ટ્રીમ કરવાની મંજૂરી આપીએ?"</string>
+    <string name="summary_app_streaming" msgid="7990244299655610920">"<xliff:g id="APP_NAME_0">%1$s</xliff:g>ની પાસે એવી બધી બાબતોનો ઍક્સેસ રહેશે જે <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> પર જોઈ શકાતી કે ચલાવી શકાતી હોય, જેમાં ઑડિયો, ફોટા, પાસવર્ડ અને મેસેજ શામેલ છે.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_1">%1$s</xliff:g> ત્યાં સુધી ઍપ અને સિસ્ટમની સુવિધાઓને <xliff:g id="DEVICE_NAME">%3$s</xliff:g> પર સ્ટ્રીમ કરી શકશે, જ્યાં સુધી તમે આ પરવાનગીનો ઍક્સેસ કાઢી નહીં નાખો."</string>
+    <string name="helper_summary_app_streaming" msgid="1872657107404139828">"<xliff:g id="APP_NAME">%1$s</xliff:g> તમારા <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>માંથી ઍપ અને સિસ્ટમની સુવિધાઓ સ્ટ્રીમ કરવા માટે <xliff:g id="DEVICE_NAME">%2$s</xliff:g> વતી પરવાનગીની વિનંતી કરી રહી છે"</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4782923323932440751">"તમારા <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>માંથી આ માહિતી ઍક્સેસ કરવા માટે, &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;ને મંજૂરી આપો"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
     <string name="helper_summary_computer" msgid="2298803016482139668">"<xliff:g id="APP_NAME">%1$s</xliff:g> તમારા <xliff:g id="DEVICE_NAME">%2$s</xliff:g> વતી તમારા <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>ના ફોટા, મીડિયા અને નોટિફિકેશન ઍક્સેસ કરવાની પરવાનગીની વિનંતી કરી રહી છે"</string>
-    <string name="title_nearby_device_streaming" msgid="4295322493408411976">"શું &lt;strong&gt;<xliff:g id="DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt;ને <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>ની ઍપ અને સિસ્ટમની સુવિધાઓને &lt;strong&gt;<xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>&lt;/strong&gt; પર સ્ટ્રીમ કરવાની મંજૂરી આપીએ?"</string>
-    <string name="summary_nearby_device_streaming" msgid="962267343109051648">"<xliff:g id="APP_NAME_0">%1$s</xliff:g>ની પાસે એવી બધી બાબતોનો ઍક્સેસ રહેશે જે <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> પર જોઈ શકાતી કે ચલાવી શકાતી હોય, જેમાં ઑડિયો, ફોટા, ચુકવણીની માહિતી, પાસવર્ડ અને મેસેજ શામેલ છે.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_1">%1$s</xliff:g> ત્યાં સુધી ઍપ અને સિસ્ટમની સુવિધાઓને <xliff:g id="DEVICE_NAME">%3$s</xliff:g> પર સ્ટ્રીમ કરી શકશે, જ્યાં સુધી તમે આ પરવાનગીનો ઍક્સેસ કાઢી નહીં નાખો."</string>
-    <string name="helper_summary_nearby_device_streaming" msgid="8509848562931818793">"<xliff:g id="APP_NAME">%1$s</xliff:g> તમારા ડિવાઇસ વચ્ચે ઍપ અને સિસ્ટમની અન્ય સુવિધાઓ સ્ટ્રીમ કરવા તમારા <xliff:g id="DEVICE_NAME">%2$s</xliff:g> વતી પરવાનગીની વિનંતી કરી રહી છે"</string>
+    <string name="title_nearby_device_streaming" msgid="2727103756701741359">"શું &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;ને <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>ની ઍપને &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt; પર સ્ટ્રીમ કરવાની મંજૂરી આપીએ?"</string>
+    <string name="summary_nearby_device_streaming" msgid="70434958004946884">"<xliff:g id="APP_NAME_0">%1$s</xliff:g>ની પાસે એવી બધી બાબતોનો ઍક્સેસ રહેશે જે <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g> પર જોઈ શકાતી કે ચલાવી શકાતી હોય, જેમાં ઑડિયો, ફોટા, ચુકવણીની માહિતી, પાસવર્ડ અને મેસેજ શામેલ છે.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_2">%1$s</xliff:g> ત્યાં સુધી ઍપને <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> પર સ્ટ્રીમ કરી શકશે, જ્યાં સુધી તમે આ પરવાનગીનો ઍક્સેસ કાઢી નહીં નાખો."</string>
+    <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"<xliff:g id="APP_NAME">%1$s</xliff:g> તમારા <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>માંથી ઍપ સ્ટ્રીમ કરવા માટે <xliff:g id="DEVICE_NAME">%2$s</xliff:g> વતી પરવાનગીની વિનંતી કરી રહી છે"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"ડિવાઇસ"</string>
     <string name="summary_generic" msgid="1761976003668044801">"આ ઍપ તમારા ફોન અને પસંદ કરેલા ડિવાઇસ વચ્ચે, કૉલ કરનાર કોઈ વ્યક્તિનું નામ જેવી માહિતી સિંક કરી શકશે"</string>
     <string name="consent_yes" msgid="8344487259618762872">"મંજૂરી આપો"</string>
diff --git a/packages/CompanionDeviceManager/res/values-hi/strings.xml b/packages/CompanionDeviceManager/res/values-hi/strings.xml
index b5a40e95f..562f762 100644
--- a/packages/CompanionDeviceManager/res/values-hi/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-hi/strings.xml
@@ -25,17 +25,17 @@
     <string name="confirmation_title_glasses" msgid="8288346850537727333">"क्या &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; को &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; मैनेज करने की अनुमति देनी है?"</string>
     <string name="profile_name_glasses" msgid="3506504967216601277">"डिवाइस"</string>
     <string name="summary_glasses" msgid="5469208629679579157">"यह ऐप्लिकेशन, आपके <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> पर इन अनुमतियों को ऐक्सेस कर पाएगा"</string>
-    <string name="title_app_streaming" msgid="6845373585257287200">"क्या &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; को आपके <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> के ऐप्लिकेशन &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt; पर स्ट्रीम करने की अनुमति देनी है?"</string>
-    <string name="summary_app_streaming" msgid="1274464413649731829">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> के पास ऐसे किसी भी कॉन्टेंट का ऐक्सेस होगा जो इस <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> पर दिखता है या चलाया जाता है. इसमें ऑडियो, फ़ोटो, पासवर्ड, और मैसेज भी शामिल हैं.&lt;br/&gt;&lt;br/&gt;.<xliff:g id="APP_NAME_1">%1$s</xliff:g>, <xliff:g id="DEVICE_NAME">%3$s</xliff:g> पर तब तक ऐप्लिकेशन स्ट्रीम कर पाएगा, जब तक आप यह अनुमति हटा न दें."</string>
-    <string name="helper_summary_app_streaming" msgid="1944832605534698562">"आपके <xliff:g id="DEVICE_NAME">%2$s</xliff:g> की ओर से <xliff:g id="APP_NAME">%1$s</xliff:g>, आपके डिवाइस में मौजूद ऐप्लिकेशन को अन्य डिवाइसों पर दिखाने और स्ट्रीम करने की अनुमति मांग रहा है"</string>
+    <string name="title_app_streaming" msgid="1047090167914857893">"क्या &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; को आपके <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> में मौजूद ऐप्लिकेशन और सिस्टम की सुविधाओं को &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt; पर स्ट्रीम करने की अनुमति देनी है?"</string>
+    <string name="summary_app_streaming" msgid="7990244299655610920">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> के पास ऐसे किसी भी कॉन्टेंट का ऐक्सेस होगा जो आपके <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> पर दिखता है या चलाया जाता है. इसमें ऑडियो, फ़ोटो, पेमेंट संबंधी जानकारी, पासवर्ड, और मैसेज शामिल हैं.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_1">%1$s</xliff:g>, <xliff:g id="DEVICE_NAME">%3$s</xliff:g> पर तब ऐप्लिकेशन को स्ट्रीम कर सकेगा, जब तक आप यह अनुमति हटा न दें."</string>
+    <string name="helper_summary_app_streaming" msgid="1872657107404139828">"<xliff:g id="APP_NAME">%1$s</xliff:g> को <xliff:g id="DEVICE_NAME">%2$s</xliff:g> की ओर से, आपके <xliff:g id="DEVICE_TYPE">%3$s</xliff:g> में मौजूद ऐप्लिकेशन और सिस्टम की सुविधाओं को स्ट्रीम करने की अनुमति चाहिए"</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4782923323932440751">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; को आपके <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> की यह जानकारी ऐक्सेस करने दें"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
     <string name="helper_summary_computer" msgid="2298803016482139668">"आपके <xliff:g id="DEVICE_NAME">%2$s</xliff:g> की ओर से <xliff:g id="APP_NAME">%1$s</xliff:g>, आपके <xliff:g id="DEVICE_TYPE">%3$s</xliff:g> में मौजूद फ़ोटो, मीडिया, और सूचनाओं को ऐक्सेस करने की अनुमति मांग रहा है"</string>
-    <string name="title_nearby_device_streaming" msgid="4295322493408411976">"क्या &lt;strong&gt;<xliff:g id="DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt; को आपके <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> के ऐप्लिकेशन और सिस्टम की सुविधाओं को &lt;strong&gt;<xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>&lt;/strong&gt; पर स्ट्रीम करने की अनुमति देनी है?"</string>
-    <string name="summary_nearby_device_streaming" msgid="962267343109051648">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> के पास ऐसे किसी भी कॉन्टेंट का ऐक्सेस होगा जो आपके <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> पर दिखता है या चलाया जाता है. इसमें ऑडियो, फ़ोटो, पेमेंट की जानकारी, पासवर्ड, और मैसेज भी शामिल हैं.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_1">%1$s</xliff:g>, <xliff:g id="DEVICE_NAME">%3$s</xliff:g> पर तब ऐप्लिकेशन और सिस्टम की सुविधाओं को स्ट्रीम कर सकेगा, जब तक आप यह अनुमति हटा न दें."</string>
-    <string name="helper_summary_nearby_device_streaming" msgid="8509848562931818793">"आपके <xliff:g id="DEVICE_NAME">%2$s</xliff:g> की ओर से <xliff:g id="APP_NAME">%1$s</xliff:g>, आपके डिवाइस में मौजूद ऐप्लिकेशन और सिस्टम की अन्य सुविधाओं को आपके दूसरे डिवाइसों पर स्ट्रीम करने की अनुमति मांग रहा है"</string>
+    <string name="title_nearby_device_streaming" msgid="2727103756701741359">"क्या &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; को आपके <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> में मौजूद ऐप्लिकेशन को &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt; पर स्ट्रीम करने की अनुमति देनी है?"</string>
+    <string name="summary_nearby_device_streaming" msgid="70434958004946884">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> के पास ऐसे किसी भी कॉन्टेंट का ऐक्सेस होगा जो आपके <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g> पर दिखता है या चलाया जाता है. इसमें ऑडियो, फ़ोटो, पेमेंट संबंधी जानकारी, पासवर्ड, और मैसेज शामिल हैं.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_2">%1$s</xliff:g>, <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> पर तब ऐप्लिकेशन को स्ट्रीम कर सकेगा, जब तक आप यह अनुमति हटा न दें."</string>
+    <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"<xliff:g id="APP_NAME">%1$s</xliff:g> को <xliff:g id="DEVICE_NAME">%2$s</xliff:g> की ओर से, आपके <xliff:g id="DEVICE_TYPE">%3$s</xliff:g> में मौजूद ऐप्लिकेशन को स्ट्रीम करने की अनुमति चाहिए"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"डिवाइस"</string>
     <string name="summary_generic" msgid="1761976003668044801">"यह ऐप्लिकेशन, आपके फ़ोन और चुने हुए डिवाइस के बीच जानकारी सिंक करेगा. जैसे, कॉल करने वाले व्यक्ति का नाम"</string>
     <string name="consent_yes" msgid="8344487259618762872">"अनुमति दें"</string>
diff --git a/packages/CompanionDeviceManager/res/values-hr/strings.xml b/packages/CompanionDeviceManager/res/values-hr/strings.xml
index 2d94b67..17b4538 100644
--- a/packages/CompanionDeviceManager/res/values-hr/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-hr/strings.xml
@@ -25,17 +25,17 @@
     <string name="confirmation_title_glasses" msgid="8288346850537727333">"Dopustiti aplikaciji &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; da upravlja uređajem &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
     <string name="profile_name_glasses" msgid="3506504967216601277">"uređaj"</string>
     <string name="summary_glasses" msgid="5469208629679579157">"Aplikacija će moći pristupati ovim dopuštenjima na vašem uređaju <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
-    <string name="title_app_streaming" msgid="6845373585257287200">"Želite li dopustiti aplikaciji &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; da streama aplikacije uređaja <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> na uređaj &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;?"</string>
-    <string name="summary_app_streaming" msgid="1274464413649731829">"Aplikacija <xliff:g id="APP_NAME_0">%1$s</xliff:g> imat će pristup svemu što je vidljivo ili se reproducira na uređaju <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>, uključujući zvuk, fotografije, zaporke i poruke.&lt;br/&gt;&lt;br/&gt;Aplikacija <xliff:g id="APP_NAME_1">%1$s</xliff:g> moći će streamati aplikacije na uređaj <xliff:g id="DEVICE_NAME">%3$s</xliff:g> dok ne uklonite pristup za to dopuštenje."</string>
-    <string name="helper_summary_app_streaming" msgid="1944832605534698562">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> zahtijeva dopuštenje u ime vašeg uređaja <xliff:g id="DEVICE_NAME">%2$s</xliff:g> za prikaz i streaming aplikacija s jednog uređaja na drugi"</string>
+    <string name="title_app_streaming" msgid="1047090167914857893">"Želite li dopustiti aplikaciji &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; da streama aplikacije i značajke sustava uređaja <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> na uređaj &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;?"</string>
+    <string name="summary_app_streaming" msgid="7990244299655610920">"Aplikacija <xliff:g id="APP_NAME_0">%1$s</xliff:g> imat će pristup svemu što je vidljivo ili se reproducira na uređaju <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>, uključujući zvuk, fotografije, podatke o plaćanju, zaporke i poruke.&lt;br/&gt;&lt;br/&gt;Aplikacija <xliff:g id="APP_NAME_1">%1$s</xliff:g> moći će streamati aplikacije na uređaj <xliff:g id="DEVICE_NAME">%3$s</xliff:g> dok ne uklonite pristup za to dopuštenje."</string>
+    <string name="helper_summary_app_streaming" msgid="1872657107404139828">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> zahtijeva dopuštenje u ime uređaja <xliff:g id="DEVICE_NAME">%2$s</xliff:g> za streaming aplikacija i značajki sustava s vašeg uređaja <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>"</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4782923323932440751">"Omogućite aplikaciji &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; da pristupa informacijama s vašeg uređaja <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
     <string name="helper_summary_computer" msgid="2298803016482139668">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> zahtijeva dopuštenje u ime vašeg uređaja <xliff:g id="DEVICE_NAME">%2$s</xliff:g> za pristup fotografijama, medijskim sadržajima i obavijestima na uređaju <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>"</string>
-    <string name="title_nearby_device_streaming" msgid="4295322493408411976">"Želite li dopustiti uređaju &lt;strong&gt;<xliff:g id="DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt; da streama aplikacije i značajke sustava uređaja <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> na uređaj &lt;strong&gt;<xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>&lt;/strong&gt;?"</string>
-    <string name="summary_nearby_device_streaming" msgid="962267343109051648">"Aplikacija <xliff:g id="APP_NAME_0">%1$s</xliff:g> imat će pristup svemu što je vidljivo ili se reproducira na vašem uređaju <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>, uključujući zvuk, fotografije, informacije o plaćanju, zaporke i poruke.&lt;br/&gt;&lt;br/&gt;Aplikacija <xliff:g id="APP_NAME_1">%1$s</xliff:g> moći će streamati aplikacije i značajke sustava na uređaj <xliff:g id="DEVICE_NAME">%3$s</xliff:g> dok ne uklonite pristup za to dopuštenje."</string>
-    <string name="helper_summary_nearby_device_streaming" msgid="8509848562931818793">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> zahtjeva dopuštenja u ime vašeg uređaja <xliff:g id="DEVICE_NAME">%2$s</xliff:g> za stream aplikacija i drugih značajki sustava između vaših uređaja"</string>
+    <string name="title_nearby_device_streaming" msgid="2727103756701741359">"Želite li dopustiti aplikaciji &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; da streama aplikacije uređaja <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> na uređaj &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;?"</string>
+    <string name="summary_nearby_device_streaming" msgid="70434958004946884">"Aplikacija <xliff:g id="APP_NAME_0">%1$s</xliff:g> imat će pristup svemu što je vidljivo ili se reproducira na uređaju <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>, uključujući zvuk, fotografije, podatke o plaćanju, zaporke i poruke.&lt;br/&gt;&lt;br/&gt;Aplikacija <xliff:g id="APP_NAME_2">%1$s</xliff:g> moći će streamati aplikacije na uređaj <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> dok ne uklonite pristup za to dopuštenje."</string>
+    <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> zahtijeva dopuštenje u ime uređaja <xliff:g id="DEVICE_NAME">%2$s</xliff:g> za streaming aplikacija s vašeg uređaja <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"uređaj"</string>
     <string name="summary_generic" msgid="1761976003668044801">"Ta će aplikacija moći sinkronizirati podatke između vašeg telefona i odabranog uređaja, primjerice ime pozivatelja"</string>
     <string name="consent_yes" msgid="8344487259618762872">"Dopusti"</string>
diff --git a/packages/CompanionDeviceManager/res/values-hu/strings.xml b/packages/CompanionDeviceManager/res/values-hu/strings.xml
index b63f8ab..4b0dd49 100644
--- a/packages/CompanionDeviceManager/res/values-hu/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-hu/strings.xml
@@ -25,17 +25,17 @@
     <string name="confirmation_title_glasses" msgid="8288346850537727333">"Engedélyezi, hogy a(z) &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; kezelje a következő eszközt: &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
     <string name="profile_name_glasses" msgid="3506504967216601277">"eszköz"</string>
     <string name="summary_glasses" msgid="5469208629679579157">"Az alkalmazás hozzáférhet majd ezekhez az engedélyekhez a következőn: <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
-    <string name="title_app_streaming" msgid="6845373585257287200">"Engedélyezi a(z) &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; számára a(z) <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> alkalmazásainak streamelését a következőre: &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;?"</string>
-    <string name="summary_app_streaming" msgid="1274464413649731829">"A(z) <xliff:g id="APP_NAME_0">%1$s</xliff:g> hozzáférhet a(z) <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> minden látható vagy lejátszható tartalmához, így az audiotartalmakhoz, fényképekhez, jelszavakhoz és üzenetekhez is.&lt;br/&gt;&lt;br/&gt;Amíg Ön el nem távolítja az ehhez az engedélyhez való hozzáférést, a(z) <xliff:g id="APP_NAME_1">%1$s</xliff:g> képes lesz majd az alkalmazások és a rendszerfunkciók <xliff:g id="DEVICE_NAME">%3$s</xliff:g> eszközre való streamelésére."</string>
-    <string name="helper_summary_app_streaming" msgid="1944832605534698562">"A(z) <xliff:g id="APP_NAME">%1$s</xliff:g> engedélyt kér a(z) <xliff:g id="DEVICE_NAME">%2$s</xliff:g> nevében az alkalmazások eszközök közötti megjelenítéséhez és streameléséhez."</string>
+    <string name="title_app_streaming" msgid="1047090167914857893">"Engedélyezi a(z) &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; számára a(z) <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> alkalmazásainak és rendszerfunkcióinak streamelését a következőre: &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;?"</string>
+    <string name="summary_app_streaming" msgid="7990244299655610920">"A(z) <xliff:g id="APP_NAME_0">%1$s</xliff:g> hozzáférhet a(z) <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> minden látható vagy lejátszható tartalmához, így az audiotartalmakhoz, fényképekhez, fizetési adatokhoz, jelszavakhoz és üzenetekhez is.&lt;br/&gt;&lt;br/&gt;Amíg Ön el nem távolítja az ehhez az engedélyhez való hozzáférést, a(z) <xliff:g id="APP_NAME_1">%1$s</xliff:g> képes lesz majd az alkalmazások <xliff:g id="DEVICE_NAME">%3$s</xliff:g> eszközre való streamelésére."</string>
+    <string name="helper_summary_app_streaming" msgid="1872657107404139828">"A(z) <xliff:g id="APP_NAME">%1$s</xliff:g> engedélyt kér a(z) <xliff:g id="DEVICE_NAME">%2$s</xliff:g> nevében az alkalmazások és rendszerfunkciók következőről való streameléséhez: <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>"</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4782923323932440751">"Engedélyezi a(z) &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; alkalmazás számára az ehhez az információhoz való hozzáférést a(z) <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> esetén"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
     <string name="helper_summary_computer" msgid="2298803016482139668">"A(z) <xliff:g id="APP_NAME">%1$s</xliff:g> engedélyt kér a(z) <xliff:g id="DEVICE_NAME">%2$s</xliff:g> nevében a(z) <xliff:g id="DEVICE_TYPE">%3$s</xliff:g> fotóihoz, médiatartalmaihoz és értesítéseihez való hozzáféréshez"</string>
-    <string name="title_nearby_device_streaming" msgid="4295322493408411976">"Engedélyezi a(z) &lt;strong&gt;<xliff:g id="DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt; számára a(z) <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> alkalmazásainak és rendszerfunkcióinak streamelését a következőre: &lt;strong&gt;<xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>&lt;/strong&gt;?"</string>
-    <string name="summary_nearby_device_streaming" msgid="962267343109051648">"A(z) <xliff:g id="APP_NAME_0">%1$s</xliff:g> hozzáférhet a(z) <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> minden látható vagy lejátszható tartalmához, így az audiotartalmakhoz, fényképekhez, fizetési adatokhoz, jelszavakhoz és üzenetekhez is.&lt;br/&gt;&lt;br/&gt;Amíg Ön el nem távolítja az ehhez az engedélyhez való hozzáférést, a(z) <xliff:g id="APP_NAME_1">%1$s</xliff:g> képes lesz majd az alkalmazások és a rendszerfunkciók <xliff:g id="DEVICE_NAME">%3$s</xliff:g> eszközre való streamelésére."</string>
-    <string name="helper_summary_nearby_device_streaming" msgid="8509848562931818793">"A(z) <xliff:g id="APP_NAME">%1$s</xliff:g> engedélyt kér a(z) <xliff:g id="DEVICE_NAME">%2$s</xliff:g> nevében az alkalmazások és más rendszerfunkcióknak eszközök közötti streameléséhez"</string>
+    <string name="title_nearby_device_streaming" msgid="2727103756701741359">"Engedélyezi a(z) &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; számára a(z) <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> alkalmazásainak streamelését a következőre: &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;?"</string>
+    <string name="summary_nearby_device_streaming" msgid="70434958004946884">"A(z) <xliff:g id="APP_NAME_0">%1$s</xliff:g> hozzáférhet a(z) <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g> minden látható vagy lejátszható tartalmához, így az audiotartalmakhoz, fényképekhez, fizetési adatokhoz, jelszavakhoz és üzenetekhez is.&lt;br/&gt;&lt;br/&gt;Amíg Ön el nem távolítja az ehhez az engedélyhez való hozzáférést, a(z) <xliff:g id="APP_NAME_2">%1$s</xliff:g> képes lesz majd az alkalmazások <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> eszközre való streamelésére."</string>
+    <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"A(z) <xliff:g id="APP_NAME">%1$s</xliff:g> engedélyt kér a(z) <xliff:g id="DEVICE_NAME">%2$s</xliff:g> nevében az alkalmazások következőről való streameléséhez: <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"eszköz"</string>
     <string name="summary_generic" msgid="1761976003668044801">"Ez az alkalmazás képes lesz szinkronizálni az olyan információkat a telefon és a kiválasztott eszköz között, mint például a hívó fél neve."</string>
     <string name="consent_yes" msgid="8344487259618762872">"Engedélyezés"</string>
diff --git a/packages/CompanionDeviceManager/res/values-hy/strings.xml b/packages/CompanionDeviceManager/res/values-hy/strings.xml
index f90a324..a4238c0 100644
--- a/packages/CompanionDeviceManager/res/values-hy/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-hy/strings.xml
@@ -25,17 +25,23 @@
     <string name="confirmation_title_glasses" msgid="8288346850537727333">"Թույլատրե՞լ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; հավելվածին կառավարել &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; սարքը"</string>
     <string name="profile_name_glasses" msgid="3506504967216601277">"սարք"</string>
     <string name="summary_glasses" msgid="5469208629679579157">"Այս հավելվածը կստանա հետևյալ թույլտվությունները ձեր <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>ում"</string>
-    <string name="title_app_streaming" msgid="6845373585257287200">"Թույլատրե՞լ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; հավելվածին հեռարձակել ձեր <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>ի հավելվածները &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt; սարքին։"</string>
-    <string name="summary_app_streaming" msgid="1274464413649731829">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> հավելվածին հասանելի կլինի ձեր <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>ում ցուցադրվող կամ նվագարկվող բովանդակությունը՝ ներառյալ աուդիոն, լուսանկարները, գաղտնաբառերը և հաղորդագրությունները։&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_1">%1$s</xliff:g> հավելվածը կկարողանա հավելվածներ հեռարձակել <xliff:g id="DEVICE_NAME">%3$s</xliff:g> սարքին, քանի դեռ չեք չեղարկել այս թույլտվությունը։"</string>
-    <string name="helper_summary_app_streaming" msgid="1944832605534698562">"<xliff:g id="APP_NAME">%1$s</xliff:g> հավելվածը ձեր <xliff:g id="DEVICE_NAME">%2$s</xliff:g> սարքի անունից թույլտվություն է խնդրում՝ ձեր սարքերի միջև հավելվածներ հեռարձակելու համար"</string>
+    <!-- no translation found for title_app_streaming (1047090167914857893) -->
+    <skip />
+    <!-- no translation found for summary_app_streaming (7990244299655610920) -->
+    <skip />
+    <!-- no translation found for helper_summary_app_streaming (1872657107404139828) -->
+    <skip />
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4782923323932440751">"Թույլատրեք &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; հավելվածին օգտագործել այս տեղեկությունները ձեր <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>ից"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
     <string name="helper_summary_computer" msgid="2298803016482139668">"<xliff:g id="APP_NAME">%1$s</xliff:g> հավելվածը ձեր <xliff:g id="DEVICE_NAME">%2$s</xliff:g> սարքի անունից թույլտվություն է խնդրում՝ ձեր <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>ի լուսանկարները, մեդիաֆայլերն ու ծանուցումները տեսնելու համար"</string>
-    <string name="title_nearby_device_streaming" msgid="4295322493408411976">"Թույլատրե՞լ &lt;strong&gt;<xliff:g id="DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt; սարքին հեռարձակել ձեր <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>ի հավելվածները և համակարգի գործառույթները &lt;strong&gt;<xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>&lt;/strong&gt; սարքին։"</string>
-    <string name="summary_nearby_device_streaming" msgid="962267343109051648">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> հավելվածին հասանելի կլինի ձեր <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>ում ցուցադրվող կամ նվագարկվող բովանդակությունը՝ ներառյալ աուդիոն, լուսանկարները, վճարային տեղեկությունները, գաղտնաբառերը և հաղորդագրությունները։&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_1">%1$s</xliff:g> հավելվածը կկարողանա հավելվածներ և համակարգի գործառույթներ հեռարձակել <xliff:g id="DEVICE_NAME">%3$s</xliff:g> սարքին, քանի դեռ չեք չեղարկել այս թույլտվությունը։"</string>
-    <string name="helper_summary_nearby_device_streaming" msgid="8509848562931818793">"<xliff:g id="APP_NAME">%1$s</xliff:g> հավելվածը ձեր <xliff:g id="DEVICE_NAME">%2$s</xliff:g> սարքի անունից թույլտվություն է խնդրում՝ ձեր սարքերի միջև հավելվածներ հեռարձակելու համար"</string>
+    <!-- no translation found for title_nearby_device_streaming (2727103756701741359) -->
+    <skip />
+    <!-- no translation found for summary_nearby_device_streaming (70434958004946884) -->
+    <skip />
+    <!-- no translation found for helper_summary_nearby_device_streaming (4712712177819370967) -->
+    <skip />
     <string name="profile_name_generic" msgid="6851028682723034988">"սարք"</string>
     <string name="summary_generic" msgid="1761976003668044801">"Այս հավելվածը կկարողանա համաժամացնել ձեր հեռախոսի և ընտրված սարքի տվյալները, օր․՝ զանգողի անունը"</string>
     <string name="consent_yes" msgid="8344487259618762872">"Թույլատրել"</string>
diff --git a/packages/CompanionDeviceManager/res/values-in/strings.xml b/packages/CompanionDeviceManager/res/values-in/strings.xml
index 7a9f485..abb02992 100644
--- a/packages/CompanionDeviceManager/res/values-in/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-in/strings.xml
@@ -25,17 +25,17 @@
     <string name="confirmation_title_glasses" msgid="8288346850537727333">"Izinkan &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; mengelola &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
     <string name="profile_name_glasses" msgid="3506504967216601277">"perangkat"</string>
     <string name="summary_glasses" msgid="5469208629679579157">"Aplikasi ini akan diizinkan mengakses izin ini di <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> Anda"</string>
-    <string name="title_app_streaming" msgid="6845373585257287200">"Izinkan &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; men-streaming aplikasi <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> ke &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;?"</string>
-    <string name="summary_app_streaming" msgid="1274464413649731829">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> akan memiliki akses ke apa pun yang ditampilkan atau diputar di <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>, termasuk audio, foto, sandi, dan pesan.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_1">%1$s</xliff:g> akan dapat men-streaming aplikasi ke <xliff:g id="DEVICE_NAME">%3$s</xliff:g> hingga Anda menghapus izin ini."</string>
-    <string name="helper_summary_app_streaming" msgid="1944832605534698562">"<xliff:g id="APP_NAME">%1$s</xliff:g> meminta izin atas nama <xliff:g id="DEVICE_NAME">%2$s</xliff:g> untuk menampilkan dan men-streaming aplikasi di antara perangkat Anda"</string>
+    <string name="title_app_streaming" msgid="1047090167914857893">"Izinkan &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; melakukan streaming aplikasi dan fitur sistem <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> ke &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;?"</string>
+    <string name="summary_app_streaming" msgid="7990244299655610920">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> akan memiliki akses ke apa pun yang ditampilkan atau diputar di <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>, termasuk audio, foto, info pembayaran, sandi, dan pesan.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_1">%1$s</xliff:g> akan dapat melakukan streaming aplikasi ke <xliff:g id="DEVICE_NAME">%3$s</xliff:g> hingga Anda menghapus izin ini."</string>
+    <string name="helper_summary_app_streaming" msgid="1872657107404139828">"<xliff:g id="APP_NAME">%1$s</xliff:g> meminta izin atas nama <xliff:g id="DEVICE_NAME">%2$s</xliff:g> untuk melakukan streaming aplikasi dan fitur sistem dari <xliff:g id="DEVICE_TYPE">%3$s</xliff:g> Anda"</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4782923323932440751">"Izinkan &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; untuk mengakses informasi ini dari <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> Anda"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
     <string name="helper_summary_computer" msgid="2298803016482139668">"<xliff:g id="APP_NAME">%1$s</xliff:g> meminta izin atas nama <xliff:g id="DEVICE_NAME">%2$s</xliff:g> untuk mengakses foto, media, dan notifikasi <xliff:g id="DEVICE_TYPE">%3$s</xliff:g> Anda"</string>
-    <string name="title_nearby_device_streaming" msgid="4295322493408411976">"Izinkan &lt;strong&gt;<xliff:g id="DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt; men-streaming aplikasi dan fitur sistem <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> ke &lt;strong&gt;<xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>&lt;/strong&gt;?"</string>
-    <string name="summary_nearby_device_streaming" msgid="962267343109051648">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> akan memiliki akses ke apa pun yang ditampilkan atau diputar di <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>, termasuk audio, foto, info pembayaran, sandi, dan pesan.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_1">%1$s</xliff:g> akan dapat men-streaming aplikasi dan fitur sistem ke <xliff:g id="DEVICE_NAME">%3$s</xliff:g> hingga Anda menghapus izin ini."</string>
-    <string name="helper_summary_nearby_device_streaming" msgid="8509848562931818793">"<xliff:g id="APP_NAME">%1$s</xliff:g> meminta izin atas nama <xliff:g id="DEVICE_NAME">%2$s</xliff:g> untuk men-streaming aplikasi dan fitur sistem lainnya di antara perangkat Anda"</string>
+    <string name="title_nearby_device_streaming" msgid="2727103756701741359">"Izinkan &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; melakukan streaming aplikasi <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> ke &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;?"</string>
+    <string name="summary_nearby_device_streaming" msgid="70434958004946884">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> akan memiliki akses ke apa pun yang ditampilkan atau diputar di <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>, termasuk audio, foto, info pembayaran, sandi, dan pesan.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_2">%1$s</xliff:g> akan dapat melakukan streaming aplikasi ke <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> hingga Anda menghapus izin ini."</string>
+    <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"<xliff:g id="APP_NAME">%1$s</xliff:g> meminta izin atas nama <xliff:g id="DEVICE_NAME">%2$s</xliff:g> untuk melakukan streaming aplikasi dari <xliff:g id="DEVICE_TYPE">%3$s</xliff:g> Anda"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"perangkat"</string>
     <string name="summary_generic" msgid="1761976003668044801">"Aplikasi ini akan dapat menyinkronkan info, seperti nama penelepon, antara ponsel dan perangkat yang dipilih"</string>
     <string name="consent_yes" msgid="8344487259618762872">"Izinkan"</string>
diff --git a/packages/CompanionDeviceManager/res/values-is/strings.xml b/packages/CompanionDeviceManager/res/values-is/strings.xml
index 3a41706..7294e16 100644
--- a/packages/CompanionDeviceManager/res/values-is/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-is/strings.xml
@@ -25,17 +25,17 @@
     <string name="confirmation_title_glasses" msgid="8288346850537727333">"Leyfa &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; að stjórna &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
     <string name="profile_name_glasses" msgid="3506504967216601277">"tæki"</string>
     <string name="summary_glasses" msgid="5469208629679579157">"Þetta forrit fær aðgang að eftirfarandi heimildum í <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
-    <string name="title_app_streaming" msgid="6845373585257287200">"Leyfa &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; að streyma forritum í <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> í ;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;?"</string>
-    <string name="summary_app_streaming" msgid="1274464413649731829">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> fær aðgang að öllu sem er sýnilegt eða spilað í <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>, þ.m.t. hljóði, myndum, greiðsluupplýsingum, aðgangsorðum og skilaboðum.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_1">%1$s</xliff:g> getur streymt forritum í <xliff:g id="DEVICE_NAME">%3$s</xliff:g> þar til þú fjarlægir aðgang að þessari heimild."</string>
-    <string name="helper_summary_app_streaming" msgid="1944832605534698562">"<xliff:g id="APP_NAME">%1$s</xliff:g> biður um heimild fyrir <xliff:g id="DEVICE_NAME">%2$s</xliff:g> til að birta og streyma forritum á milli tækjanna þinna"</string>
+    <string name="title_app_streaming" msgid="1047090167914857893">"Leyfa &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; að streyma forritum og kerfiseiginleikum <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> í &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;?"</string>
+    <string name="summary_app_streaming" msgid="7990244299655610920">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> fær aðgang að öllu sem er sýnilegt eða spilað í <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>, þ.m.t. hljóði, myndum, greiðsluupplýsingum, aðgangsorðum og skilaboðum.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_1">%1$s</xliff:g> getur streymt forritum í <xliff:g id="DEVICE_NAME">%3$s</xliff:g> þar til þú fjarlægir þessa heimild."</string>
+    <string name="helper_summary_app_streaming" msgid="1872657107404139828">"<xliff:g id="APP_NAME">%1$s</xliff:g> biður um heimild fyrir hönd <xliff:g id="DEVICE_NAME">%2$s</xliff:g> til að streyma forritum og kerfiseiginleikum úr <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>"</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4782923323932440751">"Veita &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; aðgang að þessum upplýsingum úr <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
     <string name="helper_summary_computer" msgid="2298803016482139668">"<xliff:g id="APP_NAME">%1$s</xliff:g> biður um heimild fyrir <xliff:g id="DEVICE_NAME">%2$s</xliff:g> vegna aðgangs að myndum, margmiðlunarefni og tilkynningum í <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>"</string>
-    <string name="title_nearby_device_streaming" msgid="4295322493408411976">"Leyfa &lt;strong&gt;<xliff:g id="DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt; að streyma forritum og kerfiseiginleikum í <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> í &lt;strong&gt;<xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>&lt;/strong&gt;?"</string>
-    <string name="summary_nearby_device_streaming" msgid="962267343109051648">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> fær aðgang að öllu sem er sýnilegt eða spilað í <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>, þ.m.t. hljóði, myndum, greiðsluupplýsingum, aðgangsorðum og skilaboðum.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_1">%1$s</xliff:g> getur streymt forritum og kerfiseiginleikum í <xliff:g id="DEVICE_NAME">%3$s</xliff:g> þar til þú fjarlægir aðgang að þessari heimild."</string>
-    <string name="helper_summary_nearby_device_streaming" msgid="8509848562931818793">"<xliff:g id="APP_NAME">%1$s</xliff:g> biður um heimild fyrir <xliff:g id="DEVICE_NAME">%2$s</xliff:g> til að streyma forritum og öðrum kerfiseiginleikum á milli tækjanna þinna"</string>
+    <string name="title_nearby_device_streaming" msgid="2727103756701741359">"Leyfa &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; að streyma forritum <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> í &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;?"</string>
+    <string name="summary_nearby_device_streaming" msgid="70434958004946884">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> fær aðgang að öllu sem er sýnilegt eða spilað í <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>, þ.m.t. hljóði, myndum, greiðsluupplýsingum, aðgangsorðum og skilaboðum.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_2">%1$s</xliff:g> getur streymt forritum í <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> þar til þú fjarlægir þessa heimild."</string>
+    <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"<xliff:g id="APP_NAME">%1$s</xliff:g> biður um heimild fyrir hönd <xliff:g id="DEVICE_NAME">%2$s</xliff:g> til að streyma forritum úr <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"tæki"</string>
     <string name="summary_generic" msgid="1761976003668044801">"Þetta forrit mun geta samstillt upplýsingar, t.d. nafn þess sem hringir, á milli símans og valins tækis"</string>
     <string name="consent_yes" msgid="8344487259618762872">"Leyfa"</string>
diff --git a/packages/CompanionDeviceManager/res/values-it/strings.xml b/packages/CompanionDeviceManager/res/values-it/strings.xml
index b85ce64..2fdcaf0 100644
--- a/packages/CompanionDeviceManager/res/values-it/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-it/strings.xml
@@ -25,17 +25,23 @@
     <string name="confirmation_title_glasses" msgid="8288346850537727333">"Vuoi consentire all\'app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; di gestire &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
     <string name="profile_name_glasses" msgid="3506504967216601277">"dispositivo"</string>
     <string name="summary_glasses" msgid="5469208629679579157">"Questa app potrà accedere alle seguenti autorizzazioni <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>:"</string>
-    <string name="title_app_streaming" msgid="6845373585257287200">"Consentire all\'app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; di riprodurre in streaming le app <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> su &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;?"</string>
-    <string name="summary_app_streaming" msgid="1274464413649731829">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> avrà accesso a tutti i contenuti visibili o riprodotti <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>, inclusi audio, foto, password e messaggi.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_1">%1$s</xliff:g> sarà in grado di riprodurre in streaming le app su <xliff:g id="DEVICE_NAME">%3$s</xliff:g> finché non rimuoverai l\'accesso a questa autorizzazione."</string>
-    <string name="helper_summary_app_streaming" msgid="1944832605534698562">"<xliff:g id="APP_NAME">%1$s</xliff:g> richiede per conto di <xliff:g id="DEVICE_NAME">%2$s</xliff:g> l\'autorizzazione a mostrare e riprodurre in streaming app tra i dispositivi"</string>
+    <!-- no translation found for title_app_streaming (1047090167914857893) -->
+    <skip />
+    <!-- no translation found for summary_app_streaming (7990244299655610920) -->
+    <skip />
+    <!-- no translation found for helper_summary_app_streaming (1872657107404139828) -->
+    <skip />
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4782923323932440751">"Consenti all\'app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; di accedere a queste informazioni <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
     <string name="helper_summary_computer" msgid="2298803016482139668">"<xliff:g id="APP_NAME">%1$s</xliff:g> richiede per conto di <xliff:g id="DEVICE_NAME">%2$s</xliff:g> l\'autorizzazione ad accedere a foto, contenuti multimediali e notifiche <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>"</string>
-    <string name="title_nearby_device_streaming" msgid="4295322493408411976">"Consentire all\'app &lt;strong&gt;<xliff:g id="DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt; di riprodurre in streaming le app e le funzionalità di sistema <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> su &lt;strong&gt;<xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>&lt;/strong&gt;?"</string>
-    <string name="summary_nearby_device_streaming" msgid="962267343109051648">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> avrà accesso a tutti i contenuti visibili o riprodotti <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>, inclusi audio, foto, dati di pagamento, password e messaggi.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_1">%1$s</xliff:g> sarà in grado di riprodurre in streaming app e funzionalità di sistema su <xliff:g id="DEVICE_NAME">%3$s</xliff:g> finché non rimuoverai l\'accesso a questa autorizzazione."</string>
-    <string name="helper_summary_nearby_device_streaming" msgid="8509848562931818793">"<xliff:g id="APP_NAME">%1$s</xliff:g> richiede per conto di <xliff:g id="DEVICE_NAME">%2$s</xliff:g> l\'autorizzazione a riprodurre in streaming app e altre funzionalità di sistema tra i dispositivi"</string>
+    <!-- no translation found for title_nearby_device_streaming (2727103756701741359) -->
+    <skip />
+    <!-- no translation found for summary_nearby_device_streaming (70434958004946884) -->
+    <skip />
+    <!-- no translation found for helper_summary_nearby_device_streaming (4712712177819370967) -->
+    <skip />
     <string name="profile_name_generic" msgid="6851028682723034988">"dispositivo"</string>
     <string name="summary_generic" msgid="1761976003668044801">"Questa app potrà sincronizzare informazioni, ad esempio il nome di un chiamante, tra il telefono e il dispositivo scelto"</string>
     <string name="consent_yes" msgid="8344487259618762872">"Consenti"</string>
diff --git a/packages/CompanionDeviceManager/res/values-iw/strings.xml b/packages/CompanionDeviceManager/res/values-iw/strings.xml
index 8148f56..1600031 100644
--- a/packages/CompanionDeviceManager/res/values-iw/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-iw/strings.xml
@@ -25,17 +25,17 @@
     <string name="confirmation_title_glasses" msgid="8288346850537727333">"‏מתן הרשאה לאפליקציה ‎&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&amp;g;‎‏ לנהל את ‎&lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;‎‏"</string>
     <string name="profile_name_glasses" msgid="3506504967216601277">"מכשיר"</string>
     <string name="summary_glasses" msgid="5469208629679579157">"האפליקציה הזו תוכל לגשת להרשאות האלה ב<xliff:g id="DEVICE_TYPE">%1$s</xliff:g> שלך"</string>
-    <string name="title_app_streaming" msgid="6845373585257287200">"‏לאשר לאפליקציית &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; לשדר את האפליקציות של ה<xliff:g id="DEVICE_TYPE">%2$s</xliff:g> ל-&lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;?"</string>
-    <string name="summary_app_streaming" msgid="1274464413649731829">"‏לאפליקציה <xliff:g id="APP_NAME_0">%1$s</xliff:g> תהיה גישה לכל מה שרואים או מפעילים ב<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>, כולל אודיו, תמונות, סיסמאות והודעות.&lt;br/&gt;&lt;br/&gt;לאפליקציה <xliff:g id="APP_NAME_1">%1$s</xliff:g> תהיה אפשרות לשדר אפליקציות ל-<xliff:g id="DEVICE_NAME">%3$s</xliff:g> עד שהגישה להרשאה הזו תוסר."</string>
-    <string name="helper_summary_app_streaming" msgid="1944832605534698562">"האפליקציה <xliff:g id="APP_NAME">%1$s</xliff:g> מבקשת הרשאה ל-<xliff:g id="DEVICE_NAME">%2$s</xliff:g> כדי להציג ולשדר אפליקציות בין המכשירים שלך"</string>
+    <string name="title_app_streaming" msgid="1047090167914857893">"‏לאשר לאפליקציית &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; לשדר את האפליקציות ותכונות המערכת של ה<xliff:g id="DEVICE_TYPE">%2$s</xliff:g> אל &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;?"</string>
+    <string name="summary_app_streaming" msgid="7990244299655610920">"‏לאפליקציה <xliff:g id="APP_NAME_0">%1$s</xliff:g> תהיה גישה לכל מה שרואים או מפעילים ב<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>, כולל אודיו, תמונות, פרטי תשלום, סיסמאות והודעות.&lt;br/&gt;&lt;br/&gt;לאפליקציה <xliff:g id="APP_NAME_1">%1$s</xliff:g> תהיה אפשרות לשדר אפליקציות ל-<xliff:g id="DEVICE_NAME">%3$s</xliff:g> עד שהגישה להרשאה הזו תוסר."</string>
+    <string name="helper_summary_app_streaming" msgid="1872657107404139828">"האפליקציה <xliff:g id="APP_NAME">%1$s</xliff:g> מבקשת הרשאה ל-<xliff:g id="DEVICE_NAME">%2$s</xliff:g> כדי לשדר אפליקציות ותכונות מערכת מה<xliff:g id="DEVICE_TYPE">%3$s</xliff:g>"</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4782923323932440751">"‏מתן אישור לאפליקציה &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; לגשת למידע הזה מה<xliff:g id="DEVICE_TYPE">%2$s</xliff:g> שלך"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
     <string name="helper_summary_computer" msgid="2298803016482139668">"האפליקציה <xliff:g id="APP_NAME">%1$s</xliff:g> מבקשת הרשאה ל-<xliff:g id="DEVICE_NAME">%2$s</xliff:g> כדי לגשת לתמונות, למדיה ולהתראות ב<xliff:g id="DEVICE_TYPE">%3$s</xliff:g>"</string>
-    <string name="title_nearby_device_streaming" msgid="4295322493408411976">"‏לאשר ל-&lt;strong&gt;<xliff:g id="DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt; לשדר אפליקציות ותכונות מערכת אחרות של ה<xliff:g id="DEVICE_TYPE">%2$s</xliff:g> למכשיר &lt;strong&gt;<xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>&lt;/strong&gt;?"</string>
-    <string name="summary_nearby_device_streaming" msgid="962267343109051648">"‏לאפליקציה <xliff:g id="APP_NAME_0">%1$s</xliff:g> תהיה גישה לכל מה שרואים או מפעילים ב<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>, כולל אודיו, תמונות, פרטי תשלום, סיסמאות והודעות.&lt;br/&gt;&lt;br/&gt;לאפליקציה <xliff:g id="APP_NAME_1">%1$s</xliff:g> תהיה אפשרות לשדר אפליקציות ותכונות מערכת ל-<xliff:g id="DEVICE_NAME">%3$s</xliff:g> עד שהגישה להרשאה הזו תוסר."</string>
-    <string name="helper_summary_nearby_device_streaming" msgid="8509848562931818793">"האפליקציה <xliff:g id="APP_NAME">%1$s</xliff:g> מבקשת הרשאה ל<xliff:g id="DEVICE_NAME">%2$s</xliff:g> כדי לשדר אפליקציות ותכונות מערכת אחרות בין המכשירים שלך"</string>
+    <string name="title_nearby_device_streaming" msgid="2727103756701741359">"‏לאשר לאפליקציית &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; לשדר את האפליקציות של ה<xliff:g id="DEVICE_TYPE">%2$s</xliff:g> ל-&lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;?"</string>
+    <string name="summary_nearby_device_streaming" msgid="70434958004946884">"‏לאפליקציה <xliff:g id="APP_NAME_0">%1$s</xliff:g> תהיה גישה לכל מה שרואים או מפעילים ב-<xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>, כולל אודיו, תמונות, פרטי תשלום, סיסמאות והודעות.&lt;br/&gt;&lt;br/&gt;לאפליקציה <xliff:g id="APP_NAME_2">%1$s</xliff:g> תהיה אפשרות לשדר אפליקציות ל-<xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> עד שהגישה להרשאה הזו תוסר."</string>
+    <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"האפליקציה <xliff:g id="APP_NAME">%1$s</xliff:g> מבקשת הרשאה ל-<xliff:g id="DEVICE_NAME">%2$s</xliff:g> כדי לשדר אפליקציות מה<xliff:g id="DEVICE_TYPE">%3$s</xliff:g>"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"מכשיר"</string>
     <string name="summary_generic" msgid="1761976003668044801">"האפליקציה הזו תוכל לסנכרן מידע, כמו השם של מישהו שמתקשר, מהטלפון שלך למכשיר שבחרת"</string>
     <string name="consent_yes" msgid="8344487259618762872">"יש אישור"</string>
diff --git a/packages/CompanionDeviceManager/res/values-ja/strings.xml b/packages/CompanionDeviceManager/res/values-ja/strings.xml
index 173a72f..639e8bc 100644
--- a/packages/CompanionDeviceManager/res/values-ja/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ja/strings.xml
@@ -25,17 +25,17 @@
     <string name="confirmation_title_glasses" msgid="8288346850537727333">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; に &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; の管理を許可しますか?"</string>
     <string name="profile_name_glasses" msgid="3506504967216601277">"デバイス"</string>
     <string name="summary_glasses" msgid="5469208629679579157">"このアプリは、<xliff:g id="DEVICE_TYPE">%1$s</xliff:g>の以下の権限にアクセスできるようになります"</string>
-    <string name="title_app_streaming" msgid="6845373585257287200">"<xliff:g id="DEVICE_TYPE">%2$s</xliff:g> のアプリを &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt; にストリーミングすることを &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; に許可しますか?"</string>
-    <string name="summary_app_streaming" msgid="1274464413649731829">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> は、音声、写真、パスワード、メッセージを含め、<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>で表示、再生されるすべてのコンテンツにアクセスできるようになります。&lt;br/&gt;&lt;br/&gt;この権限へのアクセス権を削除するまで、<xliff:g id="APP_NAME_1">%1$s</xliff:g> は <xliff:g id="DEVICE_NAME">%3$s</xliff:g> にアプリをストリーミングできます。"</string>
-    <string name="helper_summary_app_streaming" msgid="1944832605534698562">"<xliff:g id="APP_NAME">%1$s</xliff:g> が <xliff:g id="DEVICE_NAME">%2$s</xliff:g> に代わってデバイス間でアプリを表示およびストリーミングする権限をリクエストしています"</string>
+    <string name="title_app_streaming" msgid="1047090167914857893">"<xliff:g id="DEVICE_TYPE">%2$s</xliff:g> のアプリとシステム機能を &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt; にストリーミングすることを &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; に許可しますか?"</string>
+    <string name="summary_app_streaming" msgid="7990244299655610920">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> は、音声、写真、お支払い情報、パスワード、メッセージを含め、<xliff:g id="DEVICE_TYPE">%2$s</xliff:g> で表示、再生されるすべてのコンテンツにアクセスできるようになります。&lt;br/&gt;&lt;br/&gt;この権限へのアクセス権を削除するまで、<xliff:g id="APP_NAME_1">%1$s</xliff:g> は <xliff:g id="DEVICE_NAME">%3$s</xliff:g> にアプリをストリーミングできます。"</string>
+    <string name="helper_summary_app_streaming" msgid="1872657107404139828">"<xliff:g id="APP_NAME">%1$s</xliff:g> が <xliff:g id="DEVICE_NAME">%2$s</xliff:g> に代わって、アプリやシステム機能を <xliff:g id="DEVICE_TYPE">%3$s</xliff:g> からストリーミングする権限をリクエストしています"</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4782923323932440751">"<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>のこの情報へのアクセスを &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; に許可"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
     <string name="helper_summary_computer" msgid="2298803016482139668">"<xliff:g id="APP_NAME">%1$s</xliff:g> が <xliff:g id="DEVICE_NAME">%2$s</xliff:g> に代わって<xliff:g id="DEVICE_TYPE">%3$s</xliff:g>の写真、メディア、通知にアクセスする権限をリクエストしています"</string>
-    <string name="title_nearby_device_streaming" msgid="4295322493408411976">"<xliff:g id="DEVICE_TYPE">%2$s</xliff:g> のアプリとシステム機能を &lt;strong&gt;<xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>&lt;/strong&gt; にストリーミングすることを &lt;strong&gt;<xliff:g id="DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt; に許可しますか?"</string>
-    <string name="summary_nearby_device_streaming" msgid="962267343109051648">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> は、音声、写真、お支払い情報、パスワード、メッセージを含め、<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>で表示、再生されるすべてのコンテンツにアクセスできるようになります。&lt;br/&gt;&lt;br/&gt;この権限へのアクセス権を削除するまで、<xliff:g id="APP_NAME_1">%1$s</xliff:g> は <xliff:g id="DEVICE_NAME">%3$s</xliff:g> にアプリとシステム機能をストリーミングできます。"</string>
-    <string name="helper_summary_nearby_device_streaming" msgid="8509848562931818793">"<xliff:g id="APP_NAME">%1$s</xliff:g> が <xliff:g id="DEVICE_NAME">%2$s</xliff:g> に代わって、アプリやその他のシステム機能をデバイス間でストリーミングする権限をリクエストしています"</string>
+    <string name="title_nearby_device_streaming" msgid="2727103756701741359">"<xliff:g id="DEVICE_TYPE">%2$s</xliff:g> のアプリを &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt; にストリーミングすることを &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; に許可しますか?"</string>
+    <string name="summary_nearby_device_streaming" msgid="70434958004946884">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> は、音声、写真、お支払い情報、パスワード、メッセージを含め、<xliff:g id="DEVICE_NAME_1">%3$s</xliff:g> で表示、再生されるすべてのコンテンツにアクセスできるようになります。&lt;br/&gt;&lt;br/&gt;この権限へのアクセス権を削除するまで、<xliff:g id="APP_NAME_2">%1$s</xliff:g> は <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> にアプリをストリーミングできます。"</string>
+    <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"<xliff:g id="APP_NAME">%1$s</xliff:g> が <xliff:g id="DEVICE_NAME">%2$s</xliff:g> に代わって、アプリを <xliff:g id="DEVICE_TYPE">%3$s</xliff:g> からストリーミングする権限をリクエストしています"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"デバイス"</string>
     <string name="summary_generic" msgid="1761976003668044801">"このアプリは、あなたのスマートフォンと選択したデバイスとの間で、通話相手の名前などの情報を同期できるようになります"</string>
     <string name="consent_yes" msgid="8344487259618762872">"許可"</string>
diff --git a/packages/CompanionDeviceManager/res/values-ka/strings.xml b/packages/CompanionDeviceManager/res/values-ka/strings.xml
index 507d13c..949d64b 100644
--- a/packages/CompanionDeviceManager/res/values-ka/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ka/strings.xml
@@ -25,17 +25,17 @@
     <string name="confirmation_title_glasses" msgid="8288346850537727333">"ნება დართეთ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>-ს&lt;/strong&gt; მართოს &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
     <string name="profile_name_glasses" msgid="3506504967216601277">"მოწყობილობა"</string>
     <string name="summary_glasses" msgid="5469208629679579157">"ეს აპი შეძლებს წვდომას თქვენს <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>-ზე არსებულ ამ ნებართვებზე"</string>
-    <string name="title_app_streaming" msgid="6845373585257287200">"გსურთ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;-ს მისცეთ თქვენი <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>-ის აპების სტრიმინგის საშუალება &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;-ზე?"</string>
-    <string name="summary_app_streaming" msgid="1274464413649731829">"<xliff:g id="APP_NAME_0">%1$s</xliff:g>-ს ექნება წვდომა ყველაფერზე, რაც ჩანს ან უკრავს <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>-ზე, მათ შორის, აუდიოზე, ფოტოებზე, პაროლებსა და შეტყობინებებზე.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_1">%1$s</xliff:g> შეძლებს აპების სტრიმინგს <xliff:g id="DEVICE_NAME">%3$s</xliff:g>-ზე მანამ, სანამ თქვენ არ გააუქმებთ წვდომას ამ ნებართვაზე."</string>
-    <string name="helper_summary_app_streaming" msgid="1944832605534698562">"<xliff:g id="APP_NAME">%1$s</xliff:g> ითხოვს ნებართვას თქვენი (<xliff:g id="DEVICE_NAME">%2$s</xliff:g>) სახელით, რათა წარმოაჩინოს და მოახდინოს აპების სტრიმინგი თქვენს მოწყობილობებს შორის"</string>
+    <string name="title_app_streaming" msgid="1047090167914857893">"გსურთ, &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;-ს მისცეთ თქვენი <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>-ის აპებისა და სისტემის ფუნქციების სტრიმინგის საშუალება &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;-ზე?"</string>
+    <string name="summary_app_streaming" msgid="7990244299655610920">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> მიიღებს წვდომას ყველაფერზე, რაც ჩანს ან უკრავს თქვენს <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>-ზე, მათ შორის, აუდიოზე, ფოტოებზე, გადახდის ინფორმაციაზე, პაროლებსა და შეტყობინებებზე.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_1">%1$s</xliff:g> შეძლებს აპების სტრიმინგს <xliff:g id="DEVICE_NAME">%3$s</xliff:g>-ზე მანამ, სანამ თქვენ არ გააუქმებთ წვდომას ამ ნებართვაზე."</string>
+    <string name="helper_summary_app_streaming" msgid="1872657107404139828">"<xliff:g id="APP_NAME">%1$s</xliff:g> ითხოვს ნებართვას <xliff:g id="DEVICE_NAME">%2$s</xliff:g>-ის სახელით აპებისა და სისტემური ფუნქციების სტრიმინგისთვის თქვენი <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>-იდან"</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4782923323932440751">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;-ის წვდომის დაშვება თქვენს <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>-ში არსებულ ამ ინფორმაციაზე"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
     <string name="helper_summary_computer" msgid="2298803016482139668">"<xliff:g id="APP_NAME">%1$s</xliff:g> ითხოვს ნებართვას თქვენი (<xliff:g id="DEVICE_NAME">%2$s</xliff:g>) სახელით, რათა მოიპოვოს წვდომა თქვენი <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>-ის ფოტოებზე, მედიასა და შეტყობინებებზე"</string>
-    <string name="title_nearby_device_streaming" msgid="4295322493408411976">"გსურთ &lt;strong&gt;<xliff:g id="DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt;-ს მისცეთ თქვენი <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>-ის აპებისა და სისტემის ფუნქციების სტრიმინგის საშუალება &lt;strong&gt;<xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>&lt;/strong&gt;-ზე?"</string>
-    <string name="summary_nearby_device_streaming" msgid="962267343109051648">"<xliff:g id="APP_NAME_0">%1$s</xliff:g>-ს ექნება წვდომა ყველაფერზე, რაც ჩანს ან უკრავს თქვენს <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>-ზე, მათ შორის, აუდიოზე, ფოტოებზე, გადახდის ინფორმაციაზე, პაროლებსა და შეტყობინებებზე.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_1">%1$s</xliff:g> შეძლებს აპებისა და სისტემის ფუნქციების სტრიმინგს <xliff:g id="DEVICE_NAME">%3$s</xliff:g>-ზე მანამ, სანამ თქვენ არ გააუქმებთ წვდომას ამ ნებართვაზე."</string>
-    <string name="helper_summary_nearby_device_streaming" msgid="8509848562931818793">"<xliff:g id="APP_NAME">%1$s</xliff:g> ითხოვს ნებართვას თქვენი (<xliff:g id="DEVICE_NAME">%2$s</xliff:g>) სახელით, რათა მოახდინოს აპებისა და სისტემის სხვა ფუნქციების სტრიმინგი თქვენს მოწყობილობებს შორის"</string>
+    <string name="title_nearby_device_streaming" msgid="2727103756701741359">"გსურთ, &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;-ს მისცეთ თქვენი <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>-ის აპების სტრიმინგის საშუალება &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;-ზე?"</string>
+    <string name="summary_nearby_device_streaming" msgid="70434958004946884">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> მიიღებს წვდომას ყველაფერზე, რაც ჩანს ან უკრავს <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>-ზე, მათ შორის, აუდიოზე, ფოტოებზე, პაროლებსა და შეტყობინებებზე.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_2">%1$s</xliff:g> შეძლებს აპების სტრიმინგს <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g>-ზე მანამ, სანამ თქვენ არ გააუქმებთ წვდომას ამ ნებართვაზე."</string>
+    <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"<xliff:g id="APP_NAME">%1$s</xliff:g> ითხოვს ნებართვას <xliff:g id="DEVICE_NAME">%2$s</xliff:g>-ის სახელით აპების სტრიმინგისთვის თქვენი <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>-იდან"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"მოწყობილობა"</string>
     <string name="summary_generic" msgid="1761976003668044801">"ეს აპი შეძლებს ინფორმაციის სინქრონიზებას თქვენს ტელეფონსა და თქვენ მიერ არჩეულ მოწყობილობას შორის, მაგალითად, იმ ადამიანის სახელის, რომელიც გირეკავთ"</string>
     <string name="consent_yes" msgid="8344487259618762872">"დაშვება"</string>
diff --git a/packages/CompanionDeviceManager/res/values-kk/strings.xml b/packages/CompanionDeviceManager/res/values-kk/strings.xml
index 16a02dc..8351542 100644
--- a/packages/CompanionDeviceManager/res/values-kk/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-kk/strings.xml
@@ -25,17 +25,17 @@
     <string name="confirmation_title_glasses" msgid="8288346850537727333">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; қолданбасына &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; құрылғысын басқаруға рұқсат беру керек пе?"</string>
     <string name="profile_name_glasses" msgid="3506504967216601277">"құрылғы"</string>
     <string name="summary_glasses" msgid="5469208629679579157">"Бұл қолданба құрылғыда (<xliff:g id="DEVICE_TYPE">%1$s</xliff:g>) осы рұқсаттарды пайдалана алады."</string>
-    <string name="title_app_streaming" msgid="6845373585257287200">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; қолданбасына құрылғыңыздағы (<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>) қолданбаларды &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt; құрылғысына трансляциялауға рұқсат берілсін бе?"</string>
-    <string name="summary_app_streaming" msgid="1274464413649731829">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> қолданбасы құрылғыда (<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>) көрінетін не ойнатылатын барлық контентті (аудиофайлдарды, фотосуреттерді, құпия сөздер мен хабарларды қоса алғанда) пайдалана алады.&lt;br/&gt;&lt;br/&gt;Осы рұқсатты өшірмесеңіз, <xliff:g id="APP_NAME_1">%1$s</xliff:g> қолданбасы құрылғысына (<xliff:g id="DEVICE_NAME">%3$s</xliff:g>) қолданбаларды трансляциялай алады."</string>
-    <string name="helper_summary_app_streaming" msgid="1944832605534698562">"<xliff:g id="APP_NAME">%1$s</xliff:g> қолданбасы <xliff:g id="DEVICE_NAME">%2$s</xliff:g> атынан құрылғыларыңыздың арасында қолданбаларды көрсетуге және трансляциялауға рұқсат сұрайды."</string>
+    <string name="title_app_streaming" msgid="1047090167914857893">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; қолданбасына құрылғыңыздағы (<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>) қолданбалар мен жүйе функцияларын &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt; құрылғысына трансляциялауға рұқсат берілсін бе?"</string>
+    <string name="summary_app_streaming" msgid="7990244299655610920">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> қолданбасы құрылғыңызда (<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>) көрінетін не ойнатылатын барлық контентті, соның ішінде аудиофайлдарды, фотосуреттерді, төлем туралы ақпаратты, құпия сөздер мен хабарларды пайдалана алады.&lt;br/&gt;&lt;br/&gt;Осы рұқсатты өшірмесеңіз, <xliff:g id="APP_NAME_1">%1$s</xliff:g> қолданбасы құрылғыға (<xliff:g id="DEVICE_NAME">%3$s</xliff:g>) қолданбаларды трансляциялай алады."</string>
+    <string name="helper_summary_app_streaming" msgid="1872657107404139828">"<xliff:g id="APP_NAME">%1$s</xliff:g> қолданбасы <xliff:g id="DEVICE_NAME">%2$s</xliff:g> атынан құрылғыдағы (<xliff:g id="DEVICE_TYPE">%3$s</xliff:g>) қолданбалар мен жүйе функцияларын трансляциялауға рұқсат сұрайды."</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4782923323932440751">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; қолданбасына құрылғыңыздағы (<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>) осы ақпаратты пайдалануға рұқсат беріңіз."</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
     <string name="helper_summary_computer" msgid="2298803016482139668">"<xliff:g id="APP_NAME">%1$s</xliff:g> қолданбасы <xliff:g id="DEVICE_NAME">%2$s</xliff:g> атынан құрылғыңыздағы (<xliff:g id="DEVICE_TYPE">%3$s</xliff:g>) фотосуреттерді, медиафайлдар мен хабарландыруларды пайдалануға рұқсат сұрайды."</string>
-    <string name="title_nearby_device_streaming" msgid="4295322493408411976">"&lt;strong&gt;<xliff:g id="DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt; қолданбасына құрылғыңыздағы (<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>) қолданбалар мен жүйе функцияларын &lt;strong&gt;<xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>&lt;/strong&gt; құрылғысына трансляциялауға рұқсат берілсін бе?"</string>
-    <string name="summary_nearby_device_streaming" msgid="962267343109051648">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> қолданбасы құрылғыңызда (<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>) көрінетін не ойнатылатын барлық контентті (аудиофайлдарды, фотосуреттерді, төлем туралы ақпаратты, құпия сөздер мен хабарларды қоса алғанда) пайдалана алады.&lt;br/&gt;&lt;br/&gt;Осы рұқсатты өшірмесеңіз, <xliff:g id="APP_NAME_1">%1$s</xliff:g> қолданбасы құрылғыға (<xliff:g id="DEVICE_NAME">%3$s</xliff:g>) қолданбаларды және жүйе функцияларын трансляциялай алады."</string>
-    <string name="helper_summary_nearby_device_streaming" msgid="8509848562931818793">"<xliff:g id="APP_NAME">%1$s</xliff:g> қолданбасы <xliff:g id="DEVICE_NAME">%2$s</xliff:g> атынан құрылғыларыңыздың арасында қолданбаларды және басқа жүйе функцияларын трансляциялауға рұқсат сұрайды."</string>
+    <string name="title_nearby_device_streaming" msgid="2727103756701741359">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; қолданбасына құрылғыңыздағы (<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>) қолданбаларды &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt; құрылғысына трансляциялауға рұқсат берілсін бе?"</string>
+    <string name="summary_nearby_device_streaming" msgid="70434958004946884">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> қолданбасы құрылғыда (<xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>) көрінетін не ойнатылатын барлық контентті, соның ішінде аудиофайлдарды, фотосуреттерді, төлем туралы ақпаратты, құпия сөздер мен хабарларды пайдалана алады.&lt;br/&gt;&lt;br/&gt;Осы рұқсатты өшірмесеңіз, <xliff:g id="APP_NAME_2">%1$s</xliff:g> қолданбасы құрылғыға (<xliff:g id="DEVICE_NAME_3">%3$s</xliff:g>) қолданбаларды трансляциялай алады."</string>
+    <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"<xliff:g id="APP_NAME">%1$s</xliff:g> қолданбасы <xliff:g id="DEVICE_NAME">%2$s</xliff:g> атынан құрылғыдағы (<xliff:g id="DEVICE_TYPE">%3$s</xliff:g>) қолданбаларды трансляциялауға рұқсат сұрайды."</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"құрылғы"</string>
     <string name="summary_generic" msgid="1761976003668044801">"Бұл қолданба телефон мен таңдалған құрылғы арасында деректі (мысалы, қоңырау шалушының атын) синхрондай алады."</string>
     <string name="consent_yes" msgid="8344487259618762872">"Рұқсат беру"</string>
diff --git a/packages/CompanionDeviceManager/res/values-km/strings.xml b/packages/CompanionDeviceManager/res/values-km/strings.xml
index e59db72..79ec5f1 100644
--- a/packages/CompanionDeviceManager/res/values-km/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-km/strings.xml
@@ -25,17 +25,17 @@
     <string name="confirmation_title_glasses" msgid="8288346850537727333">"អនុញ្ញាតឱ្យ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; គ្រប់គ្រង &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ឬ?"</string>
     <string name="profile_name_glasses" msgid="3506504967216601277">"ឧបករណ៍"</string>
     <string name="summary_glasses" msgid="5469208629679579157">"កម្មវិធីនេះ​នឹងត្រូវបានអនុញ្ញាតឱ្យ​ចូលប្រើការអនុញ្ញាតទាំងនេះ​នៅលើ <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> របស់អ្នក"</string>
-    <string name="title_app_streaming" msgid="6845373585257287200">"អនុញ្ញាតឱ្យ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ផ្សាយកម្មវិធីលើ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> របស់អ្នកទៅ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt; ឬ?"</string>
-    <string name="summary_app_streaming" msgid="1274464413649731829">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> នឹងមានសិទ្ធិចូលប្រើអ្វីៗដែលអាចមើលឃើញ ឬត្រូវបានចាក់នៅលើ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> រួមទាំងសំឡេង រូបថត ពាក្យសម្ងាត់ និងសារ។&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_1">%1$s</xliff:g> នឹងអាចផ្សាយកម្មវិធី <xliff:g id="DEVICE_NAME">%3$s</xliff:g> រហូតទាល់តែអ្នកដកសិទ្ធិចូលប្រើការអនុញ្ញាតនេះចេញ។"</string>
-    <string name="helper_summary_app_streaming" msgid="1944832605534698562">"<xliff:g id="APP_NAME">%1$s</xliff:g> កំពុងស្នើសុំការអនុញ្ញាតជំនួសឱ្យ <xliff:g id="DEVICE_NAME">%2$s</xliff:g> របស់អ្នក ដើម្បីបង្ហាញ និងផ្សាយកម្មវិធីរវាងឧបករណ៍នានារបស់អ្នក"</string>
+    <string name="title_app_streaming" msgid="1047090167914857893">"អនុញ្ញាតឱ្យ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ផ្សាយកម្មវិធី និងមុខងារប្រព័ន្ធលើ<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>របស់អ្នកទៅ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt; ឬ?"</string>
+    <string name="summary_app_streaming" msgid="7990244299655610920">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> នឹងមានសិទ្ធិចូលប្រើអ្វីៗដែលអាចមើលឃើញ ឬត្រូវបានចាក់នៅលើ<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>របស់អ្នក រួមទាំងសំឡេង រូបថត ព័ត៌មាននៃការទូទាត់ប្រាក់ ពាក្យសម្ងាត់ និងសារ។&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_1">%1$s</xliff:g> នឹងអាចផ្សាយកម្មវិធីទៅ <xliff:g id="DEVICE_NAME">%3$s</xliff:g> រហូតទាល់តែអ្នកដកសិទ្ធិចូលប្រើការអនុញ្ញាតនេះចេញ។"</string>
+    <string name="helper_summary_app_streaming" msgid="1872657107404139828">"<xliff:g id="APP_NAME">%1$s</xliff:g> កំពុងស្នើសុំការអនុញ្ញាតជំនួសឱ្យ <xliff:g id="DEVICE_NAME">%2$s</xliff:g> ដើម្បីផ្សាយកម្មវិធី និងមុខងារប្រព័ន្ធពី<xliff:g id="DEVICE_TYPE">%3$s</xliff:g>របស់អ្នក"</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4782923323932440751">"អនុញ្ញាតឱ្យ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ចូលប្រើព័ត៌មាននេះពី <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> របស់អ្នក"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
     <string name="helper_summary_computer" msgid="2298803016482139668">"<xliff:g id="APP_NAME">%1$s</xliff:g> កំពុងស្នើសុំការអនុញ្ញាតជំនួសឱ្យ <xliff:g id="DEVICE_NAME">%2$s</xliff:g> របស់អ្នក ដើម្បីចូលប្រើរូបថត មេឌៀ និងការជូនដំណឹងរបស់ <xliff:g id="DEVICE_TYPE">%3$s</xliff:g> អ្នក"</string>
-    <string name="title_nearby_device_streaming" msgid="4295322493408411976">"អនុញ្ញាតឱ្យ &lt;strong&gt;<xliff:g id="DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt; ផ្សាយមុខងារប្រព័ន្ធ និងកម្មវិធីលើ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> របស់អ្នកទៅ &lt;strong&gt;<xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>&lt;/strong&gt; ឬ?"</string>
-    <string name="summary_nearby_device_streaming" msgid="962267343109051648">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> នឹងមានសិទ្ធិចូលប្រើអ្វីៗដែលអាចមើលឃើញ ឬត្រូវបានចាក់នៅលើ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> របស់អ្នក រួមទាំងសំឡេង រូបថត ព័ត៌មាននៃការទូទាត់ប្រាក់ ពាក្យសម្ងាត់ និងសារ។&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_1">%1$s</xliff:g> នឹងអាចផ្សាយកម្មវិធី និងមុខងារប្រព័ន្ធទៅ <xliff:g id="DEVICE_NAME">%3$s</xliff:g> រហូតទាល់តែអ្នកដកសិទ្ធិចូលប្រើការអនុញ្ញាតនេះចេញ។"</string>
-    <string name="helper_summary_nearby_device_streaming" msgid="8509848562931818793">"<xliff:g id="APP_NAME">%1$s</xliff:g> កំពុងស្នើសុំ​ការអនុញ្ញាតជំនួសឱ្យ <xliff:g id="DEVICE_NAME">%2$s</xliff:g> របស់អ្នក ដើម្បីផ្សាយកម្មវិធី និងមុខងារប្រព័ន្ធផ្សេងទៀតរវាងឧបករណ៍របស់អ្នក"</string>
+    <string name="title_nearby_device_streaming" msgid="2727103756701741359">"អនុញ្ញាតឱ្យ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ផ្សាយកម្មវិធីលើ<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>របស់អ្នកទៅ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt; ឬ?"</string>
+    <string name="summary_nearby_device_streaming" msgid="70434958004946884">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> នឹងមានសិទ្ធិចូលប្រើអ្វីៗដែលអាចមើលឃើញ ឬត្រូវបានចាក់នៅលើ <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g> រួមទាំងសំឡេង រូបថត ព័ត៌មាននៃការទូទាត់ប្រាក់ ពាក្យសម្ងាត់ និងសារ។&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_2">%1$s</xliff:g> នឹងអាចផ្សាយកម្មវិធីទៅ <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> រហូតទាល់តែអ្នកដកសិទ្ធិចូលប្រើការអនុញ្ញាតនេះចេញ។"</string>
+    <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"<xliff:g id="APP_NAME">%1$s</xliff:g> កំពុងស្នើសុំការអនុញ្ញាតជំនួសឱ្យ <xliff:g id="DEVICE_NAME">%2$s</xliff:g> ដើម្បីផ្សាយកម្មវិធីពី<xliff:g id="DEVICE_TYPE">%3$s</xliff:g>របស់អ្នក"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"ឧបករណ៍"</string>
     <string name="summary_generic" msgid="1761976003668044801">"កម្មវិធីនេះនឹងអាច​ធ្វើសមកាលកម្មព័ត៌មាន ដូចជាឈ្មោះមនុស្សដែលហៅទូរសព្ទជាដើម​ រវាងឧបករណ៍ដែលបានជ្រើសរើស និងទូរសព្ទរបស់អ្នក"</string>
     <string name="consent_yes" msgid="8344487259618762872">"អនុញ្ញាត"</string>
diff --git a/packages/CompanionDeviceManager/res/values-kn/strings.xml b/packages/CompanionDeviceManager/res/values-kn/strings.xml
index ea7d824..7cf4069 100644
--- a/packages/CompanionDeviceManager/res/values-kn/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-kn/strings.xml
@@ -25,17 +25,17 @@
     <string name="confirmation_title_glasses" msgid="8288346850537727333">"&lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;? ನಿರ್ವಹಿಸಲು &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ಗೆ ಅನುಮತಿಸಬೇಕೇ?"</string>
     <string name="profile_name_glasses" msgid="3506504967216601277">"ಸಾಧನ"</string>
     <string name="summary_glasses" msgid="5469208629679579157">"ನಿಮ್ಮ <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> ನಲ್ಲಿ ಈ ಅನುಮತಿಗಳನ್ನು ಆ್ಯಕ್ಸೆಸ್‌ ಮಾಡಲು ಈ ಆ್ಯಪ್‌ ಅನ್ನು ಅನುಮತಿಸಲಾಗುತ್ತದೆ"</string>
-    <string name="title_app_streaming" msgid="6845373585257287200">"ನಿಮ್ಮ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> ನ ಆ್ಯಪ್‌ಗಳನ್ನು <xliff:g id="DEVICE_NAME">%3$s</xliff:g> ಗೆ ಸ್ಟ್ರೀಮ್ ಮಾಡಲು <xliff:g id="APP_NAME">%1$s</xliff:g> ಗೆ ಅನುಮತಿಸಬೇಕೇ?"</string>
-    <string name="summary_app_streaming" msgid="1274464413649731829">"ನಿಮ್ಮ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> ನಲ್ಲಿನ ಆಡಿಯೋ, ಫೋಟೋಗಳು, ಪಾಸ್‌ವರ್ಡ್‌ಗಳು ಮತ್ತು ಸಂದೇಶಗಳು ಸೇರಿದಂತೆ <xliff:g id="APP_NAME_0">%1$s</xliff:g> ನಲ್ಲಿ ಗೋಚರಿಸುವ ಅಥವಾ ಪ್ಲೇ ಆಗುವ ಯಾವುದಕ್ಕೂ ಆ್ಯಕ್ಸೆಸ್ ಅನ್ನು ಹೊಂದಿರುತ್ತದೆ. ನೀವು ಈ ಅನುಮತಿಗೆ <xliff:g id="DEVICE_NAME">%3$s</xliff:g> ಆ್ಯಕ್ಸೆಸ್ ಅನ್ನು ತೆಗೆದುಹಾಕುವವರೆಗೆ <xliff:g id="APP_NAME_1">%1$s</xliff:g> ಗೆ ಆ್ಯಪ್‌ಗಳನ್ನು ಸ್ಟ್ರೀಮ್ ಮಾಡಲು ಸಾಧ್ಯವಾಗುತ್ತದೆ."</string>
-    <string name="helper_summary_app_streaming" msgid="1944832605534698562">"ನಿಮ್ಮ ಸಾಧನಗಳ ನಡುವೆ ಆ್ಯಪ್‌ಗಳನ್ನು ಪ್ರದರ್ಶಿಸಲು ಮತ್ತು ಸ್ಟ್ರೀಮ್ ಮಾಡಲು ನಿಮ್ಮ <xliff:g id="DEVICE_NAME">%2$s</xliff:g> ಪರವಾಗಿ <xliff:g id="APP_NAME">%1$s</xliff:g> ಅನುಮತಿಯನ್ನು ವಿನಂತಿಸುತ್ತಿದೆ"</string>
+    <string name="title_app_streaming" msgid="1047090167914857893">"ನಿಮ್ಮ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> ನ ಆ್ಯಪ್‌ಗಳು ಮತ್ತು ಸಿಸ್ಟಮ್ ಫೀಚರ್‌ಗಳನ್ನು <xliff:g id="DEVICE_NAME">%3$s</xliff:g> ಗೆ ಸ್ಟ್ರೀಮ್ ಮಾಡಲು <xliff:g id="APP_NAME">%1$s</xliff:g> ಗೆ ಅನುಮತಿಸಬೇಕೇ?"</string>
+    <string name="summary_app_streaming" msgid="7990244299655610920">"ಆಡಿಯೋ, ಫೋಟೋಗಳು, ಪಾವತಿ ಮಾಹಿತಿ, ಪಾಸ್‌ವರ್ಡ್‌ಗಳು ಮತ್ತು ಸಂದೇಶಗಳು ಸೇರಿದಂತೆ ನಿಮ್ಮ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> ನಲ್ಲಿ ಗೋಚರಿಸುವ ಅಥವಾ ಪ್ಲೇ ಆಗುವ ಎಲ್ಲದಕ್ಕೂ <xliff:g id="APP_NAME_0">%1$s</xliff:g> ಆ್ಯಕ್ಸೆಸ್ ಅನ್ನು ಹೊಂದಿರುತ್ತದೆ. ನೀವು ಈ ಅನುಮತಿಗೆ ಆ್ಯಕ್ಸೆಸ್‌ ಅನ್ನು ತೆಗೆದುಹಾಕುವವರೆಗೆ <xliff:g id="DEVICE_NAME">%3$s</xliff:g> ಗೆ ಆ್ಯಪ್‌ಗಳನ್ನು ಸ್ಟ್ರೀಮ್ ಮಾಡಲು <xliff:g id="APP_NAME_1">%1$s</xliff:g> ಗೆ ಸಾಧ್ಯವಾಗುತ್ತದೆ."</string>
+    <string name="helper_summary_app_streaming" msgid="1872657107404139828">"ನಿಮ್ಮ <xliff:g id="DEVICE_TYPE">%3$s</xliff:g> ನಿಂದ ಆ್ಯಪ್‌ಗಳು ಮತ್ತು ಸಿಸ್ಟಮ್ ಫೀಚರ್‌ಗಳನ್ನು ಸ್ಟ್ರೀಮ್ ಮಾಡಲು <xliff:g id="DEVICE_NAME">%2$s</xliff:g> ಪರವಾಗಿ <xliff:g id="APP_NAME">%1$s</xliff:g> ಅನುಮತಿಗಾಗಿ ವಿನಂತಿಸುತ್ತಿದೆ"</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4782923323932440751">"ನಿಮ್ಮ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> ನಿಂದ ಈ ಮಾಹಿತಿಯನ್ನು ಆ್ಯಕ್ಸೆಸ್‌ ಮಾಡಲು <xliff:g id="APP_NAME">%1$s</xliff:g> ಗೆ ಅನುಮತಿಸಿ"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
     <string name="helper_summary_computer" msgid="2298803016482139668">"ನಿಮ್ಮ <xliff:g id="DEVICE_TYPE">%3$s</xliff:g> ನ ಫೋಟೋಗಳು, ಮೀಡಿಯಾ ಮತ್ತು ನೋಟಿಫಿಕೇಶನ್‌ಗಳನ್ನು ಆ್ಯಕ್ಸೆಸ್‌ ಮಾಡಲು ನಿಮ್ಮ <xliff:g id="DEVICE_NAME">%2$s</xliff:g> ಪರವಾಗಿ <xliff:g id="APP_NAME">%1$s</xliff:g> ಅನುಮತಿಯನ್ನು ವಿನಂತಿಸುತ್ತಿದೆ"</string>
-    <string name="title_nearby_device_streaming" msgid="4295322493408411976">"ನಿಮ್ಮ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> ನ ಆ್ಯಪ್‌ಗಳು ಮತ್ತು ಸಿಸ್ಟಮ್ ಫೀಚರ್‌ಗಳನ್ನು <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g> ಗೆ ಸ್ಟ್ರೀಮ್ ಮಾಡಲು <xliff:g id="DEVICE_NAME_0">%1$s</xliff:g> ಗೆ ಅನುಮತಿಸಬೇಕೇ?"</string>
-    <string name="summary_nearby_device_streaming" msgid="962267343109051648">"ನಿಮ್ಮ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> ನಲ್ಲಿನ ಆಡಿಯೋ, ಫೋಟೋಗಳು, ಪಾವತಿ ಮಾಹಿತಿ, ಪಾಸ್‌ವರ್ಡ್‌ಗಳು ಮತ್ತು ಸಂದೇಶಗಳು ಸೇರಿದಂತೆ ನಿಮ್ಮ <xliff:g id="APP_NAME_0">%1$s</xliff:g> ನಲ್ಲಿ ಗೋಚರಿಸುವ ಅಥವಾ ಪ್ಲೇ ಆಗುವ ಯಾವುದಕ್ಕೂ ಆ್ಯಕ್ಸೆಸ್ ಅನ್ನು ಹೊಂದಿರುತ್ತದೆ. ನೀವು ಈ ಅನುಮತಿಗೆ <xliff:g id="DEVICE_NAME">%3$s</xliff:g> ಆ್ಯಕ್ಸೆಸ್‌ ಅನ್ನು ತೆಗೆದುಹಾಕುವವರೆಗೆ <xliff:g id="APP_NAME_1">%1$s</xliff:g> ಗೆ ಆ್ಯಪ್‌ಗಳು ಮತ್ತು ಸಿಸ್ಟಮ್ ಫೀಚರ್‌ಗಳನ್ನು ಸ್ಟ್ರೀಮ್ ಮಾಡಲು ಸಾಧ್ಯವಾಗುತ್ತದೆ ."</string>
-    <string name="helper_summary_nearby_device_streaming" msgid="8509848562931818793">"<xliff:g id="APP_NAME">%1$s</xliff:g> ನಿಮ್ಮ ಸಾಧನಗಳ ನಡುವೆ ಆ್ಯಪ್‌ಗಳು ಮತ್ತು ಇತರ ಸಿಸ್ಟಮ್ ಫೀಚರ್‌ಗಳನ್ನು ಸ್ಟ್ರೀಮ್ ಮಾಡಲು ನಿಮ್ಮ <xliff:g id="DEVICE_NAME">%2$s</xliff:g> ಪರವಾಗಿ ಅನುಮತಿಯನ್ನು ವಿನಂತಿಸುತ್ತಿದೆ"</string>
+    <string name="title_nearby_device_streaming" msgid="2727103756701741359">"ನಿಮ್ಮ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> ನ ಆ್ಯಪ್‌ಗಳನ್ನು <xliff:g id="DEVICE_NAME">%3$s</xliff:g> ಗೆ ಸ್ಟ್ರೀಮ್ ಮಾಡಲು <xliff:g id="APP_NAME">%1$s</xliff:g> ಗೆ ಅನುಮತಿಸಬೇಕೇ?"</string>
+    <string name="summary_nearby_device_streaming" msgid="70434958004946884">"ಆಡಿಯೋ, ಫೋಟೋಗಳು, ಪಾವತಿ ಮಾಹಿತಿ, ಪಾಸ್‌ವರ್ಡ್‌ಗಳು ಮತ್ತು ಸಂದೇಶಗಳು ಸೇರಿದಂತೆ <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g> ನಲ್ಲಿ ಗೋಚರಿಸುವ ಅಥವಾ ಪ್ಲೇ ಆಗುವ ಎಲ್ಲದಕ್ಕೂ <xliff:g id="APP_NAME_0">%1$s</xliff:g> ಆ್ಯಕ್ಸೆಸ್ ಅನ್ನು ಹೊಂದಿರುತ್ತದೆ. ನೀವು ಈ ಅನುಮತಿಗೆ ಆ್ಯಕ್ಸೆಸ್‌ ಅನ್ನು ತೆಗೆದುಹಾಕುವವರೆಗೆ <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> ಗೆ ಆ್ಯಪ್‌ಗಳನ್ನು ಸ್ಟ್ರೀಮ್ ಮಾಡಲು <xliff:g id="APP_NAME_2">%1$s</xliff:g> ಗೆ ಸಾಧ್ಯವಾಗುತ್ತದೆ."</string>
+    <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"ನಿಮ್ಮ <xliff:g id="DEVICE_TYPE">%3$s</xliff:g> ನಿಂದ ಆ್ಯಪ್‌ಗಳನ್ನು ಸ್ಟ್ರೀಮ್ ಮಾಡಲು <xliff:g id="DEVICE_NAME">%2$s</xliff:g> ಪರವಾಗಿ <xliff:g id="APP_NAME">%1$s</xliff:g> ಅನುಮತಿಗಾಗಿ ವಿನಂತಿಸುತ್ತಿದೆ"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"ಸಾಧನ"</string>
     <string name="summary_generic" msgid="1761976003668044801">"ಮೊಬೈಲ್ ಫೋನ್ ಮತ್ತು ಆಯ್ಕೆಮಾಡಿದ ಸಾಧನದ ನಡುವೆ, ಕರೆ ಮಾಡುವವರ ಹೆಸರಿನಂತಹ ಮಾಹಿತಿಯನ್ನು ಸಿಂಕ್ ಮಾಡಲು ಈ ಆ್ಯಪ್‌ಗೆ ಸಾಧ್ಯವಾಗುತ್ತದೆ"</string>
     <string name="consent_yes" msgid="8344487259618762872">"ಅನುಮತಿಸಿ"</string>
diff --git a/packages/CompanionDeviceManager/res/values-ko/strings.xml b/packages/CompanionDeviceManager/res/values-ko/strings.xml
index 4ff768e..c384363 100644
--- a/packages/CompanionDeviceManager/res/values-ko/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ko/strings.xml
@@ -25,17 +25,17 @@
     <string name="confirmation_title_glasses" msgid="8288346850537727333">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;에서 &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; 기기를 관리하도록 허용하시겠습니까?"</string>
     <string name="profile_name_glasses" msgid="3506504967216601277">"기기"</string>
     <string name="summary_glasses" msgid="5469208629679579157">"앱이 <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>에서 이러한 권한에 액세스할 수 있게 됩니다."</string>
-    <string name="title_app_streaming" msgid="6845373585257287200">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;에서 <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>의 앱을 &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt; 기기로 스트리밍하도록 허용하시겠습니까?"</string>
-    <string name="summary_app_streaming" msgid="1274464413649731829">"<xliff:g id="APP_NAME_0">%1$s</xliff:g>에서 오디오, 사진, 비밀번호, 메시지 등 <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>에 표시되거나 해당 기기에서 재생되는 모든 항목에 액세스할 수 있습니다.&lt;br/&gt;&lt;br/&gt;이 권한에 대한 액세스를 삭제할 때까지 <xliff:g id="APP_NAME_1">%1$s</xliff:g>에서 <xliff:g id="DEVICE_NAME">%3$s</xliff:g> 기기로 앱을 스트리밍할 수 있습니다."</string>
-    <string name="helper_summary_app_streaming" msgid="1944832605534698562">"<xliff:g id="APP_NAME">%1$s</xliff:g>에서 <xliff:g id="DEVICE_NAME">%2$s</xliff:g> 대신 기기 간에 앱을 표시하고 스트리밍할 수 있는 권한을 요청하고 있습니다."</string>
+    <string name="title_app_streaming" msgid="1047090167914857893">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;에서 <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>의 앱 및 시스템 기능을 &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt; 기기로 스트리밍하도록 허용하시겠습니까?"</string>
+    <string name="summary_app_streaming" msgid="7990244299655610920">"<xliff:g id="APP_NAME_0">%1$s</xliff:g>에서 오디오, 사진, 결제 정보, 비밀번호, 메시지 등 <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>에 표시되거나 해당 기기에서 재생되는 모든 항목에 액세스할 수 있습니다.&lt;br/&gt;&lt;br/&gt;이 권한에 대한 액세스를 삭제할 때까지 <xliff:g id="APP_NAME_1">%1$s</xliff:g>에서 <xliff:g id="DEVICE_NAME">%3$s</xliff:g> 기기로 앱을 스트리밍할 수 있습니다."</string>
+    <string name="helper_summary_app_streaming" msgid="1872657107404139828">"<xliff:g id="APP_NAME">%1$s</xliff:g>에서 <xliff:g id="DEVICE_NAME">%2$s</xliff:g> 대신 <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>의 앱 및 시스템 기능을 스트리밍할 권한을 요청하고 있습니다."</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4782923323932440751">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; 앱이 <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>에서 이 정보에 액세스하도록 허용합니다."</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
     <string name="helper_summary_computer" msgid="2298803016482139668">"<xliff:g id="APP_NAME">%1$s</xliff:g>에서 <xliff:g id="DEVICE_NAME">%2$s</xliff:g> 대신 <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>의 사진, 미디어, 알림에 액세스할 수 있는 권한을 요청하고 있습니다."</string>
-    <string name="title_nearby_device_streaming" msgid="4295322493408411976">"&lt;strong&gt;<xliff:g id="DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt;에서 <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>의 앱 및 시스템 기능을 &lt;strong&gt;<xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>&lt;/strong&gt; 기기로 스트리밍하도록 허용하시겠습니까?"</string>
-    <string name="summary_nearby_device_streaming" msgid="962267343109051648">"<xliff:g id="APP_NAME_0">%1$s</xliff:g>에서 오디오, 사진, 결제 정보, 비밀번호, 메시지 등 <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>에 표시되거나 해당 기기에서 재생되는 모든 항목에 액세스할 수 있습니다.&lt;br/&gt;&lt;br/&gt;이 권한에 대한 액세스를 삭제할 때까지 <xliff:g id="APP_NAME_1">%1$s</xliff:g>에서 <xliff:g id="DEVICE_NAME">%3$s</xliff:g> 기기로 앱 및 시스템 기능을 스트리밍할 수 있습니다."</string>
-    <string name="helper_summary_nearby_device_streaming" msgid="8509848562931818793">"<xliff:g id="APP_NAME">%1$s</xliff:g>에서 <xliff:g id="DEVICE_NAME">%2$s</xliff:g> 대신 기기 간에 앱 및 다른 시스템 기능을 스트리밍할 권한을 요청하고 있습니다."</string>
+    <string name="title_nearby_device_streaming" msgid="2727103756701741359">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;에서 <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>의 앱을 &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt; 기기로 스트리밍하도록 허용하시겠습니까?"</string>
+    <string name="summary_nearby_device_streaming" msgid="70434958004946884">"<xliff:g id="APP_NAME_0">%1$s</xliff:g>에서 오디오, 사진, 결제 정보, 비밀번호, 메시지 등 <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>에 표시되거나 해당 기기에서 재생되는 모든 항목에 액세스할 수 있습니다.&lt;br/&gt;&lt;br/&gt;이 권한에 대한 액세스를 삭제할 때까지 <xliff:g id="APP_NAME_2">%1$s</xliff:g>에서 <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> 기기로 앱을 스트리밍할 수 있습니다."</string>
+    <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"<xliff:g id="APP_NAME">%1$s</xliff:g>에서 <xliff:g id="DEVICE_NAME">%2$s</xliff:g> 대신 <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>의 앱을 스트리밍할 권한을 요청하고 있습니다."</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"기기"</string>
     <string name="summary_generic" msgid="1761976003668044801">"이 앱에서 휴대전화와 선택한 기기 간에 정보(예: 발신자 이름)를 동기화할 수 있게 됩니다."</string>
     <string name="consent_yes" msgid="8344487259618762872">"허용"</string>
diff --git a/packages/CompanionDeviceManager/res/values-ky/strings.xml b/packages/CompanionDeviceManager/res/values-ky/strings.xml
index 3e265a2..70bdf1f 100644
--- a/packages/CompanionDeviceManager/res/values-ky/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ky/strings.xml
@@ -25,17 +25,17 @@
     <string name="confirmation_title_glasses" msgid="8288346850537727333">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; колдонмосуна &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; түзмөгүн тескөөгө уруксат бересизби?"</string>
     <string name="profile_name_glasses" msgid="3506504967216601277">"түзмөк"</string>
     <string name="summary_glasses" msgid="5469208629679579157">"Бул колдонмого <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> түзмөгүңүздө төмөнкүлөрдү аткарууга уруксат берилет"</string>
-    <string name="title_app_streaming" msgid="6845373585257287200">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; колдонмосуна <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> түзмөгүңүздөгү колдонмолорду &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt; түзмөгүнө алып ойнотууга уруксат бересизби?"</string>
-    <string name="summary_app_streaming" msgid="1274464413649731829">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> түзмөгүндө көрүнгөн же ойнотулган бардык нерселерге, анын ичинде аудио, сүрөттөр, сырсөздөр жана билдирүүлөргө кире алат.&lt;br/&gt;&lt;br/&gt;Бул уруксатты алып салмайынча, <xliff:g id="APP_NAME_1">%1$s</xliff:g> колдонмолорду <xliff:g id="DEVICE_NAME">%3$s</xliff:g> түзмөгүнө алып ойното алат."</string>
-    <string name="helper_summary_app_streaming" msgid="1944832605534698562">"<xliff:g id="APP_NAME">%1$s</xliff:g> колдонмосу <xliff:g id="DEVICE_NAME">%2$s</xliff:g> түзмөгүңүздүн атынан түзмөктөрдүн ортосунда колдонмолорду көрсөтүү жана алып ойнотуу үчүн уруксат сурап жатат"</string>
+    <string name="title_app_streaming" msgid="1047090167914857893">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; түзмөгүнө <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> түзмөгүндөгү колдонмолорду жана тутумдун функцияларын &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt; түзмөгүндө алып ойнотууга уруксат бересизби?"</string>
+    <string name="summary_app_streaming" msgid="7990244299655610920">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> түзмөгүңүздө көрүнгөн же ойнотулган бардык нерселерге, анын ичинде аудио, сүрөттөр, төлөм маалыматы, сырсөздөр жана билдирүүлөргө кире алат.&lt;br/&gt;&lt;br/&gt;Бул уруксатты алып салмайынча, <xliff:g id="APP_NAME_1">%1$s</xliff:g> <xliff:g id="DEVICE_NAME">%3$s</xliff:g> түзмөгүндөгү колдонмолорду алып ойното алат."</string>
+    <string name="helper_summary_app_streaming" msgid="1872657107404139828">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="DEVICE_TYPE">%3$s</xliff:g> түзмөгүңүздөн колдонмолорду жана тутум функцияларын алып ойнотуу үчүн <xliff:g id="DEVICE_NAME">%2$s</xliff:g> түзмөгүнүн атынан уруксат сурап жатат"</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4782923323932440751">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; колдонмосуна <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> түзмөгүңүздөгү ушул маалыматты көрүүгө уруксат бериңиз"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
     <string name="helper_summary_computer" msgid="2298803016482139668">"<xliff:g id="APP_NAME">%1$s</xliff:g> колдонмосу <xliff:g id="DEVICE_NAME">%2$s</xliff:g> түзмөгүңүздүн атынан <xliff:g id="DEVICE_TYPE">%3$s</xliff:g> сүрөттөрүн, медиа файлдарын жана билдирмелерин колдонууга уруксат сурап жатат"</string>
-    <string name="title_nearby_device_streaming" msgid="4295322493408411976">"&lt;strong&gt;<xliff:g id="DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt; түзмөгүнө <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> түзмөгүндөгү колдонмолорду жана тутумдун функцияларын &lt;strong&gt;<xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>&lt;/strong&gt; түзмөгүндө алып ойнотууга уруксат бересизби?"</string>
-    <string name="summary_nearby_device_streaming" msgid="962267343109051648">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> түзмөгүңүздө көрүнгөн же ойнотулган бардык нерселерге, анын ичинде аудио, сүрөттөр, төлөм маалыматы, сырсөздөр жана билдирүүлөргө кире алат.&lt;br/&gt;&lt;br/&gt;Бул уруксатты алып салмайынча, <xliff:g id="APP_NAME_1">%1$s</xliff:g> <xliff:g id="DEVICE_NAME">%3$s</xliff:g> түзмөгүндөгү колдонмолорду жана тутум функцияларын алып ойното алат."</string>
-    <string name="helper_summary_nearby_device_streaming" msgid="8509848562931818793">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="DEVICE_NAME">%2$s</xliff:g> түзмөгүңүздүн атынан түзмөктөрдүн ортосунда колдонмолорду жана тутумдун башка функцияларын алып ойнотууга уруксат сурап жатат"</string>
+    <string name="title_nearby_device_streaming" msgid="2727103756701741359">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; колдонмосуна <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> түзмөгүңүздөгү колдонмолорду &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt; түзмөгүнө алып ойнотууга уруксат бересизби?"</string>
+    <string name="summary_nearby_device_streaming" msgid="70434958004946884">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g> түзмөгүңүздө көрүнгөн же ойнотулган бардык нерселерге, анын ичинде аудио, сүрөттөр, төлөм маалыматы, сырсөздөр жана билдирүүлөргө кире алат.&lt;br/&gt;&lt;br/&gt;Бул уруксатты алып салмайынча, <xliff:g id="APP_NAME_2">%1$s</xliff:g> <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> түзмөгүндөгү колдонмолорду алып ойното алат."</string>
+    <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="DEVICE_TYPE">%3$s</xliff:g> түзмөгүңүздөн колдонмолорду алып ойнотуу үчүн <xliff:g id="DEVICE_NAME">%2$s</xliff:g> түзмөгүнүн атынан уруксат сурап жатат"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"түзмөк"</string>
     <string name="summary_generic" msgid="1761976003668044801">"Бул колдонмо маалыматты шайкештире алат, мисалы, чалып жаткан кишинин атын телефон жана тандалган түзмөк менен шайкештирет"</string>
     <string name="consent_yes" msgid="8344487259618762872">"Ооба"</string>
diff --git a/packages/CompanionDeviceManager/res/values-lo/strings.xml b/packages/CompanionDeviceManager/res/values-lo/strings.xml
index 2917c3e..f8da499 100644
--- a/packages/CompanionDeviceManager/res/values-lo/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-lo/strings.xml
@@ -25,17 +25,17 @@
     <string name="confirmation_title_glasses" msgid="8288346850537727333">"ອະນຸຍາດ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ຈັດການ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ບໍ?"</string>
     <string name="profile_name_glasses" msgid="3506504967216601277">"ອຸປະກອນ"</string>
     <string name="summary_glasses" msgid="5469208629679579157">"ແອັບນີ້ຈະໄດ້ຮັບສິດເຂົ້າເຖິງການອະນຸຍາດເຫຼົ່ານີ້ຢູ່ <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> ຂອງທ່ານ"</string>
-    <string name="title_app_streaming" msgid="6845373585257287200">"ອະນຸຍາດໃຫ້ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ສະຕຣີມແອັບຂອງ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> ຂອງທ່ານໄປຫາ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt; ບໍ?"</string>
-    <string name="summary_app_streaming" msgid="1274464413649731829">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> ຈະມີສິດເຂົ້າເຖິງທຸກຢ່າງທີ່ປາກົດ ຫຼື ຫຼິ້ນຢູ່ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>, ເຊິ່ງຮວມທັງສຽງ, ຮູບພາບ, ລະຫັດຜ່ານ ແລະ ຂໍ້ຄວາມ.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_1">%1$s</xliff:g> ຈະສາມາດສະຕຣີມແອັບໄປຫາ <xliff:g id="DEVICE_NAME">%3$s</xliff:g> ໄດ້ຈົນກວ່າທ່ານຈະລຶບສິດເຂົ້າເຖິງການອະນຸຍາດນີ້ອອກ."</string>
-    <string name="helper_summary_app_streaming" msgid="1944832605534698562">"<xliff:g id="APP_NAME">%1$s</xliff:g> ກໍາລັງຮ້ອງຂໍການອະນຸຍາດໃນນາມຂອງ <xliff:g id="DEVICE_NAME">%2$s</xliff:g> ຂອງທ່ານເພື່ອສະແດງ ແລະ ສະຕຣີມແອັບລະຫວ່າງອຸປະກອນຕ່າງໆຂອງທ່ານ"</string>
+    <string name="title_app_streaming" msgid="1047090167914857893">"ອະນຸຍາດໃຫ້ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ສະຕຣີມແອັບ ແລະ ຄຸນສົມບັດຂອງລະບົບຂອງ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> ຂອງທ່ານໄປຫາ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt; ບໍ?"</string>
+    <string name="summary_app_streaming" msgid="7990244299655610920">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> ຈະມີສິດເຂົ້າເຖິງທຸກຢ່າງທີ່ປາກົດ ຫຼື ຫຼິ້ນຢູ່ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> ຂອງທ່ານ, ເຊິ່ງຮວມທັງສຽງ, ຮູບພາບ, ຂໍ້ມູນການຈ່າຍເງິນ ລະຫັດຜ່ານ ແລະ ຂໍ້ຄວາມ.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_1">%1$s</xliff:g> ຈະສາມາດສະຕຣີມແອັບໄປຫາ <xliff:g id="DEVICE_NAME">%3$s</xliff:g> ໄດ້ຈົນກວ່າທ່ານຈະລຶບສິດເຂົ້າເຖິງການອະນຸຍາດນີ້ອອກ."</string>
+    <string name="helper_summary_app_streaming" msgid="1872657107404139828">"<xliff:g id="APP_NAME">%1$s</xliff:g> ກຳລັງຮ້ອງຂໍການອະນຸຍາດໃນນາມ <xliff:g id="DEVICE_NAME">%2$s</xliff:g> ເພື່ອສະຕຣີມແອັລ ແລະ ຄຸນສົມບັດລະບົບຈາກ <xliff:g id="DEVICE_TYPE">%3$s</xliff:g> ຂອງທ່ານ"</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4782923323932440751">"ອະນຸຍາດໃຫ້ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ເຂົ້າເຖິງຂໍ້ມູນນີ້ຈາກ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> ຂອງທ່ານ"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
     <string name="helper_summary_computer" msgid="2298803016482139668">"<xliff:g id="APP_NAME">%1$s</xliff:g> ກຳລັງຮ້ອງຂໍການອະນຸຍາດໃນນາມຂອງ <xliff:g id="DEVICE_NAME">%2$s</xliff:g> ຂອງທ່ານເພື່ອເຂົ້າເຖິງຮູບພາບ, ສື່ ແລະ ການແຈ້ງເຕືອນໃນ <xliff:g id="DEVICE_TYPE">%3$s</xliff:g> ຂອງທ່ານ"</string>
-    <string name="title_nearby_device_streaming" msgid="4295322493408411976">"ອະນຸຍາດໃຫ້ &lt;strong&gt;<xliff:g id="DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt; ສະຕຣີມແອັບ ແລະ ຄຸນສົມບັດຂອງລະບົບຂອງ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> ຂອງທ່ານໄປຫາ &lt;strong&gt;<xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>&lt;/strong&gt; ບໍ?"</string>
-    <string name="summary_nearby_device_streaming" msgid="962267343109051648">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> ຈະມີສິດເຂົ້າເຖິງທຸກຢ່າງທີ່ປາກົດ ຫຼື ຫຼິ້ນຢູ່ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> ຂອງທ່ານ, ເຊິ່ງຮວມທັງສຽງ, ຮູບພາບ, ຂໍ້ມູນການຈ່າຍເງິນ ລະຫັດຜ່ານ ແລະ ຂໍ້ຄວາມ.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_1">%1$s</xliff:g> ຈະສາມາດສະຕຣີມແອັບ ແລະ ຄຸນສົມບັດຂອງລະບົບໄປຫາ <xliff:g id="DEVICE_NAME">%3$s</xliff:g> ໄດ້ຈົນກວ່າທ່ານຈະລຶບສິດເຂົ້າເຖິງການອະນຸຍາດນີ້ອອກ."</string>
-    <string name="helper_summary_nearby_device_streaming" msgid="8509848562931818793">"<xliff:g id="APP_NAME">%1$s</xliff:g> ກຳລັງຮ້ອງຂໍການອະນຸຍາດໃນນາມຂອງ <xliff:g id="DEVICE_NAME">%2$s</xliff:g> ຂອງທ່ານເພື່ອສະຕຣີມແອັບ ແລະ ຄຸນສົມບັດອື່ນໆຂອງລະບົບລະຫວ່າງອຸປະກອນຕ່າງໆຂອງທ່ານ"</string>
+    <string name="title_nearby_device_streaming" msgid="2727103756701741359">"ອະນຸຍາດໃຫ້ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ສະຕຣີມແອັບຂອງ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> ຂອງທ່ານໄປຫາ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt; ບໍ?"</string>
+    <string name="summary_nearby_device_streaming" msgid="70434958004946884">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> ຈະມີສິດເຂົ້າເຖິງທຸກຢ່າງທີ່ປາກົດ ຫຼື ຫຼິ້ນຢູ່ <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>, ເຊິ່ງຮວມທັງສຽງ, ຮູບພາບ, ຂໍ້ມູນການຈ່າຍເງິນ, ລະຫັດຜ່ານ ແລະ ຂໍ້ຄວາມ.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_2">%1$s</xliff:g> ຈະສາມາດສະຕຣີມແອັບໄປຫາ <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> ໄດ້ຈົນກວ່າທ່ານຈະລຶບສິດເຂົ້າເຖິງການອະນຸຍາດນີ້ອອກ."</string>
+    <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"<xliff:g id="APP_NAME">%1$s</xliff:g> ກຳລັງຮ້ອງຂໍການອະນຸຍາດໃນນາມ <xliff:g id="DEVICE_NAME">%2$s</xliff:g> ເພື່ອສະຕຣີມແອັບຈາກ <xliff:g id="DEVICE_TYPE">%3$s</xliff:g> ຂອງທ່ານ"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"ອຸປະກອນ"</string>
     <string name="summary_generic" msgid="1761976003668044801">"ແອັບນີ້ຈະສາມາດຊິ້ງຂໍ້ມູນ ເຊັ່ນ: ຊື່ຂອງຄົນທີ່ໂທເຂົ້າ, ລະຫວ່າງໂທລະສັບຂອງທ່ານ ແລະ ອຸປະກອນທີ່ເລືອກໄວ້ໄດ້"</string>
     <string name="consent_yes" msgid="8344487259618762872">"ອະນຸຍາດ"</string>
diff --git a/packages/CompanionDeviceManager/res/values-lt/strings.xml b/packages/CompanionDeviceManager/res/values-lt/strings.xml
index a1b5cd9..7a5f347 100644
--- a/packages/CompanionDeviceManager/res/values-lt/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-lt/strings.xml
@@ -25,17 +25,17 @@
     <string name="confirmation_title_glasses" msgid="8288346850537727333">"Leisti &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; valdyti &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
     <string name="profile_name_glasses" msgid="3506504967216601277">"įrenginio"</string>
     <string name="summary_glasses" msgid="5469208629679579157">"Šiai programai bus leidžiama pasiekti toliau nurodytus leidimus jūsų <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>."</string>
-    <string name="title_app_streaming" msgid="6845373585257287200">"Leisti programai &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; srautu perduoti <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> programas į &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;?"</string>
-    <string name="summary_app_streaming" msgid="1274464413649731829">"Programa „<xliff:g id="APP_NAME_0">%1$s</xliff:g>“ galės pasiekti visą „<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>“ matomą ar leidžiamą turinį, įskaitant garso įrašus, nuotraukas, slaptažodžius ir pranešimus.&lt;br/&gt;&lt;br/&gt;Programa „<xliff:g id="APP_NAME_1">%1$s</xliff:g>“ galės perduoti srautu programas į „<xliff:g id="DEVICE_NAME">%3$s</xliff:g>“, kol pašalinsite prieigą prie šio leidimo."</string>
-    <string name="helper_summary_app_streaming" msgid="1944832605534698562">"Programa „<xliff:g id="APP_NAME">%1$s</xliff:g>“ prašo leidimo jūsų „<xliff:g id="DEVICE_NAME">%2$s</xliff:g>“ vardu, kad galėtų rodyti ir srautu perduoti programas iš vieno įrenginio į kitą"</string>
+    <string name="title_app_streaming" msgid="1047090167914857893">"Leisti programai &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; srautu perduoti <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> programas ir sistemos funkcijas į &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;?"</string>
+    <string name="summary_app_streaming" msgid="7990244299655610920">"Programa „<xliff:g id="APP_NAME_0">%1$s</xliff:g>“ galės pasiekti visą jūsų <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> matomą ar leidžiamą turinį, įskaitant garso įrašus, nuotraukas, mokėjimo informaciją, slaptažodžius ir pranešimus.&lt;br/&gt;&lt;br/&gt;Programa „<xliff:g id="APP_NAME_1">%1$s</xliff:g>“ galės perduoti srautu programas į „<xliff:g id="DEVICE_NAME">%3$s</xliff:g>“, kol pašalinsite prieigą prie šio leidimo."</string>
+    <string name="helper_summary_app_streaming" msgid="1872657107404139828">"„<xliff:g id="APP_NAME">%1$s</xliff:g>“ prašo leidimo „<xliff:g id="DEVICE_NAME">%2$s</xliff:g>“ vardu, kad galėtų srautu perduoti programas ir sistemos funkcijas iš jūsų <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>"</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4782923323932440751">"Leisti programai &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; pasiekti šią informaciją iš jūsų <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
     <string name="helper_summary_computer" msgid="2298803016482139668">"Programa „<xliff:g id="APP_NAME">%1$s</xliff:g>“ prašo leidimo jūsų „<xliff:g id="DEVICE_NAME">%2$s</xliff:g>“ vardu, kad galėtų pasiekti <xliff:g id="DEVICE_TYPE">%3$s</xliff:g> nuotraukas, mediją ir pranešimus"</string>
-    <string name="title_nearby_device_streaming" msgid="4295322493408411976">"Leisti programai &lt;strong&gt;<xliff:g id="DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt; srautu perduoti <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> programas ir sistemos funkcijas į &lt;strong&gt;<xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>&lt;/strong&gt;?"</string>
-    <string name="summary_nearby_device_streaming" msgid="962267343109051648">"Programa „<xliff:g id="APP_NAME_0">%1$s</xliff:g>“ galės pasiekti visą <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> matomą ar leidžiamą turinį, įskaitant garso įrašus, nuotraukas, mokėjimo informaciją, slaptažodžius ir pranešimus.&lt;br/&gt;&lt;br/&gt;Programa „<xliff:g id="APP_NAME_1">%1$s</xliff:g>“ galės perduoti srautu programas ir sistemos funkcijas į „<xliff:g id="DEVICE_NAME">%3$s</xliff:g>“, kol pašalinsite prieigą prie šio leidimo."</string>
-    <string name="helper_summary_nearby_device_streaming" msgid="8509848562931818793">"Programa „<xliff:g id="APP_NAME">%1$s</xliff:g>“ prašo leidimo jūsų „<xliff:g id="DEVICE_NAME">%2$s</xliff:g>“ vardu, kad galėtų srautu perduoti programas ir kitas sistemos funkcijas iš vieno įrenginio į kitą"</string>
+    <string name="title_nearby_device_streaming" msgid="2727103756701741359">"Leisti programai &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; srautu perduoti <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> programas į &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;?"</string>
+    <string name="summary_nearby_device_streaming" msgid="70434958004946884">"Programa „<xliff:g id="APP_NAME_0">%1$s</xliff:g>“ galės pasiekti visą „<xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>“ matomą ar leidžiamą turinį, įskaitant garso įrašus, nuotraukas, mokėjimo informaciją, slaptažodžius ir pranešimus.&lt;br/&gt;&lt;br/&gt;Programa „<xliff:g id="APP_NAME_2">%1$s</xliff:g>“ galės perduoti srautu programas į „<xliff:g id="DEVICE_NAME_3">%3$s</xliff:g>“, kol pašalinsite prieigą prie šio leidimo."</string>
+    <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"„<xliff:g id="APP_NAME">%1$s</xliff:g>“ prašo leidimo „<xliff:g id="DEVICE_NAME">%2$s</xliff:g>“ vardu, kad galėtų srautu perduoti programas iš jūsų <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"įrenginys"</string>
     <string name="summary_generic" msgid="1761976003668044801">"Ši programa galės sinchronizuoti tam tikrą informaciją, pvz., skambinančio asmens vardą, su jūsų telefonu ir pasirinktu įrenginiu"</string>
     <string name="consent_yes" msgid="8344487259618762872">"Leisti"</string>
diff --git a/packages/CompanionDeviceManager/res/values-lv/strings.xml b/packages/CompanionDeviceManager/res/values-lv/strings.xml
index 880b981..2d79d53 100644
--- a/packages/CompanionDeviceManager/res/values-lv/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-lv/strings.xml
@@ -25,17 +25,17 @@
     <string name="confirmation_title_glasses" msgid="8288346850537727333">"Vai atļaut lietotnei &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; piekļūt ierīcei &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
     <string name="profile_name_glasses" msgid="3506504967216601277">"ierīce"</string>
     <string name="summary_glasses" msgid="5469208629679579157">"Šī lietotne drīkstēs piekļūt norādītajām <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> atļaujām."</string>
-    <string name="title_app_streaming" msgid="6845373585257287200">"Vai atļaut lietotnei &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; straumēt <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> lietotnes ierīcē &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;?"</string>
-    <string name="summary_app_streaming" msgid="1274464413649731829">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> varēs piekļūt visam <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> ekrānā parādītajam vai atskaņotajam saturam, tostarp audio, fotoattēliem, parolēm un ziņojumiem.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_1">%1$s</xliff:g> varēs straumēt lietotnes ierīcē <xliff:g id="DEVICE_NAME">%3$s</xliff:g>, līdz noņemsiet piekļuvi šai atļaujai."</string>
-    <string name="helper_summary_app_streaming" msgid="1944832605534698562">"Lietotne <xliff:g id="APP_NAME">%1$s</xliff:g> pieprasa atļauju attēlot un straumēt lietotnes starp jūsu ierīcēm šīs ierīces vārdā: <xliff:g id="DEVICE_NAME">%2$s</xliff:g>"</string>
+    <string name="title_app_streaming" msgid="1047090167914857893">"Vai atļaut lietotnei &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; straumēt <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> lietotnes un sistēmas funkcijas ierīcē &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;?"</string>
+    <string name="summary_app_streaming" msgid="7990244299655610920">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> varēs piekļūt visam <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> ekrānā parādītajam vai atskaņotajam saturam, tostarp audio, fotoattēliem, maksājumu informācijai, parolēm un ziņojumiem.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_1">%1$s</xliff:g> varēs straumēt lietotnes ierīcē <xliff:g id="DEVICE_NAME">%3$s</xliff:g>, līdz noņemsiet piekļuvi šai atļaujai."</string>
+    <string name="helper_summary_app_streaming" msgid="1872657107404139828">"<xliff:g id="APP_NAME">%1$s</xliff:g> pieprasa atļauju <xliff:g id="DEVICE_NAME">%2$s</xliff:g> vārdā straumēt lietotnes un sistēmas funkcijas no jūsu ierīces <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>."</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4782923323932440751">"Vai atļaut lietotnei &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; piekļūt šai informācijai no jūsu <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>?"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
     <string name="helper_summary_computer" msgid="2298803016482139668">"Lietotne <xliff:g id="APP_NAME">%1$s</xliff:g> pieprasa atļauju piekļūt jūsu <xliff:g id="DEVICE_TYPE">%3$s</xliff:g> fotoattēliem, multivides saturam un paziņojumiem šīs ierīces vārdā: <xliff:g id="DEVICE_NAME">%2$s</xliff:g>."</string>
-    <string name="title_nearby_device_streaming" msgid="4295322493408411976">"Vai atļaut lietotnei &lt;strong&gt;<xliff:g id="DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt; straumēt <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> lietotnes un sistēmas funkcijas ierīcē &lt;strong&gt;<xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>&lt;/strong&gt;?"</string>
-    <string name="summary_nearby_device_streaming" msgid="962267343109051648">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> varēs piekļūt visam <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> ekrānā parādītajam vai atskaņotajam saturam, tostarp audio, fotoattēliem, maksājumu informācijai, parolēm un ziņojumiem.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_1">%1$s</xliff:g> varēs straumēt lietotnes un sistēmas funkcijas ierīcē <xliff:g id="DEVICE_NAME">%3$s</xliff:g>, līdz noņemsiet piekļuvi šai atļaujai."</string>
-    <string name="helper_summary_nearby_device_streaming" msgid="8509848562931818793">"Lietotne <xliff:g id="APP_NAME">%1$s</xliff:g> pieprasa atļauju straumēt lietotnes un citas sistēmas funkcijas starp jūsu ierīcēm šīs ierīces vārdā: <xliff:g id="DEVICE_NAME">%2$s</xliff:g>."</string>
+    <string name="title_nearby_device_streaming" msgid="2727103756701741359">"Vai atļaut lietotnei &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; straumēt <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> lietotnes ierīcē &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;?"</string>
+    <string name="summary_nearby_device_streaming" msgid="70434958004946884">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> varēs piekļūt visam <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g> ekrānā parādītajam vai atskaņotajam saturam, tostarp audio, fotoattēliem, maksājumu informācijai, parolēm un ziņojumiem.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_2">%1$s</xliff:g> varēs straumēt lietotnes ierīcē <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g>, līdz noņemsiet piekļuvi šai atļaujai."</string>
+    <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"<xliff:g id="APP_NAME">%1$s</xliff:g> pieprasa atļauju <xliff:g id="DEVICE_NAME">%2$s</xliff:g> vārdā straumēt lietotnes no jūsu ierīces <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>."</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"ierīce"</string>
     <string name="summary_generic" msgid="1761976003668044801">"Šī lietotne varēs sinhronizēt informāciju (piemēram, zvanītāja vārdu) starp jūsu tālruni un izvēlēto ierīci"</string>
     <string name="consent_yes" msgid="8344487259618762872">"Atļaut"</string>
diff --git a/packages/CompanionDeviceManager/res/values-mk/strings.xml b/packages/CompanionDeviceManager/res/values-mk/strings.xml
index 219f9d14..c0e48b3 100644
--- a/packages/CompanionDeviceManager/res/values-mk/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-mk/strings.xml
@@ -25,17 +25,23 @@
     <string name="confirmation_title_glasses" msgid="8288346850537727333">"Ќе дозволите &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; да управува со &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
     <string name="profile_name_glasses" msgid="3506504967216601277">"уред"</string>
     <string name="summary_glasses" msgid="5469208629679579157">"Апликацијава ќе може да пристапува до овие дозволи на <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
-    <string name="title_app_streaming" msgid="6845373585257287200">"Да се дозволи &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; да ги стримува апликациите од <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> на &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;?"</string>
-    <string name="summary_app_streaming" msgid="1274464413649731829">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> ќе има пристап до сè што е видливо или репродуцирано на <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>, including вклучувајќи ги и аудиото, фотографиите, лозинките и пораките.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_1">%1$s</xliff:g> ќе може да стримува апликации на <xliff:g id="DEVICE_NAME">%3$s</xliff:g> додека не ја повлечете дозволава."</string>
-    <string name="helper_summary_app_streaming" msgid="1944832605534698562">"<xliff:g id="APP_NAME">%1$s</xliff:g> бара дозвола во име на вашиот <xliff:g id="DEVICE_NAME">%2$s</xliff:g> за да прикажува и стримува апликации меѓу вашите уреди"</string>
+    <!-- no translation found for title_app_streaming (1047090167914857893) -->
+    <skip />
+    <!-- no translation found for summary_app_streaming (7990244299655610920) -->
+    <skip />
+    <!-- no translation found for helper_summary_app_streaming (1872657107404139828) -->
+    <skip />
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4782923323932440751">"Дозволете &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; да пристапува до овие податоци на <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
     <string name="helper_summary_computer" msgid="2298803016482139668">"<xliff:g id="APP_NAME">%1$s</xliff:g> бара дозвола во име на вашиот <xliff:g id="DEVICE_NAME">%2$s</xliff:g> за да пристапува до фотографиите, аудиовизуелните содржини и известувањата на <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>"</string>
-    <string name="title_nearby_device_streaming" msgid="4295322493408411976">"Да се дозволи &lt;strong&gt;<xliff:g id="DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt; да ги стримува апликациите и системските функции од <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> на &lt;strong&gt;<xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>&lt;/strong&gt;?"</string>
-    <string name="summary_nearby_device_streaming" msgid="962267343109051648">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> ќе има пристап до сè што е видливо или репродуцирано на <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>, вклучувајќи ги и аудиото, фотографиите, податоците за плаќање, лозинките и пораките.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_1">%1$s</xliff:g> ќе може да стримува апликации и системски функции на <xliff:g id="DEVICE_NAME">%3$s</xliff:g> додека не ја повлечете дозволава."</string>
-    <string name="helper_summary_nearby_device_streaming" msgid="8509848562931818793">"<xliff:g id="APP_NAME">%1$s</xliff:g> бара дозвола во име на вашиот <xliff:g id="DEVICE_NAME">%2$s</xliff:g> за да стримува апликации и други системски функции на вашите уреди"</string>
+    <!-- no translation found for title_nearby_device_streaming (2727103756701741359) -->
+    <skip />
+    <!-- no translation found for summary_nearby_device_streaming (70434958004946884) -->
+    <skip />
+    <!-- no translation found for helper_summary_nearby_device_streaming (4712712177819370967) -->
+    <skip />
     <string name="profile_name_generic" msgid="6851028682723034988">"уред"</string>
     <string name="summary_generic" msgid="1761976003668044801">"Оваа апликација ќе може да ги синхронизира податоците како што се имињата на јавувачите помеѓу вашиот телефон и избраниот уред"</string>
     <string name="consent_yes" msgid="8344487259618762872">"Дозволи"</string>
diff --git a/packages/CompanionDeviceManager/res/values-ml/strings.xml b/packages/CompanionDeviceManager/res/values-ml/strings.xml
index 199f782..1a19f22 100644
--- a/packages/CompanionDeviceManager/res/values-ml/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ml/strings.xml
@@ -25,17 +25,17 @@
     <string name="confirmation_title_glasses" msgid="8288346850537727333">"&lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;? മാനേജ് ചെയ്യാൻ, &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; എന്നതിനെ അനുവദിക്കുക"</string>
     <string name="profile_name_glasses" msgid="3506504967216601277">"ഉപകരണം"</string>
     <string name="summary_glasses" msgid="5469208629679579157">"നിങ്ങളുടെ <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> എന്നതിൽ ഇനിപ്പറയുന്ന അനുമതികൾ ആക്‌സസ് ചെയ്യാൻ ഈ ആപ്പിനെ അനുവദിക്കും"</string>
-    <string name="title_app_streaming" msgid="6845373585257287200">"നിങ്ങളുടെ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> എന്നതിന്റെ ആപ്പുകൾ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt; എന്നതിലേക്ക് സ്ട്രീം ചെയ്യാൻ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; എന്നതിനെ അനുവദിക്കണോ?"</string>
-    <string name="summary_app_streaming" msgid="1274464413649731829">"ഓഡിയോ, ഫോട്ടോകൾ, പാസ്‌വേഡുകൾ, സന്ദേശങ്ങൾ എന്നിവ ഉൾപ്പെടെ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> എന്നതിൽ ദൃശ്യമാകുന്നതോ പ്ലേ ചെയ്യുന്നതോ എല്ലാ എല്ലാത്തിലേക്കും <xliff:g id="APP_NAME_0">%1$s</xliff:g> എന്നതിന് ആക്സസ് ഉണ്ടായിരിക്കും.&lt;br/&gt;&lt;br/&gt;നിങ്ങൾ ഈ അനുമതിയിലേക്കുള്ള ആക്സസ് നീക്കം ചെയ്യുന്നത് വരെ <xliff:g id="APP_NAME_1">%1$s</xliff:g> എന്നതിന് <xliff:g id="DEVICE_NAME">%3$s</xliff:g> എന്നതിലേക്ക് ആപ്പുകൾ സ്ട്രീം ചെയ്യാനാകും."</string>
-    <string name="helper_summary_app_streaming" msgid="1944832605534698562">"നിങ്ങളുടെ ഉപകരണങ്ങൾക്കിടയിൽ ആപ്പുകൾ സ്ട്രീം ചെയ്യാനും പ്രദർശിപ്പിക്കാനും നിങ്ങളുടെ <xliff:g id="DEVICE_NAME">%2$s</xliff:g> എന്ന ഉപകരണത്തിന് വേണ്ടി <xliff:g id="APP_NAME">%1$s</xliff:g> അനുമതി അഭ്യർത്ഥിക്കുന്നു"</string>
+    <string name="title_app_streaming" msgid="1047090167914857893">"നിങ്ങളുടെ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> എന്നതിന്റെ ആപ്പുകളും സിസ്റ്റം ഫീച്ചറുകളും &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt; എന്നതിലേക്ക് സ്ട്രീം ചെയ്യാൻ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; എന്നതിനെ അനുവദിക്കണോ?"</string>
+    <string name="summary_app_streaming" msgid="7990244299655610920">"ഓഡിയോ, ഫോട്ടോകൾ, പാസ്‌വേഡുകൾ, സന്ദേശങ്ങൾ എന്നിവ ഉൾപ്പെടെ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> എന്നതിൽ ദൃശ്യമാകുന്നതോ പ്ലേ ചെയ്യുന്നതോ എല്ലാ എല്ലാത്തിലേക്കും <xliff:g id="APP_NAME_0">%1$s</xliff:g> എന്നതിന് ആക്സസ് ഉണ്ടായിരിക്കും.&lt;br/&gt;&lt;br/&gt;നിങ്ങൾ ഈ അനുമതിയിലേക്കുള്ള ആക്സസ് നീക്കം ചെയ്യുന്നത് വരെ <xliff:g id="APP_NAME_1">%1$s</xliff:g> എന്നതിന് <xliff:g id="DEVICE_NAME">%3$s</xliff:g> എന്നതിലേക്ക് ആപ്പുകൾ സ്ട്രീം ചെയ്യാനാകും."</string>
+    <string name="helper_summary_app_streaming" msgid="1872657107404139828">"നിങ്ങളുടെ <xliff:g id="DEVICE_TYPE">%3$s</xliff:g> എന്നതിൽ നിന്ന് ആപ്പുകളും സിസ്റ്റം ഫീച്ചറുകളും സ്ട്രീം ചെയ്യാൻ <xliff:g id="DEVICE_NAME">%2$s</xliff:g> എന്നതിന്റെ പേരിൽ <xliff:g id="APP_NAME">%1$s</xliff:g> അനുമതി അഭ്യർത്ഥിക്കുന്നു"</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4782923323932440751">"നിങ്ങളുടെ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> എന്നതിൽ നിന്ന് ഈ വിവരങ്ങൾ ആക്‌സസ് ചെയ്യാൻ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; എന്നതിനെ അനുവദിക്കുക"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
     <string name="helper_summary_computer" msgid="2298803016482139668">"നിങ്ങളുടെ <xliff:g id="DEVICE_TYPE">%3$s</xliff:g> എന്നതിലെ ഫോട്ടോകൾ, മീഡിയ, അറിയിപ്പുകൾ എന്നിവ ആക്സസ് ചെയ്യാൻ <xliff:g id="DEVICE_NAME">%2$s</xliff:g> എന്ന ഉപകരണത്തിന് വേണ്ടി <xliff:g id="APP_NAME">%1$s</xliff:g> അനുമതി അഭ്യർത്ഥിക്കുന്നു"</string>
-    <string name="title_nearby_device_streaming" msgid="4295322493408411976">"നിങ്ങളുടെ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> എന്നതിന്റെ ആപ്പുകളും സിസ്റ്റം ഫീച്ചറുകളും &lt;strong&gt;<xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>&lt;/strong&gt; എന്നതിലേക്ക് സ്ട്രീം ചെയ്യാൻ &lt;strong&gt;<xliff:g id="DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt; എന്നതിനെ അനുവദിക്കണോ?"</string>
-    <string name="summary_nearby_device_streaming" msgid="962267343109051648">"ഓഡിയോ, ഫോട്ടോകൾ, പാസ്‌വേഡുകൾ, സന്ദേശങ്ങൾ എന്നിവ ഉൾപ്പെടെ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> എന്നതിൽ ദൃശ്യമാകുന്നതോ പ്ലേ ചെയ്യുന്നതോ എല്ലാ എല്ലാത്തിലേക്കും <xliff:g id="APP_NAME_0">%1$s</xliff:g> എന്നതിന് ആക്സസ് ഉണ്ടായിരിക്കും.&lt;br/&gt;&lt;br/&gt;നിങ്ങൾ ഈ അനുമതിയിലേക്കുള്ള ആക്സസ് നീക്കം ചെയ്യുന്നത് വരെ <xliff:g id="APP_NAME_1">%1$s</xliff:g> എന്നതിന് <xliff:g id="DEVICE_NAME">%3$s</xliff:g> എന്നതിലേക്ക് ആപ്പുകളും മറ്റ് സിസ്റ്റം ഫീച്ചറുകളും സ്ട്രീം ചെയ്യാനാകും."</string>
-    <string name="helper_summary_nearby_device_streaming" msgid="8509848562931818793">"നിങ്ങളുടെ ഉപകരണങ്ങളിൽ ഒന്നിൽ നിന്ന് അടുത്തതിലേക്ക് ആപ്പുകളും മറ്റ് സിസ്റ്റം ഫീച്ചറുകളും സ്ട്രീം ചെയ്യാൻ <xliff:g id="DEVICE_NAME">%2$s</xliff:g> എന്ന ഉപകരണത്തിന് വേണ്ടി <xliff:g id="APP_NAME">%1$s</xliff:g> എന്നത് അനുമതി അഭ്യർത്ഥിക്കുന്നു"</string>
+    <string name="title_nearby_device_streaming" msgid="2727103756701741359">"നിങ്ങളുടെ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> എന്നതിന്റെ ആപ്പുകൾ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt; എന്നതിലേക്ക് സ്ട്രീം ചെയ്യാൻ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; എന്നതിനെ അനുവദിക്കണോ?"</string>
+    <string name="summary_nearby_device_streaming" msgid="70434958004946884">"ഓഡിയോ, ഫോട്ടോകൾ, പേയ്മെന്റ് വിവരങ്ങൾ, പാസ്‌വേഡുകൾ, സന്ദേശങ്ങൾ എന്നിവ ഉൾപ്പെടെ <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g> എന്നതിൽ ദൃശ്യമാകുന്നതോ പ്ലേ ചെയ്യുന്നതോ എല്ലാ എല്ലാത്തിലേക്കും <xliff:g id="APP_NAME_0">%1$s</xliff:g> എന്നതിന് ആക്സസ് ഉണ്ടായിരിക്കും.&lt;br/&gt;&lt;br/&gt;നിങ്ങൾ ഈ അനുമതിയിലേക്കുള്ള ആക്സസ് നീക്കം ചെയ്യുന്നത് വരെ <xliff:g id="APP_NAME_2">%1$s</xliff:g> എന്നതിന് <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> എന്നതിലേക്ക് ആപ്പുകൾ സ്ട്രീം ചെയ്യാനാകും."</string>
+    <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"നിങ്ങളുടെ <xliff:g id="DEVICE_TYPE">%3$s</xliff:g> എന്നതിൽ നിന്ന് ആപ്പുകൾ സ്ട്രീം ചെയ്യാൻ <xliff:g id="DEVICE_NAME">%2$s</xliff:g> എന്നതിന്റെ പേരിൽ <xliff:g id="APP_NAME">%1$s</xliff:g> അനുമതി അഭ്യർത്ഥിക്കുന്നു"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"ഉപകരണം"</string>
     <string name="summary_generic" msgid="1761976003668044801">"വിളിക്കുന്നയാളുടെ പേര് പോലുള്ള വിവരങ്ങൾ നിങ്ങളുടെ ഫോണിനും തിരഞ്ഞെടുത്ത ഉപകരണത്തിനും ഇടയിൽ സമന്വയിപ്പിക്കുന്നതിന് ഈ ആപ്പിന് കഴിയും"</string>
     <string name="consent_yes" msgid="8344487259618762872">"അനുവദിക്കുക"</string>
diff --git a/packages/CompanionDeviceManager/res/values-mn/strings.xml b/packages/CompanionDeviceManager/res/values-mn/strings.xml
index 94f862c..543bdfa 100644
--- a/packages/CompanionDeviceManager/res/values-mn/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-mn/strings.xml
@@ -25,17 +25,23 @@
     <string name="confirmation_title_glasses" msgid="8288346850537727333">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;-д &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;-г удирдахыг зөвшөөрөх үү?"</string>
     <string name="profile_name_glasses" msgid="3506504967216601277">"төхөөрөмж"</string>
     <string name="summary_glasses" msgid="5469208629679579157">"Энэ аппад таны <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> дээрх эдгээр зөвшөөрөлд хандахыг зөвшөөрнө"</string>
-    <string name="title_app_streaming" msgid="6845373585257287200">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;-д таны <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>-н аппуудыг &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;-д дамжуулахыг зөвшөөрөх үү?"</string>
-    <string name="summary_app_streaming" msgid="1274464413649731829">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> аудио, зураг, нууц үг, мессеж зэрэг <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> дээр харагдаж эсвэл тоглуулж буй аливаа зүйлд хандах эрхтэй болно.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_1">%1$s</xliff:g> таныг энэ зөвшөөрлийн хандалтыг хасах хүртэл <xliff:g id="DEVICE_NAME">%3$s</xliff:g>-д апп дамжуулах боломжтой байх болно."</string>
-    <string name="helper_summary_app_streaming" msgid="1944832605534698562">"<xliff:g id="APP_NAME">%1$s</xliff:g> таны <xliff:g id="DEVICE_NAME">%2$s</xliff:g>-н өмнөөс таны төхөөрөмжүүдийн хооронд апп үзүүлж, дамжуулах зөвшөөрлийг хүсэж байна"</string>
+    <!-- no translation found for title_app_streaming (1047090167914857893) -->
+    <skip />
+    <!-- no translation found for summary_app_streaming (7990244299655610920) -->
+    <skip />
+    <!-- no translation found for helper_summary_app_streaming (1872657107404139828) -->
+    <skip />
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4782923323932440751">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;-д таны <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>-н энэ мэдээлэлд хандахыг зөвшөөрнө үү"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
     <string name="helper_summary_computer" msgid="2298803016482139668">"<xliff:g id="APP_NAME">%1$s</xliff:g> таны <xliff:g id="DEVICE_NAME">%2$s</xliff:g>-н өмнөөс <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>-н зураг, медиа, мэдэгдэлд хандах зөвшөөрлийг хүсэж байна"</string>
-    <string name="title_nearby_device_streaming" msgid="4295322493408411976">"&lt;strong&gt;<xliff:g id="DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt;-д таны <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>-н апп болон системийн онцлогуудыг &lt;strong&gt;<xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>&lt;/strong&gt;-д дамжуулахыг зөвшөөрөх үү?"</string>
-    <string name="summary_nearby_device_streaming" msgid="962267343109051648">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> аудио, зураг, төлбөрийн мэдээлэл, нууц үг, мессеж зэрэг таны <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> дээр харагдаж эсвэл тоглуулж буй аливаа зүйлд хандах эрхтэй байх болно.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_1">%1$s</xliff:g> таныг энэ зөвшөөрлийн хандалтыг хасах хүртэл <xliff:g id="DEVICE_NAME">%3$s</xliff:g>-д апп болон системийн онцлогуудыг дамжуулах боломжтой байх болно."</string>
-    <string name="helper_summary_nearby_device_streaming" msgid="8509848562931818793">"<xliff:g id="APP_NAME">%1$s</xliff:g> таны <xliff:g id="DEVICE_NAME">%2$s</xliff:g>-н өмнөөс таны төхөөрөмжүүдийн хооронд апп болон системийн бусад онцлогийг дамжуулах зөвшөөрлийг хүсэж байна"</string>
+    <!-- no translation found for title_nearby_device_streaming (2727103756701741359) -->
+    <skip />
+    <!-- no translation found for summary_nearby_device_streaming (70434958004946884) -->
+    <skip />
+    <!-- no translation found for helper_summary_nearby_device_streaming (4712712177819370967) -->
+    <skip />
     <string name="profile_name_generic" msgid="6851028682723034988">"төхөөрөмж"</string>
     <string name="summary_generic" msgid="1761976003668044801">"Энэ апп залгаж буй хүний нэр зэрэг мэдээллийг таны утас болон сонгосон төхөөрөмжийн хооронд синк хийх боломжтой болно"</string>
     <string name="consent_yes" msgid="8344487259618762872">"Зөвшөөрөх"</string>
diff --git a/packages/CompanionDeviceManager/res/values-mr/strings.xml b/packages/CompanionDeviceManager/res/values-mr/strings.xml
index c758d29..5ac1e56 100644
--- a/packages/CompanionDeviceManager/res/values-mr/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-mr/strings.xml
@@ -25,17 +25,17 @@
     <string name="confirmation_title_glasses" msgid="8288346850537727333">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ला &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; व्यवस्थापित करण्याची अनुमती द्यायची आहे?"</string>
     <string name="profile_name_glasses" msgid="3506504967216601277">"डिव्हाइस"</string>
     <string name="summary_glasses" msgid="5469208629679579157">"या अ‍ॅपला तुमच्या <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> वर या परवानग्या अ‍ॅक्सेस करण्याची अनुमती दिली जाईल"</string>
-    <string name="title_app_streaming" msgid="6845373585257287200">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ला तुमच्या <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> अ‍ॅप्स &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;वर स्ट्रीम करण्याची अनुमती द्यायची आहे का?"</string>
-    <string name="summary_app_streaming" msgid="1274464413649731829">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> ला ऑडिओ, फोटो, पासवर्ड आणि मेसेज यांसह <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> वर दिसणाऱ्या किंवा प्ले होणाऱ्या सर्व गोष्टींचा अ‍ॅक्सेस असेल.&lt;br/&gt;&lt;br/&gt;तुम्ही या परवानगीचा अ‍ॅक्सेस काढून टाकेपर्यंत <xliff:g id="APP_NAME_1">%1$s</xliff:g> हे <xliff:g id="DEVICE_NAME">%3$s</xliff:g> वर ॲप्स स्ट्रीम करू शकेल."</string>
-    <string name="helper_summary_app_streaming" msgid="1944832605534698562">"तुमच्या डिव्हाइसदरम्यान ॲप्स दाखवण्यासाठी आणि स्ट्रीम करण्यासाठी <xliff:g id="APP_NAME">%1$s</xliff:g> हे तुमच्या <xliff:g id="DEVICE_NAME">%2$s</xliff:g> च्या वतीने परवानगीची विनंती करत आहे"</string>
+    <string name="title_app_streaming" msgid="1047090167914857893">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ला तुमच्या <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> अ‍ॅप्स आणि सिस्टीमची वैशिष्ट्ये &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;वर स्ट्रीम करण्याची अनुमती द्यायची आहे का?"</string>
+    <string name="summary_app_streaming" msgid="7990244299655610920">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> ला ऑडिओ, फोटो, पेमेंट माहिती, पासवर्ड आणि मेसेज यांसह तुमच्या <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> वर दिसणाऱ्या किंवा प्ले होणाऱ्या सर्व गोष्टींचा अ‍ॅक्सेस असेल.&lt;br/&gt;&lt;br/&gt;तुम्ही या परवानगीचा अ‍ॅक्सेस काढून टाकेपर्यंत <xliff:g id="APP_NAME_1">%1$s</xliff:g> हे ॲप्स <xliff:g id="DEVICE_NAME">%3$s</xliff:g> वर स्ट्रीम करू शकेल."</string>
+    <string name="helper_summary_app_streaming" msgid="1872657107404139828">"<xliff:g id="APP_NAME">%1$s</xliff:g> हे तुमच्या <xliff:g id="DEVICE_TYPE">%3$s</xliff:g> वरून अ‍ॅप्स आणि सिस्टीम वैशिष्ट्ये स्ट्रीम करण्यासाठी <xliff:g id="DEVICE_NAME">%2$s</xliff:g> च्या वतीने परवानगीची विनंती करत आहे"</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4782923323932440751">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ला ही माहिती तुमच्या <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> वरून अ‍ॅक्सेस करण्यासाठी अनुमती द्या"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
     <string name="helper_summary_computer" msgid="2298803016482139668">"तुमच्या <xliff:g id="DEVICE_TYPE">%3$s</xliff:g> मधील फोटो, मीडिया आणि नोटिफिकेशन अ‍ॅक्सेस करण्यासाठी <xliff:g id="APP_NAME">%1$s</xliff:g> हे तुमच्या <xliff:g id="DEVICE_NAME">%2$s</xliff:g> च्या वतीने परवानगीची विनंती करत आहे"</string>
-    <string name="title_nearby_device_streaming" msgid="4295322493408411976">"&lt;strong&gt;<xliff:g id="DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt; ला तुमच्या <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> अ‍ॅप्स आणि सिस्टीमची वैशिष्ट्ये &lt;strong&gt;<xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>&lt;/strong&gt;वर स्ट्रीम करण्याची अनुमती द्यायची आहे का?"</string>
-    <string name="summary_nearby_device_streaming" msgid="962267343109051648">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> ला ऑडिओ, फोटो, पेमेंट माहिती, पासवर्ड आणि मेसेज यांसह तुमच्या <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> वर दिसणाऱ्या किंवा प्ले होणाऱ्या सर्व गोष्टींचा अ‍ॅक्सेस असेल.&lt;br/&gt;&lt;br/&gt;तुम्ही या परवानगीचा अ‍ॅक्सेस काढून टाकेपर्यंत <xliff:g id="APP_NAME_1">%1$s</xliff:g> हे ॲप्स आणि सिस्टीमची वैशिष्ट्ये <xliff:g id="DEVICE_NAME">%3$s</xliff:g> वर स्ट्रीम करू शकेल."</string>
-    <string name="helper_summary_nearby_device_streaming" msgid="8509848562931818793">"तुमच्या डिव्हाइसदरम्यान ॲप्स आणि इतर सिस्टीम वैशिष्‍ट्ये स्ट्रीम करण्यासाठी <xliff:g id="APP_NAME">%1$s</xliff:g> हे तुमच्या <xliff:g id="DEVICE_NAME">%2$s</xliff:g> च्या वतीने परवानगीची विनंती करत आहे"</string>
+    <string name="title_nearby_device_streaming" msgid="2727103756701741359">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ला तुमच्या <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> ला अ‍ॅप्स &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;वर स्ट्रीम करण्याची अनुमती द्यायची आहे का?"</string>
+    <string name="summary_nearby_device_streaming" msgid="70434958004946884">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> ला ऑडिओ, फोटो, पेमेंट माहिती, पासवर्ड आणि मेसेज यांसह तुमच्या <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g> वर दिसणाऱ्या किंवा प्ले होणाऱ्या सर्व गोष्टींचा अ‍ॅक्सेस असेल.&lt;br/&gt;&lt;br/&gt;तुम्ही या परवानगीचा अ‍ॅक्सेस काढून टाकेपर्यंत <xliff:g id="APP_NAME_2">%1$s</xliff:g> हे <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> वर ॲप्स स्ट्रीम करू शकेल."</string>
+    <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"<xliff:g id="APP_NAME">%1$s</xliff:g> हे तुमच्या <xliff:g id="DEVICE_TYPE">%3$s</xliff:g> वरून अ‍ॅप्स आणि सिस्टीम वैशिष्ट्ये स्ट्रीम करण्यासाठी <xliff:g id="DEVICE_NAME">%2$s</xliff:g> च्या वतीने परवानगीची विनंती करत आहे"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"डिव्हाइस"</string>
     <string name="summary_generic" msgid="1761976003668044801">"हे ॲप तुमचा फोन आणि निवडलेल्या डिव्‍हाइसदरम्यान कॉल करत असलेल्‍या एखाद्या व्यक्तीचे नाव यासारखी माहिती सिंक करू शकेल"</string>
     <string name="consent_yes" msgid="8344487259618762872">"अनुमती द्या"</string>
diff --git a/packages/CompanionDeviceManager/res/values-ms/strings.xml b/packages/CompanionDeviceManager/res/values-ms/strings.xml
index 424b815b..13916b7 100644
--- a/packages/CompanionDeviceManager/res/values-ms/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ms/strings.xml
@@ -25,17 +25,17 @@
     <string name="confirmation_title_glasses" msgid="8288346850537727333">"Benarkan &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; mengurus &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
     <string name="profile_name_glasses" msgid="3506504967216601277">"peranti"</string>
     <string name="summary_glasses" msgid="5469208629679579157">"Apl ini akan dibenarkan untuk mengakses kebenaran yang berikut pada <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> anda"</string>
-    <string name="title_app_streaming" msgid="6845373585257287200">"Benarkan &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; untuk menstrim apl <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> anda kepada &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;?"</string>
-    <string name="summary_app_streaming" msgid="1274464413649731829">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> akan mendapat akses kepada semua perkara yang dipaparkan atau dimainkan pada <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>, termasuk audio, foto, kata laluan dan mesej.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_1">%1$s</xliff:g> akan dapat menstrim apl kepada <xliff:g id="DEVICE_NAME">%3$s</xliff:g> sehingga anda mengalih keluar akses kepada kebenaran ini."</string>
-    <string name="helper_summary_app_streaming" msgid="1944832605534698562">"<xliff:g id="APP_NAME">%1$s</xliff:g> meminta kebenaran bagi pihak <xliff:g id="DEVICE_NAME">%2$s</xliff:g> anda untuk memaparkan dan menstrim apl antara peranti anda"</string>
+    <string name="title_app_streaming" msgid="1047090167914857893">"Benarkan &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; untuk menstrim apl dan ciri sistem <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> anda kepada &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;?"</string>
+    <string name="summary_app_streaming" msgid="7990244299655610920">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> akan mendapat akses kepada semua perkara yang dipaparkan atau dimainkan pada <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> anda, termasuk audio, foto, maklumat pembayaran, kata laluan dan mesej.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_1">%1$s</xliff:g> akan dapat menstrim apl kepada <xliff:g id="DEVICE_NAME">%3$s</xliff:g> sehingga anda mengalih keluar akses kepada kebenaran ini."</string>
+    <string name="helper_summary_app_streaming" msgid="1872657107404139828">"<xliff:g id="APP_NAME">%1$s</xliff:g> meminta kebenaran bagi pihak <xliff:g id="DEVICE_NAME">%2$s</xliff:g> untuk menstrim apl dan ciri sistem daripada <xliff:g id="DEVICE_TYPE">%3$s</xliff:g> anda"</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4782923323932440751">"Benarkan &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; untuk mengakses maklumat ini daripada <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> anda"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
     <string name="helper_summary_computer" msgid="2298803016482139668">"<xliff:g id="APP_NAME">%1$s</xliff:g> sedang meminta kebenaran bagi pihak <xliff:g id="DEVICE_NAME">%2$s</xliff:g> anda untuk mengakses foto, media dan pemberitahuan <xliff:g id="DEVICE_TYPE">%3$s</xliff:g> anda"</string>
-    <string name="title_nearby_device_streaming" msgid="4295322493408411976">"Benarkan &lt;strong&gt;<xliff:g id="DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt; untuk menstrim apl dan ciri sistem <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> anda kepada &lt;strong&gt;<xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>&lt;/strong&gt;?"</string>
-    <string name="summary_nearby_device_streaming" msgid="962267343109051648">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> akan mendapat akses kepada semua perkara yang dipaparkan atau dimainkan pada <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> anda, termasuk audio, foto, maklumat pembayaran, kata laluan dan mesej.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_1">%1$s</xliff:g> akan dapat menstrim apl dan ciri sistem kepada <xliff:g id="DEVICE_NAME">%3$s</xliff:g> sehingga anda mengalih keluar akses kepada kebenaran ini."</string>
-    <string name="helper_summary_nearby_device_streaming" msgid="8509848562931818793">"<xliff:g id="APP_NAME">%1$s</xliff:g> sedang meminta kebenaran bagi pihak <xliff:g id="DEVICE_NAME">%2$s</xliff:g> anda untuk menstrim apl dan ciri sistem lain antara peranti anda"</string>
+    <string name="title_nearby_device_streaming" msgid="2727103756701741359">"Benarkan &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; untuk menstrim apl <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> anda kepada &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;?"</string>
+    <string name="summary_nearby_device_streaming" msgid="70434958004946884">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> akan mendapat akses kepada semua perkara yang dipaparkan atau dimainkan pada <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>, termasuk audio, foto, maklumat pembayaran, kata laluan dan mesej.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_2">%1$s</xliff:g> akan dapat menstrim apl kepada <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> sehingga anda mengalih keluar akses kepada kebenaran ini."</string>
+    <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"<xliff:g id="APP_NAME">%1$s</xliff:g> meminta kebenaran bagi pihak <xliff:g id="DEVICE_NAME">%2$s</xliff:g> untuk menstrim apl daripada <xliff:g id="DEVICE_TYPE">%3$s</xliff:g> anda"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"peranti"</string>
     <string name="summary_generic" msgid="1761976003668044801">"Apl ini akan dapat menyegerakkan maklumat seperti nama individu yang memanggil, antara telefon anda dengan peranti yang dipilih"</string>
     <string name="consent_yes" msgid="8344487259618762872">"Benarkan"</string>
diff --git a/packages/CompanionDeviceManager/res/values-my/strings.xml b/packages/CompanionDeviceManager/res/values-my/strings.xml
index 6185f314..bb4e7c5 100644
--- a/packages/CompanionDeviceManager/res/values-my/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-my/strings.xml
@@ -25,17 +25,17 @@
     <string name="confirmation_title_glasses" msgid="8288346850537727333">"&lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ကို &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; အား စီမံခွင့်ပြုမလား။"</string>
     <string name="profile_name_glasses" msgid="3506504967216601277">"စက်"</string>
     <string name="summary_glasses" msgid="5469208629679579157">"သင့် <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> တွင် ၎င်းခွင့်ပြုချက်များရယူရန် ဤအက်ပ်ကိုခွင့်ပြုမည်"</string>
-    <string name="title_app_streaming" msgid="6845373585257287200">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; အား သင့် <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> ၏ အက်ပ်များကို &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt; တွင် တိုက်ရိုက်ဖွင့်ခွင့်ပြုမလား။"</string>
-    <string name="summary_app_streaming" msgid="1274464413649731829">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> သည် အသံ၊ ဓာတ်ပုံ၊ စကားဝှက်နှင့် မက်ဆေ့ဂျ်များအပါအဝင် <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> တွင် မြင်နိုင်သော (သို့) ဖွင့်ထားသော အရာအားလုံးကို သုံးခွင့်ရှိပါမည်။&lt;br/&gt;&lt;br/&gt;ဤခွင့်ပြုချက်သုံးခွင့်ကို သင်မဖယ်ရှားမချင်း <xliff:g id="APP_NAME_1">%1$s</xliff:g> သည် အက်ပ်များကို <xliff:g id="DEVICE_NAME">%3$s</xliff:g> တွင် တိုက်ရိုက်ဖွင့်နိုင်ပါမည်။"</string>
-    <string name="helper_summary_app_streaming" msgid="1944832605534698562">"<xliff:g id="APP_NAME">%1$s</xliff:g> သည် သင့်စက်များအကြား အက်ပ်များ ပြပြီး တိုက်ရိုက်ဖွင့်ရန် <xliff:g id="DEVICE_NAME">%2$s</xliff:g> ကိုယ်စား ခွင့်ပြုချက်တောင်းနေသည်"</string>
+    <string name="title_app_streaming" msgid="1047090167914857893">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; အား သင့် <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> ၏ အက်ပ်နှင့် စနစ်တူးလ်များကို &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt; တွင် တိုက်ရိုက်ဖွင့်ခွင့်ပြုမလား။"</string>
+    <string name="summary_app_streaming" msgid="7990244299655610920">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> သည် အသံ၊ ဓာတ်ပုံ၊ ငွေချေအချက်အလက်၊ စကားဝှက်နှင့် မက်ဆေ့ဂျ်များအပါအဝင် သင့် <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> တွင် မြင်နိုင်သော (သို့) ဖွင့်ထားသော အရာအားလုံးကို သုံးခွင့်ရှိပါမည်။&lt;br/&gt;&lt;br/&gt;ဤခွင့်ပြုချက်သုံးခွင့်ကို သင်မဖယ်ရှားမချင်း <xliff:g id="APP_NAME_1">%1$s</xliff:g> သည် <xliff:g id="DEVICE_NAME">%3$s</xliff:g> တွင် အက်ပ်များကို တိုက်ရိုက်ဖွင့်နိုင်ပါမည်။"</string>
+    <string name="helper_summary_app_streaming" msgid="1872657107404139828">"<xliff:g id="APP_NAME">%1$s</xliff:g> သည် သင့် <xliff:g id="DEVICE_TYPE">%3$s</xliff:g> မှ အက်ပ်များနှင့် စနစ်တူးလ်များကို တိုက်ရိုက်ဖွင့်ရန် <xliff:g id="DEVICE_NAME">%2$s</xliff:g> ကိုယ်စား ခွင့်ပြုချက်တောင်းနေသည်"</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4782923323932440751">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; အား သင့် <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> မှ ဤအချက်အလက်ကို သုံးခွင့်ပြုမည်"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
     <string name="helper_summary_computer" msgid="2298803016482139668">"<xliff:g id="APP_NAME">%1$s</xliff:g> သည် သင့် <xliff:g id="DEVICE_TYPE">%3$s</xliff:g> ၏ ဓာတ်ပုံ၊ မီဒီယာနှင့် အကြောင်းကြားချက်များသုံးရန် <xliff:g id="DEVICE_NAME">%2$s</xliff:g> ကိုယ်စား ခွင့်ပြုချက်တောင်းနေသည်"</string>
-    <string name="title_nearby_device_streaming" msgid="4295322493408411976">"&lt;strong&gt;<xliff:g id="DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt; အား သင့် <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> ၏ အက်ပ်နှင့် စနစ်တူးလ်များကို &lt;strong&gt;<xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>&lt;/strong&gt; တွင် တိုက်ရိုက်ဖွင့်ခွင့်ပြုမလား။"</string>
-    <string name="summary_nearby_device_streaming" msgid="962267343109051648">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> သည် အသံ၊ ဓာတ်ပုံ၊ ငွေချေအချက်အလက်၊ စကားဝှက်နှင့် မက်ဆေ့ဂျ်များအပါအဝင် သင့် <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> တွင် မြင်နိုင်သော (သို့) ဖွင့်ထားသော အရာအားလုံးကို သုံးခွင့်ရှိပါမည်။&lt;br/&gt;&lt;br/&gt;ဤခွင့်ပြုချက်သုံးခွင့်ကို သင်မဖယ်ရှားမချင်း <xliff:g id="APP_NAME_1">%1$s</xliff:g> သည် အက်ပ်နှင့် စနစ်တူးလ်များကို <xliff:g id="DEVICE_NAME">%3$s</xliff:g> တွင် တိုက်ရိုက်ဖွင့်နိုင်ပါမည်။"</string>
-    <string name="helper_summary_nearby_device_streaming" msgid="8509848562931818793">"<xliff:g id="APP_NAME">%1$s</xliff:g> သည် သင့်စက်များအကြား အက်ပ်နှင့် အခြားစနစ်တူးလ်များ တိုက်ရိုက်ဖွင့်ရန် <xliff:g id="DEVICE_NAME">%2$s</xliff:g> ကိုယ်စား ခွင့်ပြုချက်တောင်းနေသည်"</string>
+    <string name="title_nearby_device_streaming" msgid="2727103756701741359">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; အား သင့် <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> ၏ အက်ပ်များကို &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt; တွင် တိုက်ရိုက်ဖွင့်ခွင့်ပြုမလား။"</string>
+    <string name="summary_nearby_device_streaming" msgid="70434958004946884">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> သည် အသံ၊ ဓာတ်ပုံ၊ စကားဝှက်နှင့် မက်ဆေ့ဂျ်များအပါအဝင် <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g> တွင် မြင်နိုင်သော (သို့) ဖွင့်ထားသော အရာအားလုံးကို သုံးခွင့်ရှိပါမည်။&lt;br/&gt;&lt;br/&gt;ဤခွင့်ပြုချက်သုံးခွင့်ကို သင်မဖယ်ရှားမချင်း <xliff:g id="APP_NAME_2">%1$s</xliff:g> သည် <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> တွင် အက်ပ်များကို တိုက်ရိုက်ဖွင့်နိုင်ပါမည်။"</string>
+    <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"<xliff:g id="APP_NAME">%1$s</xliff:g> သည် သင့် <xliff:g id="DEVICE_TYPE">%3$s</xliff:g> မှ အက်ပ်များကို တိုက်ရိုက်ဖွင့်ရန် <xliff:g id="DEVICE_NAME">%2$s</xliff:g> ကိုယ်စား ခွင့်ပြုချက်တောင်းနေသည်"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"စက်"</string>
     <string name="summary_generic" msgid="1761976003668044801">"ဤအက်ပ်သည် သင့်ဖုန်းနှင့် ရွေးထားသောစက်အကြား ခေါ်ဆိုသူ၏အမည်ကဲ့သို့ အချက်အလက်ကို စင့်ခ်လုပ်နိုင်ပါမည်"</string>
     <string name="consent_yes" msgid="8344487259618762872">"ခွင့်ပြုရန်"</string>
@@ -61,7 +61,7 @@
     <string name="permission_call_logs_summary" msgid="7545243592757693321">"ဖုန်းခေါ်ဆိုမှတ်တမ်းကို ဖတ်နိုင်၊ ရေးနိုင်သည်"</string>
     <string name="permission_sms_summary" msgid="8499509535410068616">"SMS မက်ဆေ့ဂျ်များ ပို့နိုင်၊ ကြည့်နိုင်သည်"</string>
     <string name="permission_contacts_summary" msgid="2840800622763086808">"သင့်အဆက်အသွယ်များကို ဝင်ကြည့်နိုင်သည်"</string>
-    <string name="permission_calendar_summary" msgid="8430353935747336165">"သင့်ပြက္ခဒိန်ကို ဝင်ကြည့်နိုင်သည်"</string>
+    <string name="permission_calendar_summary" msgid="8430353935747336165">"သင့်ပြက္ခဒိန်အား ဝင်သုံးနိုင်သည်"</string>
     <string name="permission_microphone_summary" msgid="4862628553869973259">"အသံသွင်းနိုင်သည်"</string>
     <string name="permission_nearby_devices_summary" msgid="1306752848196464817">"အနီးတစ်ဝိုက်ရှိ စက်များ၏ ဆက်စပ်နေရာကို ရှာခြင်း၊ ချိတ်ဆက်ခြင်းနှင့် သတ်မှတ်ခြင်းတို့ လုပ်နိုင်သည်"</string>
     <string name="permission_notification_listener_access_summary" msgid="7856071768185367749">"အဆက်အသွယ်၊ မက်ဆေ့ဂျ်နှင့် ဓာတ်ပုံများကဲ့သို့ အချက်အလက်များအပါအဝင် အကြောင်းကြားချက်အားလုံးကို ဖတ်နိုင်သည်"</string>
diff --git a/packages/CompanionDeviceManager/res/values-nb/strings.xml b/packages/CompanionDeviceManager/res/values-nb/strings.xml
index 00700ec..e8adbcd 100644
--- a/packages/CompanionDeviceManager/res/values-nb/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-nb/strings.xml
@@ -25,17 +25,17 @@
     <string name="confirmation_title_glasses" msgid="8288346850537727333">"Vil du la &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; administrere &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
     <string name="profile_name_glasses" msgid="3506504967216601277">"enheten"</string>
     <string name="summary_glasses" msgid="5469208629679579157">"Denne appen får disse tillatelsene på <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
-    <string name="title_app_streaming" msgid="6845373585257287200">"Vil du la &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; strømme apper fra <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> til &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;?"</string>
-    <string name="summary_app_streaming" msgid="1274464413649731829">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> får tilgang til alt som vises eller spilles av på <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>, inkludert lyd, bilder, passord og meldinger.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_1">%1$s</xliff:g> får muligheten til å strømme apper til <xliff:g id="DEVICE_NAME">%3$s</xliff:g> frem til du fjerner tilgangen til denne tillatelsen."</string>
-    <string name="helper_summary_app_streaming" msgid="1944832605534698562">"<xliff:g id="APP_NAME">%1$s</xliff:g> ber om tillatelse til å vise og strømme apper mellom enhetene dine, på vegne av <xliff:g id="DEVICE_NAME">%2$s</xliff:g>"</string>
+    <string name="title_app_streaming" msgid="1047090167914857893">"Vil du la &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; strømme apper og systemfunksjoner fra <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> til &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;?"</string>
+    <string name="summary_app_streaming" msgid="7990244299655610920">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> kan se alt som vises eller spilles av på <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>, inkludert lyd, bilder, betalingsopplysninger, passord og meldinger.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_1">%1$s</xliff:g> kan strømme apper til <xliff:g id="DEVICE_NAME">%3$s</xliff:g> frem til du fjerner tilgangen til denne tillatelsen."</string>
+    <string name="helper_summary_app_streaming" msgid="1872657107404139828">"<xliff:g id="APP_NAME">%1$s</xliff:g> ber om tillatelse til å strømme apper og systemfunksjoner fra <xliff:g id="DEVICE_TYPE">%3$s</xliff:g> på vegne av <xliff:g id="DEVICE_NAME">%2$s</xliff:g>"</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4782923323932440751">"Vil du gi &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; tilgang til denne informasjonen fra <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>?"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
     <string name="helper_summary_computer" msgid="2298803016482139668">"<xliff:g id="APP_NAME">%1$s</xliff:g> ber om tilgang til bilder, medieinnhold og varsler fra <xliff:g id="DEVICE_NAME">%2$s</xliff:g> på vegne av <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>"</string>
-    <string name="title_nearby_device_streaming" msgid="4295322493408411976">"Vil du la &lt;strong&gt;<xliff:g id="DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt; strømme apper og systemfunksjoner fra <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> til &lt;strong&gt;<xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>&lt;/strong&gt;?"</string>
-    <string name="summary_nearby_device_streaming" msgid="962267343109051648">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> får tilgang til alt som vises eller spilles av på <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>, inkludert lyd, bilder, betalingsopplysninger, passord og meldinger.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_1">%1$s</xliff:g> får muligheten til å strømme apper og systemfunksjoner til <xliff:g id="DEVICE_NAME">%3$s</xliff:g> frem til du fjerner tilgangen til denne tillatelsen."</string>
-    <string name="helper_summary_nearby_device_streaming" msgid="8509848562931818793">"<xliff:g id="APP_NAME">%1$s</xliff:g> ber om tillatelse til å strømme apper og andre systemfunksjoner mellom enhetene dine på vegne av <xliff:g id="DEVICE_NAME">%2$s</xliff:g>"</string>
+    <string name="title_nearby_device_streaming" msgid="2727103756701741359">"Vil du la &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; strømme apper fra <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> til &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;?"</string>
+    <string name="summary_nearby_device_streaming" msgid="70434958004946884">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> kan se som vises eller spilles av på <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>, inkludert lyd, bilder, passord og meldinger.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_2">%1$s</xliff:g> kan strømme apper til <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> frem til du fjerner tilgangen til denne tillatelsen."</string>
+    <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"<xliff:g id="APP_NAME">%1$s</xliff:g> ber om tillatelse til å strømme apper fra <xliff:g id="DEVICE_TYPE">%3$s</xliff:g> på vegne av <xliff:g id="DEVICE_NAME">%2$s</xliff:g>"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"enhet"</string>
     <string name="summary_generic" msgid="1761976003668044801">"Denne appen kan synkronisere informasjon som navnet til noen som ringer, mellom telefonen og den valgte enheten"</string>
     <string name="consent_yes" msgid="8344487259618762872">"Tillat"</string>
diff --git a/packages/CompanionDeviceManager/res/values-ne/strings.xml b/packages/CompanionDeviceManager/res/values-ne/strings.xml
index 1af4d85..6386057 100644
--- a/packages/CompanionDeviceManager/res/values-ne/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ne/strings.xml
@@ -25,17 +25,17 @@
     <string name="confirmation_title_glasses" msgid="8288346850537727333">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; लाई &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; व्यवस्थापन गर्ने अनुमति दिने हो?"</string>
     <string name="profile_name_glasses" msgid="3506504967216601277">"डिभाइस"</string>
     <string name="summary_glasses" msgid="5469208629679579157">"तपाईंको <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> मा यो एपलाई निम्न अनुमति दिइने छ:"</string>
-    <string name="title_app_streaming" msgid="6845373585257287200">"Allow &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; लाई तपाईंको <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> मा भएका एपहरू &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt; मा स्ट्रिम गर्न दिने हो?"</string>
-    <string name="summary_app_streaming" msgid="1274464413649731829">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> ले तपाईंको <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> मा देखिने वा प्ले गरिने अडियो, फोटो, पासवर्ड र म्यासेजलगायतका सबै कुरा एक्सेस गर्न सक्ने छ।&lt;br/&gt;&lt;br/&gt;तपाईंले यो अनुमति रद्द नगरेसम्म <xliff:g id="APP_NAME_1">%1$s</xliff:g> ले एपहरू <xliff:g id="DEVICE_NAME">%3$s</xliff:g> मा स्ट्रिम गर्न पाइराख्ने छ।"</string>
-    <string name="helper_summary_app_streaming" msgid="1944832605534698562">"<xliff:g id="APP_NAME">%1$s</xliff:g> तपाईंको डिभाइस <xliff:g id="DEVICE_NAME">%2$s</xliff:g> को तर्फबाट तपाईंका कुनै एउटा डिभाइसबाट अर्को डिभाइसमा एप देखाउने तथा स्ट्रिम गर्ने अनुमति माग्दै छ"</string>
+    <string name="title_app_streaming" msgid="1047090167914857893">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; लाई तपाईंको <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> मा भएका एप तथा सिस्टमका सुविधाहरू &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt; मा स्ट्रिम गर्न दिने हो?"</string>
+    <string name="summary_app_streaming" msgid="7990244299655610920">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> ले तपाईंको <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> मा देखिने वा प्ले गरिने अडियो, फोटो, भुक्तानीसम्बन्धी जानकारी, पासवर्ड र म्यासेजलगायतका सबै कुरा एक्सेस गर्न सक्ने छ।&lt;br/&gt;&lt;br/&gt;तपाईंले यो अनुमति रद्द नगरेसम्म <xliff:g id="APP_NAME_1">%1$s</xliff:g> ले एपहरू <xliff:g id="DEVICE_NAME">%3$s</xliff:g> मा स्ट्रिम गर्न पाइराख्ने छ।"</string>
+    <string name="helper_summary_app_streaming" msgid="1872657107404139828">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="DEVICE_NAME">%2$s</xliff:g> को तर्फबाट तपाईंको <xliff:g id="DEVICE_TYPE">%3$s</xliff:g> बाट एप र सिस्टमका अन्य सुविधाहरू स्ट्रिम गर्ने अनुमति माग्दै छ"</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4782923323932440751">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; लाई तपाईंको <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> मा भएको यो जानकारी एक्सेस गर्ने अनुमति दिनुहोस्"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
     <string name="helper_summary_computer" msgid="2298803016482139668">"<xliff:g id="APP_NAME">%1$s</xliff:g> तपाईंको डिभाइस <xliff:g id="DEVICE_NAME">%2$s</xliff:g> को तर्फबाट तपाईंको <xliff:g id="DEVICE_TYPE">%3$s</xliff:g> मा भएका फोटो, मिडिया र सूचनाहरू एक्सेस गर्ने अनुमति माग्दै छ"</string>
-    <string name="title_nearby_device_streaming" msgid="4295322493408411976">"&lt;strong&gt;<xliff:g id="DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt; लाई तपाईंको <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> मा भएका एप तथा सिस्टमका सुविधाहरू &lt;strong&gt;<xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>&lt;/strong&gt; मा स्ट्रिम गर्न दिने हो?"</string>
-    <string name="summary_nearby_device_streaming" msgid="962267343109051648">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> ले तपाईंको <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> मा देखिने वा प्ले गरिने अडियो, फोटो, भुक्तानीसम्बन्धी जानकारी, पासवर्ड र म्यासेजलगायतका सबै कुरा एक्सेस गर्न सक्ने छ।&lt;br/&gt;&lt;br/&gt;तपाईंले यो अनुमति रद्द नगरेसम्म <xliff:g id="APP_NAME_1">%1$s</xliff:g> ले एप तथा सिस्टमका सुविधाहरू <xliff:g id="DEVICE_NAME">%3$s</xliff:g> मा स्ट्रिम गर्न पाइराख्ने छ।"</string>
-    <string name="helper_summary_nearby_device_streaming" msgid="8509848562931818793">"<xliff:g id="APP_NAME">%1$s</xliff:g> तपाईंको डिभाइस <xliff:g id="DEVICE_NAME">%2$s</xliff:g> को तर्फबाट तपाईंका कुनै एउटा डिभाइसबाट अर्को डिभाइसमा एप र सिस्टमका अन्य सुविधाहरूमा स्ट्रिम गर्ने अनुमति माग्दै छ"</string>
+    <string name="title_nearby_device_streaming" msgid="2727103756701741359">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; लाई तपाईंको <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> मा भएका एपहरू &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt; मा स्ट्रिम गर्न दिने हो?"</string>
+    <string name="summary_nearby_device_streaming" msgid="70434958004946884">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> ले <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g> मा देखिने वा प्ले गरिने अडियो, फोटो, भुक्तानीसम्बन्धी जानकारी, पासवर्ड र म्यासेजलगायतका सबै कुरा एक्सेस गर्न सक्ने छ।&lt;br/&gt;&lt;br/&gt;तपाईंले यो अनुमति रद्द नगरेसम्म <xliff:g id="APP_NAME_2">%1$s</xliff:g> ले एपहरू <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> मा स्ट्रिम गर्न पाइराख्ने छ।"</string>
+    <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="DEVICE_NAME">%2$s</xliff:g> को तर्फबाट तपाईंको <xliff:g id="DEVICE_TYPE">%3$s</xliff:g> बाट एपहरू स्ट्रिम गर्ने अनुमति माग्दै छ"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"यन्त्र"</string>
     <string name="summary_generic" msgid="1761976003668044801">"यो एपले तपाईंको फोन र तपाईंले छनौट गर्ने डिभाइसका बिचमा कल गर्ने व्यक्तिको नाम जस्ता जानकारी सिंक गर्न सक्ने छ।"</string>
     <string name="consent_yes" msgid="8344487259618762872">"अनुमति दिनुहोस्"</string>
diff --git a/packages/CompanionDeviceManager/res/values-nl/strings.xml b/packages/CompanionDeviceManager/res/values-nl/strings.xml
index ad1cfe0..58c7d4f 100644
--- a/packages/CompanionDeviceManager/res/values-nl/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-nl/strings.xml
@@ -25,17 +25,17 @@
     <string name="confirmation_title_glasses" msgid="8288346850537727333">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; toestaan &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; te beheren?"</string>
     <string name="profile_name_glasses" msgid="3506504967216601277">"apparaat"</string>
     <string name="summary_glasses" msgid="5469208629679579157">"Deze app krijgt toegang tot deze rechten op je <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
-    <string name="title_app_streaming" msgid="6845373585257287200">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; toestaan om apps van je <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> naar &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt; te streamen?"</string>
-    <string name="summary_app_streaming" msgid="1274464413649731829">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> krijgt toegang tot alles wat zichtbaar is of wordt afgespeeld op je <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>, waaronder audio, foto\'s, wachtwoorden en berichten.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_1">%1$s</xliff:g> kan apps naar <xliff:g id="DEVICE_NAME">%3$s</xliff:g> streamen totdat je dit recht verwijdert."</string>
-    <string name="helper_summary_app_streaming" msgid="1944832605534698562">"<xliff:g id="APP_NAME">%1$s</xliff:g> vraagt namens jouw <xliff:g id="DEVICE_NAME">%2$s</xliff:g> toestemming om apps tussen je apparaten weer te geven en te streamen"</string>
+    <string name="title_app_streaming" msgid="1047090167914857893">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; toestaan om apps en systeemfuncties van je <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> naar &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt; te streamen?"</string>
+    <string name="summary_app_streaming" msgid="7990244299655610920">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> krijgt toegang tot alles wat zichtbaar is of wordt afgespeeld op je <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>, waaronder audio, foto\'s, betalingsgegevens, wachtwoorden en berichten.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_1">%1$s</xliff:g> kan apps naar <xliff:g id="DEVICE_NAME">%3$s</xliff:g> streamen totdat je dit recht verwijdert."</string>
+    <string name="helper_summary_app_streaming" msgid="1872657107404139828">"<xliff:g id="APP_NAME">%1$s</xliff:g> vraagt namens <xliff:g id="DEVICE_NAME">%2$s</xliff:g> toestemming om apps en systeemfuncties te streamen vanaf je <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>"</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4782923323932440751">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; toegang geven tot deze informatie op je <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>?"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
     <string name="helper_summary_computer" msgid="2298803016482139668">"<xliff:g id="APP_NAME">%1$s</xliff:g> vraagt namens jouw <xliff:g id="DEVICE_NAME">%2$s</xliff:g> toegang tot de foto\'s, media en meldingen van je <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>"</string>
-    <string name="title_nearby_device_streaming" msgid="4295322493408411976">"&lt;strong&gt;<xliff:g id="DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt; toestaan om apps en systeemfuncties van je <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> naar &lt;strong&gt;<xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>&lt;/strong&gt; te streamen?"</string>
-    <string name="summary_nearby_device_streaming" msgid="962267343109051648">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> krijgt toegang tot alles wat zichtbaar is of wordt afgespeeld op je <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>, waaronder audio, foto\'s, betalingsgegevens, wachtwoorden en berichten.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_1">%1$s</xliff:g> kan apps en systeemfuncties naar <xliff:g id="DEVICE_NAME">%3$s</xliff:g> streamen totdat je dit recht verwijdert."</string>
-    <string name="helper_summary_nearby_device_streaming" msgid="8509848562931818793">"<xliff:g id="APP_NAME">%1$s</xliff:g> vraagt namens jouw <xliff:g id="DEVICE_NAME">%2$s</xliff:g> toestemming om apps en andere systeemfuncties te streamen tussen je apparaten"</string>
+    <string name="title_nearby_device_streaming" msgid="2727103756701741359">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; toestaan om apps van je <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> naar &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt; te streamen?"</string>
+    <string name="summary_nearby_device_streaming" msgid="70434958004946884">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> krijgt toegang tot alles wat zichtbaar is of wordt afgespeeld op <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>, waaronder audio, foto\'s, wachtwoorden en berichten.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_2">%1$s</xliff:g> kan apps naar <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> streamen totdat je dit recht verwijdert."</string>
+    <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"<xliff:g id="APP_NAME">%1$s</xliff:g> vraagt namens <xliff:g id="DEVICE_NAME">%2$s</xliff:g> toestemming om apps te streamen vanaf je <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"apparaat"</string>
     <string name="summary_generic" msgid="1761976003668044801">"Deze app kan informatie, zoals de naam van iemand die belt, synchroniseren tussen je telefoon en het gekozen apparaat"</string>
     <string name="consent_yes" msgid="8344487259618762872">"Toestaan"</string>
diff --git a/packages/CompanionDeviceManager/res/values-or/strings.xml b/packages/CompanionDeviceManager/res/values-or/strings.xml
index 58c6476..ffba68f 100644
--- a/packages/CompanionDeviceManager/res/values-or/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-or/strings.xml
@@ -25,17 +25,17 @@
     <string name="confirmation_title_glasses" msgid="8288346850537727333">"&lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;କୁ ପରିଚାଳନା କରିବା ପାଇଁ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;କୁ ଅନୁମତି ଦେବେ?"</string>
     <string name="profile_name_glasses" msgid="3506504967216601277">"ଡିଭାଇସ"</string>
     <string name="summary_glasses" msgid="5469208629679579157">"ଆପଣଙ୍କ <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>ରେ ଏହି ଅନୁମତିଗୁଡ଼ିକୁ ଆକ୍ସେସ କରିବା ପାଇଁ ଏହି ଆପକୁ ଅନୁମତି ଦିଆଯିବ"</string>
-    <string name="title_app_streaming" msgid="6845373585257287200">"ଆପଣଙ୍କ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>ର ଆପ୍ସକୁ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;ରେ ଷ୍ଟ୍ରିମ କରିବା ପାଇଁ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;କୁ ଅନୁମତି ଦେବେ?"</string>
-    <string name="summary_app_streaming" msgid="1274464413649731829">"ଅଡିଓ, ଫଟୋ, ପାସୱାର୍ଡ ଏବଂ ମେସେଜ ସମେତ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>ରେ ଦେଖାଯାଉଥିବା କିମ୍ବା ପ୍ଲେ ହେଉଥିବା ସବୁକିଛିକୁ <xliff:g id="APP_NAME_0">%1$s</xliff:g>ର ଆକ୍ସେସ ରହିବ।&lt;br/&gt;&lt;br/&gt;ଆପଣ ଏହି ଅନୁମତିକୁ ଆକ୍ସେସ କାଢ଼ି ନଦେବା ପର୍ଯ୍ୟନ୍ତ <xliff:g id="APP_NAME_1">%1$s</xliff:g> <xliff:g id="DEVICE_NAME">%3$s</xliff:g>ରେ ଆପ୍ସକୁ ଷ୍ଟ୍ରିମ କରିବା ପାଇଁ ସକ୍ଷମ ହେବ।"</string>
-    <string name="helper_summary_app_streaming" msgid="1944832605534698562">"ଆପଣଙ୍କ ଡିଭାଇସଗୁଡ଼ିକ ମଧ୍ୟରେ ଆପ୍ସକୁ ଡିସପ୍ଲେ ଏବଂ ଷ୍ଟ୍ରିମ କରିବା ପାଇଁ <xliff:g id="APP_NAME">%1$s</xliff:g> ଆପଣଙ୍କର <xliff:g id="DEVICE_NAME">%2$s</xliff:g> ତରଫରୁ ଅନୁମତି ପାଇଁ ଅନୁରୋଧ କରୁଛି"</string>
+    <string name="title_app_streaming" msgid="1047090167914857893">"ଆପଣଙ୍କ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>ର ଆପ୍ସ ଏବଂ ସିଷ୍ଟମ ଫିଚରଗୁଡ଼ିକୁ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;ରେ ଷ୍ଟ୍ରିମ କରିବା ପାଇଁ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;କୁ ଅନୁମତି ଦେବେ?"</string>
+    <string name="summary_app_streaming" msgid="7990244299655610920">"ଅଡିଓ, ଫଟୋ, ପାସୱାର୍ଡ ଏବଂ ମେସେଜ ସମେତ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>ରେ ଦେଖାଯାଉଥିବା କିମ୍ବା ପ୍ଲେ ହେଉଥିବା ସବୁକିଛିକୁ <xliff:g id="APP_NAME_0">%1$s</xliff:g>ର ଆକ୍ସେସ ରହିବ।&lt;br/&gt;&lt;br/&gt;ଆପଣ ଏହି ଅନୁମତିକୁ ଆକ୍ସେସ କାଢ଼ି ନଦେବା ପର୍ଯ୍ୟନ୍ତ <xliff:g id="APP_NAME_1">%1$s</xliff:g> <xliff:g id="DEVICE_NAME">%3$s</xliff:g>ରେ ଆପ୍ସକୁ ଷ୍ଟ୍ରିମ କରିବା ପାଇଁ ସକ୍ଷମ ହେବ।"</string>
+    <string name="helper_summary_app_streaming" msgid="1872657107404139828">"<xliff:g id="APP_NAME">%1$s</xliff:g> ଆପଣଙ୍କ <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>ରୁ ଆପ୍ସ ଏବଂ ସିଷ୍ଟମ ଫିଚରଗୁଡ଼ିକ ଷ୍ଟ୍ରିମ କରିବା ପାଇଁ <xliff:g id="DEVICE_NAME">%2$s</xliff:g> ତରଫରୁ ଅନୁମତି ଅନୁରୋଧ କରୁଛି"</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4782923323932440751">"ଆପଣଙ୍କ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>ରୁ ଏହି ସୂଚନାକୁ ଆକ୍ସେସ କରିବା ପାଇଁ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;କୁ ଅନୁମତି ଦିଅନ୍ତୁ"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
     <string name="helper_summary_computer" msgid="2298803016482139668">"ଆପଣଙ୍କ <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>ର ଫଟୋ, ମିଡିଆ ଏବଂ ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକୁ ଆକ୍ସେସ କରିବା ପାଇଁ <xliff:g id="APP_NAME">%1$s</xliff:g> ଆପଣଙ୍କର <xliff:g id="DEVICE_NAME">%2$s</xliff:g> ତରଫରୁ ଅନୁମତି ପାଇଁ ଅନୁରୋଧ କରୁଛି"</string>
-    <string name="title_nearby_device_streaming" msgid="4295322493408411976">"ଆପଣଙ୍କ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>ର ଆପ୍ସ ଏବଂ ସିଷ୍ଟମ ଫିଚରଗୁଡ଼ିକୁ &lt;strong&gt;<xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>&lt;/strong&gt;ରେ ଷ୍ଟ୍ରିମ କରିବା ପାଇଁ &lt;strong&gt;<xliff:g id="DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt;କୁ ଅନୁମତି ଦେବେ?"</string>
-    <string name="summary_nearby_device_streaming" msgid="962267343109051648">"ଅଡିଓ, ଫଟୋ, ପେମେଣ୍ଟ ସୂଚନା, ପାସୱାର୍ଡ ଏବଂ ମେସେଜ ସମେତ ଆପଣଙ୍କ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>ରେ ଦେଖାଯାଉଥିବା କିମ୍ବା ପ୍ଲେ ହେଉଥିବା ସବୁକିଛିକୁ <xliff:g id="APP_NAME_0">%1$s</xliff:g>ର ଆକ୍ସେସ ରହିବ।&lt;br/&gt;&lt;br/&gt;ଆପଣ ଏହି ଅନୁମତିକୁ ଆକ୍ସେସ କାଢ଼ି ନଦେବା ପର୍ଯ୍ୟନ୍ତ <xliff:g id="APP_NAME_1">%1$s</xliff:g> <xliff:g id="DEVICE_NAME">%3$s</xliff:g>ରେ ଆପ୍ସ ଏବଂ ସିଷ୍ଟମ ଫିଚରଗୁଡ଼ିକୁ ଷ୍ଟ୍ରିମ କରିବା ପାଇଁ ସକ୍ଷମ ହେବ।"</string>
-    <string name="helper_summary_nearby_device_streaming" msgid="8509848562931818793">"ଆପଣଙ୍କ ଡିଭାଇସଗୁଡ଼ିକ ମଧ୍ୟରେ ଆପ୍ସ ଏବଂ ଅନ୍ୟ ସିଷ୍ଟମ ଫିଚରଗୁଡ଼ିକୁ ଷ୍ଟ୍ରିମ କରିବା ପାଇଁ <xliff:g id="APP_NAME">%1$s</xliff:g> ଆପଣଙ୍କର <xliff:g id="DEVICE_NAME">%2$s</xliff:g> ତରଫରୁ ଅନୁମତି ପାଇଁ ଅନୁରୋଧ କରୁଛି"</string>
+    <string name="title_nearby_device_streaming" msgid="2727103756701741359">"ଆପଣଙ୍କ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>ର ଆପ୍ସକୁ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;ରେ ଷ୍ଟ୍ରିମ କରିବା ପାଇଁ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;କୁ ଅନୁମତି ଦେବେ?"</string>
+    <string name="summary_nearby_device_streaming" msgid="70434958004946884">"ଅଡିଓ, ଫଟୋ, ପାସୱାର୍ଡ ଏବଂ ମେସେଜ ସମେତ <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>ରେ ଦେଖାଯାଉଥିବା କିମ୍ବା ପ୍ଲେ ହେଉଥିବା ସବୁକିଛିକୁ <xliff:g id="APP_NAME_0">%1$s</xliff:g>ର ଆକ୍ସେସ ରହିବ।&lt;br/&gt;&lt;br/&gt;ଆପଣ ଏହି ଅନୁମତିକୁ ଆକ୍ସେସ କାଢ଼ି ନଦେବା ପର୍ଯ୍ୟନ୍ତ <xliff:g id="APP_NAME_2">%1$s</xliff:g> <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g>ରେ ଆପ୍ସକୁ ଷ୍ଟ୍ରିମ କରିବା ପାଇଁ ସକ୍ଷମ ହେବ।"</string>
+    <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"<xliff:g id="APP_NAME">%1$s</xliff:g> ଆପଣଙ୍କ <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>ରୁ ଆପ୍ସ ଷ୍ଟ୍ରିମ କରିବା ପାଇଁ <xliff:g id="DEVICE_NAME">%2$s</xliff:g> ତରଫରୁ ଅନୁମତି ଅନୁରୋଧ କରୁଛି"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"ଡିଭାଇସ୍"</string>
     <string name="summary_generic" msgid="1761976003668044801">"ଆପଣଙ୍କ ଫୋନ ଏବଂ ବଛାଯାଇଥିବା ଡିଭାଇସ ମଧ୍ୟରେ, କଲ କରୁଥିବା ଯେ କୌଣସି ବ୍ୟକ୍ତିଙ୍କ ନାମ ପରି ସୂଚନା ସିଙ୍କ କରିବାକୁ ଏହି ଆପ ସକ୍ଷମ ହେବ"</string>
     <string name="consent_yes" msgid="8344487259618762872">"ଅନୁମତି ଦିଅନ୍ତୁ"</string>
diff --git a/packages/CompanionDeviceManager/res/values-pa/strings.xml b/packages/CompanionDeviceManager/res/values-pa/strings.xml
index d80c667..463a02b 100644
--- a/packages/CompanionDeviceManager/res/values-pa/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-pa/strings.xml
@@ -25,17 +25,17 @@
     <string name="confirmation_title_glasses" msgid="8288346850537727333">"ਕੀ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ਨੂੰ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ਦਾ ਪ੍ਰਬੰਧਨ ਕਰਨ ਦੀ ਆਗਿਆ ਦੇਣੀ ਹੈ?"</string>
     <string name="profile_name_glasses" msgid="3506504967216601277">"ਡੀਵਾਈਸ"</string>
     <string name="summary_glasses" msgid="5469208629679579157">"ਇਸ ਐਪ ਨੂੰ ਤੁਹਾਡੇ <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> \'ਤੇ ਇਨ੍ਹਾਂ ਇਜਾਜ਼ਤਾਂ ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਦੀ ਆਗਿਆ ਹੋਵੇਗੀ"</string>
-    <string name="title_app_streaming" msgid="6845373585257287200">"ਕੀ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ਨੂੰ ਤੁਹਾਡੇ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>ਦੀਆਂ ਐਪਾਂ ਨੂੰ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt; \'ਤੇ ਸਟ੍ਰੀਮ ਕਰਨ ਦੀ ਆਗਿਆ ਦੇਣੀ ਹੈ?"</string>
-    <string name="summary_app_streaming" msgid="1274464413649731829">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> ਕੋਲ ਆਡੀਓ, ਫ਼ੋਟੋਆਂ, ਪਾਸਵਰਡਾਂ ਅਤੇ ਸੁਨੇਹਿਆਂ ਸਮੇਤ, <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> \'ਤੇ ਦਿਖਾਈ ਦੇਣ ਵਾਲੀ ਜਾਂ ਚਲਾਈ ਜਾਣ ਵਾਲੀ ਕਿਸੇ ਵੀ ਚੀਜ਼ ਤੱਕ ਪਹੁੰਚ ਹੋਵੇਗੀ।&lt;br/&gt;&lt;br/&gt;ਜਦੋਂ ਤੱਕ ਤੁਸੀਂ ਇਸ ਇਜਾਜ਼ਤ ਤੱਕ ਪਹੁੰਚ ਨੂੰ ਹਟਾ ਨਹੀਂ ਦਿੰਦੇ, ਉਦੋਂ ਤੱਕ <xliff:g id="APP_NAME_1">%1$s</xliff:g>, <xliff:g id="DEVICE_NAME">%3$s</xliff:g> \'ਤੇ ਐਪਾਂ ਨੂੰ ਸਟ੍ਰੀਮ ਕਰ ਸਕੇਗੀ।"</string>
-    <string name="helper_summary_app_streaming" msgid="1944832605534698562">"<xliff:g id="APP_NAME">%1$s</xliff:g> ਤੁਹਾਡੇ <xliff:g id="DEVICE_NAME">%2$s</xliff:g> ਦੀ ਤਰਫ਼ੋਂ ਤੁਹਾਡੇ ਡੀਵਾਈਸਾਂ ਵਿਚਕਾਰ ਐਪਾਂ ਨੂੰ ਦਿਖਾਉਣ ਅਤੇ ਸਟ੍ਰੀਮ ਕਰਨ ਦੀ ਇਜਾਜ਼ਤ ਮੰਗ ਰਹੀ ਹੈ"</string>
+    <string name="title_app_streaming" msgid="1047090167914857893">"ਕੀ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ਨੂੰ ਤੁਹਾਡੇ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> ਦੀਆਂ ਐਪਾਂ ਨੂੰ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt; \'ਤੇ ਸਟ੍ਰੀਮ ਕਰਨ ਅਤੇ ਸਿਸਟਮ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਦੀ ਵਰਤੋਂ ਕਰਨ ਦੀ ਆਗਿਆ ਦੇਣੀ ਹੈ?"</string>
+    <string name="summary_app_streaming" msgid="7990244299655610920">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> ਕੋਲ ਆਡੀਓ, ਫ਼ੋਟੋਆਂ, ਪਾਸਵਰਡਾਂ ਅਤੇ ਸੁਨੇਹਿਆਂ ਸਮੇਤ ਤੁਹਾਡੇ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> \'ਤੇ ਦਿਖਾਈ ਦੇਣ ਵਾਲੀ ਜਾਂ ਚਲਾਈ ਜਾਣ ਵਾਲੀ ਕਿਸੇ ਵੀ ਚੀਜ਼ ਤੱਕ ਪਹੁੰਚ ਹੋਵੇਗੀ।&lt;br/&gt;&lt;br/&gt;ਜਦੋਂ ਤੱਕ ਤੁਸੀਂ ਇਸ ਇਜਾਜ਼ਤ ਤੱਕ ਪਹੁੰਚ ਨੂੰ ਹਟਾ ਨਹੀਂ ਦਿੰਦੇ, ਉਦੋਂ ਤੱਕ <xliff:g id="APP_NAME_1">%1$s</xliff:g>, <xliff:g id="DEVICE_NAME">%3$s</xliff:g> \'ਤੇ ਐਪਾਂ ਨੂੰ ਸਟ੍ਰੀਮ ਕਰ ਸਕੇਗੀ।"</string>
+    <string name="helper_summary_app_streaming" msgid="1872657107404139828">"<xliff:g id="APP_NAME">%1$s</xliff:g>, <xliff:g id="DEVICE_NAME">%2$s</xliff:g> ਦੀ ਤਰਫ਼ੋਂ ਤੁਹਾਡੇ <xliff:g id="DEVICE_TYPE">%3$s</xliff:g> ਤੋਂ ਐਪਾਂ ਅਤੇ ਹੋਰ ਸਿਸਟਮ ਸੰਬੰਧੀ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਨੂੰ ਸਟ੍ਰੀਮ ਕਰਨ ਦੀ ਇਜਾਜ਼ਤ ਮੰਗ ਰਹੀ ਹੈ"</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4782923323932440751">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ਨੂੰ ਤੁਹਾਡੇ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> ਤੋਂ ਇਸ ਜਾਣਕਾਰੀ ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਦੀ ਆਗਿਆ ਦਿਓ"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
     <string name="helper_summary_computer" msgid="2298803016482139668">"<xliff:g id="APP_NAME">%1$s</xliff:g> ਤੁਹਾਡੇ <xliff:g id="DEVICE_NAME">%2$s</xliff:g> ਦੀ ਤਰਫ਼ੋਂ ਤੁਹਾਡੇ <xliff:g id="DEVICE_TYPE">%3$s</xliff:g> ਦੀਆਂ ਫ਼ੋਟੋਆਂ, ਮੀਡੀਆ ਅਤੇ ਸੂਚਨਾਵਾਂ ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਦੀ ਇਜਾਜ਼ਤ ਮੰਗ ਰਹੀ ਹੈ"</string>
-    <string name="title_nearby_device_streaming" msgid="4295322493408411976">"ਕੀ &lt;strong&gt;<xliff:g id="DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt; ਨੂੰ ਤੁਹਾਡੇ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> ਦੀਆਂ ਐਪਾਂ ਨੂੰ &lt;strong&gt;<xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>&lt;/strong&gt; \'ਤੇ ਸਟ੍ਰੀਮ ਕਰਨ ਅਤੇ ਸਿਸਟਮ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਦੀ ਵਰਤੋਂ ਕਰਨ ਦੀ ਆਗਿਆ ਦੇਣੀ ਹੈ?"</string>
-    <string name="summary_nearby_device_streaming" msgid="962267343109051648">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> ਕੋਲ ਆਡੀਓ, ਫ਼ੋਟੋਆਂ, ਪਾਸਵਰਡਾਂ ਅਤੇ ਸੁਨੇਹਿਆਂ ਸਮੇਤ ਤੁਹਾਡੇ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> \'ਤੇ ਦਿਖਾਈ ਦੇਣ ਵਾਲੀ ਜਾਂ ਚਲਾਈ ਜਾਣ ਵਾਲੀ ਕਿਸੇ ਵੀ ਚੀਜ਼ ਤੱਕ ਪਹੁੰਚ ਹੋਵੇਗੀ।&lt;br/&gt;&lt;br/&gt;ਜਦੋਂ ਤੱਕ ਤੁਸੀਂ ਇਸ ਇਜਾਜ਼ਤ ਤੱਕ ਪਹੁੰਚ ਨੂੰ ਹਟਾ ਨਹੀਂ ਦਿੰਦੇ, ਉਦੋਂ ਤੱਕ <xliff:g id="APP_NAME_1">%1$s</xliff:g>, <xliff:g id="DEVICE_NAME">%3$s</xliff:g> \'ਤੇ ਐਪਾਂ ਅਤੇ ਸਿਸਟਮ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਨੂੰ ਸਟ੍ਰੀਮ ਕਰ ਸਕੇਗੀ।"</string>
-    <string name="helper_summary_nearby_device_streaming" msgid="8509848562931818793">"<xliff:g id="APP_NAME">%1$s</xliff:g> ਤੁਹਾਡੇ <xliff:g id="DEVICE_NAME">%2$s</xliff:g> ਦੀ ਤਰਫ਼ੋਂ ਤੁਹਾਡੇ ਡੀਵਾਈਸਾਂ ਵਿਚਕਾਰ ਐਪਾਂ ਅਤੇ ਹੋਰ ਸਿਸਟਮ ਸੰਬੰਧੀ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਨੂੰ ਸਟ੍ਰੀਮ ਕਰਨ ਦੀ ਇਜਾਜ਼ਤ ਮੰਗ ਰਹੀ ਹੈ"</string>
+    <string name="title_nearby_device_streaming" msgid="2727103756701741359">"ਕੀ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ਨੂੰ ਤੁਹਾਡੇ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>ਦੀਆਂ ਐਪਾਂ ਨੂੰ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt; \'ਤੇ ਸਟ੍ਰੀਮ ਕਰਨ ਦੀ ਆਗਿਆ ਦੇਣੀ ਹੈ?"</string>
+    <string name="summary_nearby_device_streaming" msgid="70434958004946884">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> ਕੋਲ ਆਡੀਓ, ਫ਼ੋਟੋਆਂ, ਭੁਗਤਾਨ ਜਾਣਕਾਰੀ, ਪਾਸਵਰਡਾਂ ਅਤੇ ਸੁਨੇਹਿਆਂ ਸਮੇਤ, <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g> \'ਤੇ ਦਿਖਾਈ ਦੇਣ ਵਾਲੀ ਜਾਂ ਚਲਾਈ ਜਾਣ ਵਾਲੀ ਕਿਸੇ ਵੀ ਚੀਜ਼ ਤੱਕ ਪਹੁੰਚ ਹੋਵੇਗੀ।&lt;br/&gt;&lt;br/&gt;ਜਦੋਂ ਤੱਕ ਤੁਸੀਂ ਇਸ ਇਜਾਜ਼ਤ ਤੱਕ ਪਹੁੰਚ ਨੂੰ ਹਟਾ ਨਹੀਂ ਦਿੰਦੇ, ਉਦੋਂ ਤੱਕ <xliff:g id="APP_NAME_2">%1$s</xliff:g>, <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> \'ਤੇ ਐਪਾਂ ਨੂੰ ਸਟ੍ਰੀਮ ਕਰ ਸਕੇਗੀ।"</string>
+    <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"<xliff:g id="APP_NAME">%1$s</xliff:g>, <xliff:g id="DEVICE_NAME">%2$s</xliff:g> ਦੀ ਤਰਫ਼ੋਂ ਤੁਹਾਡੇ <xliff:g id="DEVICE_TYPE">%3$s</xliff:g> ਤੋਂ ਐਪਾਂ ਨੂੰ ਸਟ੍ਰੀਮ ਕਰਨ ਦੀ ਇਜਾਜ਼ਤ ਮੰਗ ਰਹੀ ਹੈ"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"ਡੀਵਾਈਸ"</string>
     <string name="summary_generic" msgid="1761976003668044801">"ਇਹ ਐਪ ਤੁਹਾਡੇ ਫ਼ੋਨ ਅਤੇ ਚੁਣੇ ਗਏ ਡੀਵਾਈਸ ਵਿਚਕਾਰ ਕਾਲਰ ਦੇ ਨਾਮ ਵਰਗੀ ਜਾਣਕਾਰੀ ਨੂੰ ਸਿੰਕ ਕਰ ਸਕੇਗੀ"</string>
     <string name="consent_yes" msgid="8344487259618762872">"ਆਗਿਆ ਦਿਓ"</string>
diff --git a/packages/CompanionDeviceManager/res/values-pl/strings.xml b/packages/CompanionDeviceManager/res/values-pl/strings.xml
index 42a05b4..dc7977d 100644
--- a/packages/CompanionDeviceManager/res/values-pl/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-pl/strings.xml
@@ -25,17 +25,17 @@
     <string name="confirmation_title_glasses" msgid="8288346850537727333">"Zezwolić na dostęp aplikacji &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; do urządzenia &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
     <string name="profile_name_glasses" msgid="3506504967216601277">"urządzenie"</string>
     <string name="summary_glasses" msgid="5469208629679579157">"Aplikacja będzie miała dostęp do tych uprawnień na Twoim urządzeniu (<xliff:g id="DEVICE_TYPE">%1$s</xliff:g>)"</string>
-    <string name="title_app_streaming" msgid="6845373585257287200">"Zezwolić aplikacji &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; na strumieniowanie aplikacji na <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> na urządzenie &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;?"</string>
-    <string name="summary_app_streaming" msgid="1274464413649731829">"Aplikacja <xliff:g id="APP_NAME_0">%1$s</xliff:g> będzie miała dostęp do wszystkiego, co jest widoczne i odtwarzane na <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>, w tym do dźwięku, zdjęć, haseł i wiadomości.&lt;br/&gt;&lt;br/&gt;Aplikacja <xliff:g id="APP_NAME_1">%1$s</xliff:g> będzie mogła strumieniować aplikacje na urządzenie <xliff:g id="DEVICE_NAME">%3$s</xliff:g>, dopóki nie usuniesz dostępu do tego uprawnienia."</string>
-    <string name="helper_summary_app_streaming" msgid="1944832605534698562">"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 pozwolenie na wyświetlanie i strumieniowanie aplikacji między Twoimi urządzeniami"</string>
+    <string name="title_app_streaming" msgid="1047090167914857893">"Zezwolić aplikacji &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; na strumieniowanie aplikacji i funkcji systemowych na <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> na urządzenie &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;?"</string>
+    <string name="summary_app_streaming" msgid="7990244299655610920">"Aplikacja <xliff:g id="APP_NAME_0">%1$s</xliff:g> będzie miała dostęp do wszystkiego, co jest widoczne i odtwarzane na <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>, w tym do dźwięku, zdjęć, danych do płatności, haseł i wiadomości.&lt;br/&gt;&lt;br/&gt;Aplikacja <xliff:g id="APP_NAME_1">%1$s</xliff:g> będzie mogła strumieniować aplikacje na urządzenie <xliff:g id="DEVICE_NAME">%3$s</xliff:g>, dopóki nie usuniesz dostępu do tego uprawnienia."</string>
+    <string name="helper_summary_app_streaming" msgid="1872657107404139828">"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 pozwolenie na strumieniowanie aplikacji i funkcji systemowych z urządzenia <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>"</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4782923323932440751">"Zezwól aplikacji &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; na dostęp do tych informacji na Twoim <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
     <string name="helper_summary_computer" msgid="2298803016482139668">"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 dotyczące dostępu do zdjęć, multimediów i powiadomień na <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>"</string>
-    <string name="title_nearby_device_streaming" msgid="4295322493408411976">"Zezwolić aplikacji &lt;strong&gt;<xliff:g id="DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt; na strumieniowanie aplikacji i funkcji systemowych na <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> na urządzenie &lt;strong&gt;<xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>&lt;/strong&gt;?"</string>
-    <string name="summary_nearby_device_streaming" msgid="962267343109051648">"Aplikacja <xliff:g id="APP_NAME_0">%1$s</xliff:g> będzie miała dostęp do wszystkiego, co jest widoczne i odtwarzane na <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>, w tym do dźwięku, zdjęć, danych do płatności, haseł i wiadomości.&lt;br/&gt;&lt;br/&gt;Aplikacja <xliff:g id="APP_NAME_1">%1$s</xliff:g> będzie mogła strumieniować aplikacje i funkcje systemowe na urządzenie <xliff:g id="DEVICE_NAME">%3$s</xliff:g>, dopóki nie usuniesz dostępu do tego uprawnienia."</string>
-    <string name="helper_summary_nearby_device_streaming" msgid="8509848562931818793">"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 pozwolenie na strumieniowanie aplikacji i innych funkcji systemowych między Twoimi urządzeniami"</string>
+    <string name="title_nearby_device_streaming" msgid="2727103756701741359">"Zezwolić aplikacji &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; na strumieniowanie aplikacji na <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> na urządzenie &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;?"</string>
+    <string name="summary_nearby_device_streaming" msgid="70434958004946884">"Aplikacja <xliff:g id="APP_NAME_0">%1$s</xliff:g> będzie miała dostęp do wszystkiego, co jest widoczne i odtwarzane na <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>, w tym do dźwięku, zdjęć, haseł i wiadomości.&lt;br/&gt;&lt;br/&gt;Aplikacja <xliff:g id="APP_NAME_2">%1$s</xliff:g> będzie mogła strumieniować aplikacje na urządzenie <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g>, dopóki nie usuniesz dostępu do tego uprawnienia."</string>
+    <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"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 pozwolenie na strumieniowanie aplikacji z urządzenia <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>"</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 imię i nazwisko osoby dzwoniącej między Twoim telefonem i wybranym urządzeniem"</string>
     <string name="consent_yes" msgid="8344487259618762872">"Zezwól"</string>
diff --git a/packages/CompanionDeviceManager/res/values-pt-rBR/strings.xml b/packages/CompanionDeviceManager/res/values-pt-rBR/strings.xml
index 1ef9635..88cf563 100644
--- a/packages/CompanionDeviceManager/res/values-pt-rBR/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-pt-rBR/strings.xml
@@ -25,17 +25,17 @@
     <string name="confirmation_title_glasses" msgid="8288346850537727333">"Permitir que o app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; gerencie o dispositivo &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
     <string name="profile_name_glasses" msgid="3506504967216601277">"dispositivo"</string>
     <string name="summary_glasses" msgid="5469208629679579157">"O app poderá acessar estas permissões no seu <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
-    <string name="title_app_streaming" msgid="6845373585257287200">"Permitir que o app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; faça streaming dos aplicativos do seu <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> para o &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;?"</string>
-    <string name="summary_app_streaming" msgid="1274464413649731829">"O app <xliff:g id="APP_NAME_0">%1$s</xliff:g> terá acesso a tudo que estiver visível ou for aberto no <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>, incluindo áudios, fotos, senhas e mensagens.&lt;br/&gt;&lt;br/&gt;O app <xliff:g id="APP_NAME_1">%1$s</xliff:g> poderá fazer streaming de aplicativos para o <xliff:g id="DEVICE_NAME">%3$s</xliff:g> até que você remova o acesso a essa permissão."</string>
-    <string name="helper_summary_app_streaming" msgid="1944832605534698562">"O app <xliff:g id="APP_NAME">%1$s</xliff:g> está pedindo permissão em nome do seu <xliff:g id="DEVICE_NAME">%2$s</xliff:g> para mostrar e fazer streaming de apps entre seus dispositivos"</string>
+    <string name="title_app_streaming" msgid="1047090167914857893">"Permitir que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; faça streaming dos apps e recursos do sistema do seu <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> para o &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;?"</string>
+    <string name="summary_app_streaming" msgid="7990244299655610920">"O app <xliff:g id="APP_NAME_0">%1$s</xliff:g> terá acesso a tudo que estiver visível ou for aberto no <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>, incluindo áudios, fotos, informações de pagamento, senhas e mensagens.&lt;br/&gt;&lt;br/&gt;O app <xliff:g id="APP_NAME_1">%1$s</xliff:g> poderá fazer streaming de aplicativos para o <xliff:g id="DEVICE_NAME">%3$s</xliff:g> até que você remova o acesso a essa permissão."</string>
+    <string name="helper_summary_app_streaming" msgid="1872657107404139828">"O app <xliff:g id="APP_NAME">%1$s</xliff:g> está pedindo permissão em nome do <xliff:g id="DEVICE_NAME">%2$s</xliff:g> para fazer streaming de apps e recursos do sistema do seu <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>"</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4782923323932440751">"Permitir que o app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; acesse essas informações do seu <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
     <string name="helper_summary_computer" msgid="2298803016482139668">"O app <xliff:g id="APP_NAME">%1$s</xliff:g> está pedindo permissão em nome do seu <xliff:g id="DEVICE_NAME">%2$s</xliff:g> para acessar fotos, mídia e notificações do seu <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>"</string>
-    <string name="title_nearby_device_streaming" msgid="4295322493408411976">"Permitir que &lt;strong&gt;<xliff:g id="DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt; faça streaming dos apps e recursos do sistema do seu <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> para o &lt;strong&gt;<xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>&lt;/strong&gt;?"</string>
-    <string name="summary_nearby_device_streaming" msgid="962267343109051648">"O app <xliff:g id="APP_NAME_0">%1$s</xliff:g> terá acesso a tudo que estiver visível ou for aberto no <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>, incluindo áudios, fotos, informações de pagamento, senhas e mensagens.&lt;br/&gt;&lt;br/&gt;O app <xliff:g id="APP_NAME_1">%1$s</xliff:g> poderá fazer streaming de aplicativos e recursos do sistema para o <xliff:g id="DEVICE_NAME">%3$s</xliff:g> até que você remova o acesso a essa permissão."</string>
-    <string name="helper_summary_nearby_device_streaming" msgid="8509848562931818793">"O app <xliff:g id="APP_NAME">%1$s</xliff:g> está pedindo permissão em nome do seu <xliff:g id="DEVICE_NAME">%2$s</xliff:g> para fazer streaming de aplicativos e outros recursos do sistema entre seus dispositivos"</string>
+    <string name="title_nearby_device_streaming" msgid="2727103756701741359">"Permitir que o app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; faça streaming dos aplicativos do seu <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> para o &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;?"</string>
+    <string name="summary_nearby_device_streaming" msgid="70434958004946884">"O app <xliff:g id="APP_NAME_0">%1$s</xliff:g> terá acesso a tudo que estiver visível ou for aberto no <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>, incluindo áudios, fotos, informações de pagamento, senhas e mensagens.&lt;br/&gt;&lt;br/&gt;O app <xliff:g id="APP_NAME_2">%1$s</xliff:g> poderá fazer streaming de aplicativos para o <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> até que você remova o acesso a essa permissão."</string>
+    <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"O app <xliff:g id="APP_NAME">%1$s</xliff:g> está pedindo permissão em nome do <xliff:g id="DEVICE_NAME">%2$s</xliff:g> para fazer streaming de apps do seu <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"dispositivo"</string>
     <string name="summary_generic" msgid="1761976003668044801">"O app poderá sincronizar informações, como o nome de quem está ligando, entre seu smartphone e o dispositivo escolhido"</string>
     <string name="consent_yes" msgid="8344487259618762872">"Permitir"</string>
diff --git a/packages/CompanionDeviceManager/res/values-pt-rPT/strings.xml b/packages/CompanionDeviceManager/res/values-pt-rPT/strings.xml
index 8a464e3..34034f0 100644
--- a/packages/CompanionDeviceManager/res/values-pt-rPT/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-pt-rPT/strings.xml
@@ -25,17 +25,17 @@
     <string name="confirmation_title_glasses" msgid="8288346850537727333">"Permita que a app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; faça a gestão do dispositivo &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="profile_name_glasses" msgid="3506504967216601277">"dispositivo"</string>
     <string name="summary_glasses" msgid="5469208629679579157">"Esta app vai poder aceder a estas autorizações no seu <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
-    <string name="title_app_streaming" msgid="6845373585257287200">"Permitir que a app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; faça stream das apps do seu <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>para o dispositivo &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;?"</string>
-    <string name="summary_app_streaming" msgid="1274464413649731829">"A app <xliff:g id="APP_NAME_0">%1$s</xliff:g> vai ter acesso a tudo o que seja visível ou reproduzido no dispositivo <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>, incluindo áudio, fotos, palavras-passe e mensagens.&lt;br/&gt;&lt;br/&gt;A app <xliff:g id="APP_NAME_1">%1$s</xliff:g> vai poder fazer stream de apps para o dispositivo <xliff:g id="DEVICE_NAME">%3$s</xliff:g> até remover o acesso a esta autorização."</string>
-    <string name="helper_summary_app_streaming" msgid="1944832605534698562">"A app <xliff:g id="APP_NAME">%1$s</xliff:g> está a pedir autorização em nome do seu dispositivo <xliff:g id="DEVICE_NAME">%2$s</xliff:g> para apresentar e fazer stream de apps entre os seus dispositivos"</string>
+    <string name="title_app_streaming" msgid="1047090167914857893">"Permitir que a app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; faça stream das apps e funcionalidades do sistema do seu <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> para o dispositivo &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;?"</string>
+    <string name="summary_app_streaming" msgid="7990244299655610920">"A app <xliff:g id="APP_NAME_0">%1$s</xliff:g> vai ter acesso a tudo o que seja visível ou reproduzido no seu <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>, incluindo áudio, fotos, informações de pagamento, palavras-passe e mensagens.&lt;br/&gt;&lt;br/&gt;A app <xliff:g id="APP_NAME_1">%1$s</xliff:g> vai poder fazer stream de apps para o dispositivo <xliff:g id="DEVICE_NAME">%3$s</xliff:g> até remover o acesso a esta autorização."</string>
+    <string name="helper_summary_app_streaming" msgid="1872657107404139828">"A app <xliff:g id="APP_NAME">%1$s</xliff:g> está a pedir autorização em nome do dispositivo <xliff:g id="DEVICE_NAME">%2$s</xliff:g> para fazer stream de apps e funcionalidades do sistema a partir do seu <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>"</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4782923323932440751">"Permita que a app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; aceda a estas informações do seu <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
     <string name="helper_summary_computer" msgid="2298803016482139668">"A app <xliff:g id="APP_NAME">%1$s</xliff:g> está a pedir autorização em nome do seu dispositivo <xliff:g id="DEVICE_NAME">%2$s</xliff:g> para aceder às fotos, ao conteúdo multimédia e às notificações do seu <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>"</string>
-    <string name="title_nearby_device_streaming" msgid="4295322493408411976">"Permitir que o dispositivo &lt;strong&gt;<xliff:g id="DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt; faça stream das apps e funcionalidades do sistema do seu <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> para o dispositivo &lt;strong&gt;<xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>&lt;/strong&gt;?"</string>
-    <string name="summary_nearby_device_streaming" msgid="962267343109051648">"A app <xliff:g id="APP_NAME_0">%1$s</xliff:g> vai ter acesso a tudo o que seja visível ou reproduzido no seu <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>, incluindo áudio, fotos, informações de pagamento, palavras-passe e mensagens.&lt;br/&gt;&lt;br/&gt;A app <xliff:g id="APP_NAME_1">%1$s</xliff:g> vai poder fazer stream de apps e funcionalidades do sistema para o dispositivo <xliff:g id="DEVICE_NAME">%3$s</xliff:g> até remover o acesso a esta autorização."</string>
-    <string name="helper_summary_nearby_device_streaming" msgid="8509848562931818793">"A app <xliff:g id="APP_NAME">%1$s</xliff:g> está a pedir autorização em nome do seu dispositivo <xliff:g id="DEVICE_NAME">%2$s</xliff:g> para fazer stream de apps e outras funcionalidades do sistema entre os seus dispositivos"</string>
+    <string name="title_nearby_device_streaming" msgid="2727103756701741359">"Permitir que a app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; faça stream das apps do seu <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> para o dispositivo &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;?"</string>
+    <string name="summary_nearby_device_streaming" msgid="70434958004946884">"A app <xliff:g id="APP_NAME_0">%1$s</xliff:g> vai ter acesso a tudo o que seja visível ou reproduzido no dispositivo <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>, incluindo áudio, fotos, informações de pagamento, palavras-passe e mensagens.&lt;br/&gt;&lt;br/&gt;A app <xliff:g id="APP_NAME_2">%1$s</xliff:g> vai poder fazer stream de apps para o dispositivo <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> até remover o acesso a esta autorização."</string>
+    <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"A app <xliff:g id="APP_NAME">%1$s</xliff:g> está a pedir autorização em nome do dispositivo <xliff:g id="DEVICE_NAME">%2$s</xliff:g> para fazer stream de apps do seu <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"dispositivo"</string>
     <string name="summary_generic" msgid="1761976003668044801">"Esta app vai poder sincronizar informações, como o nome do autor de uma chamada, entre o telemóvel e o dispositivo escolhido"</string>
     <string name="consent_yes" msgid="8344487259618762872">"Permitir"</string>
diff --git a/packages/CompanionDeviceManager/res/values-pt/strings.xml b/packages/CompanionDeviceManager/res/values-pt/strings.xml
index 1ef9635..88cf563 100644
--- a/packages/CompanionDeviceManager/res/values-pt/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-pt/strings.xml
@@ -25,17 +25,17 @@
     <string name="confirmation_title_glasses" msgid="8288346850537727333">"Permitir que o app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; gerencie o dispositivo &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
     <string name="profile_name_glasses" msgid="3506504967216601277">"dispositivo"</string>
     <string name="summary_glasses" msgid="5469208629679579157">"O app poderá acessar estas permissões no seu <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
-    <string name="title_app_streaming" msgid="6845373585257287200">"Permitir que o app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; faça streaming dos aplicativos do seu <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> para o &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;?"</string>
-    <string name="summary_app_streaming" msgid="1274464413649731829">"O app <xliff:g id="APP_NAME_0">%1$s</xliff:g> terá acesso a tudo que estiver visível ou for aberto no <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>, incluindo áudios, fotos, senhas e mensagens.&lt;br/&gt;&lt;br/&gt;O app <xliff:g id="APP_NAME_1">%1$s</xliff:g> poderá fazer streaming de aplicativos para o <xliff:g id="DEVICE_NAME">%3$s</xliff:g> até que você remova o acesso a essa permissão."</string>
-    <string name="helper_summary_app_streaming" msgid="1944832605534698562">"O app <xliff:g id="APP_NAME">%1$s</xliff:g> está pedindo permissão em nome do seu <xliff:g id="DEVICE_NAME">%2$s</xliff:g> para mostrar e fazer streaming de apps entre seus dispositivos"</string>
+    <string name="title_app_streaming" msgid="1047090167914857893">"Permitir que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; faça streaming dos apps e recursos do sistema do seu <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> para o &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;?"</string>
+    <string name="summary_app_streaming" msgid="7990244299655610920">"O app <xliff:g id="APP_NAME_0">%1$s</xliff:g> terá acesso a tudo que estiver visível ou for aberto no <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>, incluindo áudios, fotos, informações de pagamento, senhas e mensagens.&lt;br/&gt;&lt;br/&gt;O app <xliff:g id="APP_NAME_1">%1$s</xliff:g> poderá fazer streaming de aplicativos para o <xliff:g id="DEVICE_NAME">%3$s</xliff:g> até que você remova o acesso a essa permissão."</string>
+    <string name="helper_summary_app_streaming" msgid="1872657107404139828">"O app <xliff:g id="APP_NAME">%1$s</xliff:g> está pedindo permissão em nome do <xliff:g id="DEVICE_NAME">%2$s</xliff:g> para fazer streaming de apps e recursos do sistema do seu <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>"</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4782923323932440751">"Permitir que o app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; acesse essas informações do seu <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
     <string name="helper_summary_computer" msgid="2298803016482139668">"O app <xliff:g id="APP_NAME">%1$s</xliff:g> está pedindo permissão em nome do seu <xliff:g id="DEVICE_NAME">%2$s</xliff:g> para acessar fotos, mídia e notificações do seu <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>"</string>
-    <string name="title_nearby_device_streaming" msgid="4295322493408411976">"Permitir que &lt;strong&gt;<xliff:g id="DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt; faça streaming dos apps e recursos do sistema do seu <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> para o &lt;strong&gt;<xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>&lt;/strong&gt;?"</string>
-    <string name="summary_nearby_device_streaming" msgid="962267343109051648">"O app <xliff:g id="APP_NAME_0">%1$s</xliff:g> terá acesso a tudo que estiver visível ou for aberto no <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>, incluindo áudios, fotos, informações de pagamento, senhas e mensagens.&lt;br/&gt;&lt;br/&gt;O app <xliff:g id="APP_NAME_1">%1$s</xliff:g> poderá fazer streaming de aplicativos e recursos do sistema para o <xliff:g id="DEVICE_NAME">%3$s</xliff:g> até que você remova o acesso a essa permissão."</string>
-    <string name="helper_summary_nearby_device_streaming" msgid="8509848562931818793">"O app <xliff:g id="APP_NAME">%1$s</xliff:g> está pedindo permissão em nome do seu <xliff:g id="DEVICE_NAME">%2$s</xliff:g> para fazer streaming de aplicativos e outros recursos do sistema entre seus dispositivos"</string>
+    <string name="title_nearby_device_streaming" msgid="2727103756701741359">"Permitir que o app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; faça streaming dos aplicativos do seu <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> para o &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;?"</string>
+    <string name="summary_nearby_device_streaming" msgid="70434958004946884">"O app <xliff:g id="APP_NAME_0">%1$s</xliff:g> terá acesso a tudo que estiver visível ou for aberto no <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>, incluindo áudios, fotos, informações de pagamento, senhas e mensagens.&lt;br/&gt;&lt;br/&gt;O app <xliff:g id="APP_NAME_2">%1$s</xliff:g> poderá fazer streaming de aplicativos para o <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> até que você remova o acesso a essa permissão."</string>
+    <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"O app <xliff:g id="APP_NAME">%1$s</xliff:g> está pedindo permissão em nome do <xliff:g id="DEVICE_NAME">%2$s</xliff:g> para fazer streaming de apps do seu <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"dispositivo"</string>
     <string name="summary_generic" msgid="1761976003668044801">"O app poderá sincronizar informações, como o nome de quem está ligando, entre seu smartphone e o dispositivo escolhido"</string>
     <string name="consent_yes" msgid="8344487259618762872">"Permitir"</string>
diff --git a/packages/CompanionDeviceManager/res/values-ro/strings.xml b/packages/CompanionDeviceManager/res/values-ro/strings.xml
index cb0572d..002c552 100644
--- a/packages/CompanionDeviceManager/res/values-ro/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ro/strings.xml
@@ -25,17 +25,17 @@
     <string name="confirmation_title_glasses" msgid="8288346850537727333">"Permiți ca &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; să gestioneze &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
     <string name="profile_name_glasses" msgid="3506504967216601277">"dispozitiv"</string>
     <string name="summary_glasses" msgid="5469208629679579157">"Aplicația va putea să acceseze următoarele permisiuni pe <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
-    <string name="title_app_streaming" msgid="6845373585257287200">"Permiți ca &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; să redea în stream aplicații de pe <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> pe &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;?"</string>
-    <string name="summary_app_streaming" msgid="1274464413649731829">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> va avea acces la tot conținutul vizibil sau redat pe <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>, inclusiv conținut audio, fotografii, parole și mesaje.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_1">%1$s</xliff:g> va putea să redea în stream aplicații pe <xliff:g id="DEVICE_NAME">%3$s</xliff:g> până când elimini accesul la această permisiune."</string>
-    <string name="helper_summary_app_streaming" msgid="1944832605534698562">"<xliff:g id="APP_NAME">%1$s</xliff:g> solicită permisiunea pentru <xliff:g id="DEVICE_NAME">%2$s</xliff:g> de a afișa și a reda în stream aplicații între dispozitive"</string>
+    <string name="title_app_streaming" msgid="1047090167914857893">"Permiți ca &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; să redea în stream aplicații și funcții de sistem de pe <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> pe &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;?"</string>
+    <string name="summary_app_streaming" msgid="7990244299655610920">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> va avea acces la tot conținutul vizibil sau redat pe <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>, inclusiv conținut audio, fotografii, informații de plată, parole și mesaje.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_1">%1$s</xliff:g> va putea să redea în stream aplicații pe <xliff:g id="DEVICE_NAME">%3$s</xliff:g> până când elimini accesul la această permisiune."</string>
+    <string name="helper_summary_app_streaming" msgid="1872657107404139828">"<xliff:g id="APP_NAME">%1$s</xliff:g> solicită permisiunea pentru <xliff:g id="DEVICE_NAME">%2$s</xliff:g> de a reda în stream aplicații și funcții de sistem de pe <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>"</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4782923323932440751">"Permite ca &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; să acceseze aceste informații de pe <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
     <string name="helper_summary_computer" msgid="2298803016482139668">"<xliff:g id="APP_NAME">%1$s</xliff:g> solicită permisiunea pentru <xliff:g id="DEVICE_NAME">%2$s</xliff:g> de a accesa fotografiile, conținutul media și notificările de pe <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>"</string>
-    <string name="title_nearby_device_streaming" msgid="4295322493408411976">"Permiți ca &lt;strong&gt;<xliff:g id="DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt; să redea în stream aplicații și funcții de sistem de pe <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> pe &lt;strong&gt;<xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>&lt;/strong&gt;?"</string>
-    <string name="summary_nearby_device_streaming" msgid="962267343109051648">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> va avea acces la tot conținutul vizibil sau redat pe <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>, inclusiv conținut audio, fotografii, informații de plată, parole și mesaje.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_1">%1$s</xliff:g> va putea să redea în stream aplicații și funcții de sistem pe <xliff:g id="DEVICE_NAME">%3$s</xliff:g> până când elimini accesul la această permisiune."</string>
-    <string name="helper_summary_nearby_device_streaming" msgid="8509848562931818793">"<xliff:g id="APP_NAME">%1$s</xliff:g> solicită permisiunea pentru <xliff:g id="DEVICE_NAME">%2$s</xliff:g> de a reda în stream aplicații și alte funcții de sistem între dispozitive"</string>
+    <string name="title_nearby_device_streaming" msgid="2727103756701741359">"Permiți ca &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; să redea în stream aplicații de pe <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> pe &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;?"</string>
+    <string name="summary_nearby_device_streaming" msgid="70434958004946884">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> va avea acces la tot conținutul vizibil sau redat pe <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>, inclusiv conținut audio, fotografii, informații de plată, parole și mesaje.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_2">%1$s</xliff:g> va putea să redea în stream aplicații pe <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> până când elimini accesul la această permisiune."</string>
+    <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"<xliff:g id="APP_NAME">%1$s</xliff:g> solicită permisiunea pentru <xliff:g id="DEVICE_NAME">%2$s</xliff:g> de a reda în stream aplicații de pe <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"dispozitiv"</string>
     <string name="summary_generic" msgid="1761976003668044801">"Aplicația va putea să sincronizeze informații, cum ar fi numele unui apelant, între telefonul tău și dispozitivul ales"</string>
     <string name="consent_yes" msgid="8344487259618762872">"Permite"</string>
diff --git a/packages/CompanionDeviceManager/res/values-ru/strings.xml b/packages/CompanionDeviceManager/res/values-ru/strings.xml
index f2e0367..6f06a2a 100644
--- a/packages/CompanionDeviceManager/res/values-ru/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ru/strings.xml
@@ -25,17 +25,17 @@
     <string name="confirmation_title_glasses" msgid="8288346850537727333">"Разрешить приложению &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; управлять устройством &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
     <string name="profile_name_glasses" msgid="3506504967216601277">"устройстве"</string>
     <string name="summary_glasses" msgid="5469208629679579157">"Это приложение получит указанные разрешения на вашем устройстве (<xliff:g id="DEVICE_TYPE">%1$s</xliff:g>)."</string>
-    <string name="title_app_streaming" msgid="6845373585257287200">"Разрешить приложению &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; транслировать приложения с вашего устройства (<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>) на устройство &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;?"</string>
-    <string name="summary_app_streaming" msgid="1274464413649731829">"У приложения \"<xliff:g id="APP_NAME_0">%1$s</xliff:g>\" будет доступ ко всему, что показывается или воспроизводится на устройстве (<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>), включая аудиофайлы, фотографии, пароли и сообщения.&lt;br/&gt;&lt;br/&gt;Приложение \"<xliff:g id="APP_NAME_1">%1$s</xliff:g>\" сможет транслировать приложения на устройство \"<xliff:g id="DEVICE_NAME">%3$s</xliff:g>\", пока вы не отзовете разрешение."</string>
-    <string name="helper_summary_app_streaming" msgid="1944832605534698562">"Приложение \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" от имени вашего устройства \"<xliff:g id="DEVICE_NAME">%2$s</xliff:g>\" запрашивает разрешение транслировать приложения между устройствами."</string>
+    <string name="title_app_streaming" msgid="1047090167914857893">"Разрешить устройству &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; транслировать приложения и системные функции с вашего устройства (<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>) на устройство &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;?"</string>
+    <string name="summary_app_streaming" msgid="7990244299655610920">"У приложения \"<xliff:g id="APP_NAME_0">%1$s</xliff:g>\" будет доступ ко всему, что показывается или воспроизводится на устройстве (<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>), включая аудиофайлы, фотографии, платежные данные, пароли и сообщения.&lt;br/&gt;&lt;br/&gt;Приложение \"<xliff:g id="APP_NAME_1">%1$s</xliff:g>\" сможет транслировать приложения на устройство \"<xliff:g id="DEVICE_NAME">%3$s</xliff:g>\", пока вы не отзовете разрешение."</string>
+    <string name="helper_summary_app_streaming" msgid="1872657107404139828">"Приложение \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" от имени вашего устройства \"<xliff:g id="DEVICE_NAME">%2$s</xliff:g>\" запрашивает разрешение транслировать приложения и системные функции с устройства (<xliff:g id="DEVICE_TYPE">%3$s</xliff:g>)."</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4782923323932440751">"Разрешить приложению &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; доступ к этой информации с вашего устройства (<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>)?"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
     <string name="helper_summary_computer" msgid="2298803016482139668">"Приложение \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" от имени вашего устройства \"<xliff:g id="DEVICE_NAME">%2$s</xliff:g>\" запрашивает разрешение на доступ к фотографиям, медиаконтенту и уведомлениям на устройстве (<xliff:g id="DEVICE_TYPE">%3$s</xliff:g>)."</string>
-    <string name="title_nearby_device_streaming" msgid="4295322493408411976">"Разрешить устройству &lt;strong&gt;<xliff:g id="DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt; транслировать приложения и системные функции с вашего устройства (<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>) на устройство &lt;strong&gt;<xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>&lt;/strong&gt;?"</string>
-    <string name="summary_nearby_device_streaming" msgid="962267343109051648">"У приложения \"<xliff:g id="APP_NAME_0">%1$s</xliff:g>\" будет доступ ко всему, что показывается или воспроизводится на вашем устройстве (<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>), включая аудиофайлы, фотографии, платежные данные, пароли и сообщения.&lt;br/&gt;&lt;br/&gt;Приложение \"<xliff:g id="APP_NAME_1">%1$s</xliff:g>\" сможет транслировать приложения и системные функции на устройство \"<xliff:g id="DEVICE_NAME">%3$s</xliff:g>\", пока вы не отзовете разрешение."</string>
-    <string name="helper_summary_nearby_device_streaming" msgid="8509848562931818793">"Приложение \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" от имени вашего устройства \"<xliff:g id="DEVICE_NAME">%2$s</xliff:g>\" запрашивает разрешение транслировать приложения и системные функции между устройствами."</string>
+    <string name="title_nearby_device_streaming" msgid="2727103756701741359">"Разрешить приложению &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; транслировать приложения с вашего устройства (<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>) на устройство &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;?"</string>
+    <string name="summary_nearby_device_streaming" msgid="70434958004946884">"У приложения \"<xliff:g id="APP_NAME_0">%1$s</xliff:g>\" будет доступ ко всему, что показывается или воспроизводится на устройстве \"<xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>\", включая аудиофайлы, фотографии, платежные данные, пароли и сообщения.&lt;br/&gt;&lt;br/&gt;Приложение \"<xliff:g id="APP_NAME_2">%1$s</xliff:g>\" сможет транслировать приложения на устройство \"<xliff:g id="DEVICE_NAME_3">%3$s</xliff:g>\", пока вы не отзовете разрешение."</string>
+    <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"Приложение \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" от имени вашего устройства \"<xliff:g id="DEVICE_NAME">%2$s</xliff:g>\" запрашивает разрешение транслировать приложения с устройства (<xliff:g id="DEVICE_TYPE">%3$s</xliff:g>)."</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"устройство"</string>
     <string name="summary_generic" msgid="1761976003668044801">"Приложение сможет синхронизировать информацию между телефоном и выбранным устройством, например данные из журнала звонков."</string>
     <string name="consent_yes" msgid="8344487259618762872">"Разрешить"</string>
diff --git a/packages/CompanionDeviceManager/res/values-si/strings.xml b/packages/CompanionDeviceManager/res/values-si/strings.xml
index 0b2369a..c4b2966 100644
--- a/packages/CompanionDeviceManager/res/values-si/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-si/strings.xml
@@ -25,17 +25,17 @@
     <string name="confirmation_title_glasses" msgid="8288346850537727333">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; හට &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; කළමනා කිරීමට ඉඩ දෙන්න ද?"</string>
     <string name="profile_name_glasses" msgid="3506504967216601277">"උපාංගය"</string>
     <string name="summary_glasses" msgid="5469208629679579157">"මෙම යෙදුමට ඔබේ <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> මත මෙම අවසර වෙත ප්‍රවේශ වීමට ඉඩ දෙනු ඇත"</string>
-    <string name="title_app_streaming" msgid="6845373585257287200">"ඔබේ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> හි යෙදුම් &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt; වෙත ප්‍රවාහ කිරීමට &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; හට ඉඩ දෙන්න ද?"</string>
-    <string name="summary_app_streaming" msgid="1274464413649731829">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> හට ශ්‍රව්‍ය, ඡායාරූප, මුරපද සහ පණිවිඩ ඇතුළුව <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> හි දෘශ්‍යමාන හෝ වාදනය වන ඕනෑම දෙයකට ප්‍රවේශය ඇත.&lt;br/&gt;&lt;br/&gt;ඔබ මෙම අවසරයට ප්‍රවේශය ඉවත් කරන තෙක් <xliff:g id="APP_NAME_1">%1$s</xliff:g> හට <xliff:g id="DEVICE_NAME">%3$s</xliff:g> වෙත යෙදුම් ප්‍රවාහ කිරීමට හැකි වනු ඇත."</string>
-    <string name="helper_summary_app_streaming" msgid="1944832605534698562">"ඔබේ උපාංග අතර යෙදුම් සංදර්ශනය කිරීමට සහ ප්‍රවාහ කිරීමට <xliff:g id="APP_NAME">%1$s</xliff:g> ඔබේ <xliff:g id="DEVICE_NAME">%2$s</xliff:g> වෙනුවෙන් අවසර ඉල්ලා සිටියි"</string>
+    <string name="title_app_streaming" msgid="1047090167914857893">"ඔබේ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> හි යෙදුම් සහ පද්ධති විශේෂාංග &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt; වෙත ප්‍රවාහ කිරීමට &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; හට ඉඩ දෙන්න ද?"</string>
+    <string name="summary_app_streaming" msgid="7990244299655610920">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> හට ශ්‍රව්‍ය, ඡායාරූප, ගෙවීම් තොරතුරු, මුරපද සහ පණිවිඩ ඇතුළුව ඔබේ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> හි දෘශ්‍යමාන හෝ වාදනය වන ඕනෑම දෙයකට ප්‍රවේශය ඇත.&lt;br/&gt;&lt;br/&gt;ඔබ මෙම අවසරයට ප්‍රවේශය ඉවත් කරන තෙක් <xliff:g id="APP_NAME_1">%1$s</xliff:g> හට <xliff:g id="DEVICE_NAME">%3$s</xliff:g> වෙත යෙදුම් ප්‍රවාහ කිරීමට හැකි වනු ඇත."</string>
+    <string name="helper_summary_app_streaming" msgid="1872657107404139828">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="DEVICE_NAME">%2$s</xliff:g> වෙනුවෙන් ඔබේ <xliff:g id="DEVICE_TYPE">%3$s</xliff:g> වෙතින් යෙදුම් සහ පද්ධති විශේෂාංග ප්‍රවාහ කිරීමට අවසර ඉල්ලා සිටියි"</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4782923323932440751">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; හට ඔබේ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> වෙතින් මෙම තොරතුරු වෙත ප්‍රවේශ වීමට ඉඩ දෙන්න"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
     <string name="helper_summary_computer" msgid="2298803016482139668">"<xliff:g id="APP_NAME">%1$s</xliff:g> ඔබේ <xliff:g id="DEVICE_NAME">%2$s</xliff:g> වෙනුවෙන් ඔබේ <xliff:g id="DEVICE_TYPE">%3$s</xliff:g> හි ඡායාරූප, මාධ්‍ය, සහ දැනුම්දීම් වෙත ප්‍රවේශ වීමට අවසරය ඉල්ලමින් සිටියි"</string>
-    <string name="title_nearby_device_streaming" msgid="4295322493408411976">"ඔබේ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> හි යෙදුම් සහ පද්ධති විශේෂාංග &lt;strong&gt;<xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>&lt;/strong&gt; වෙත ප්‍රවාහ කිරීමට &lt;strong&gt;<xliff:g id="DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt; හට ඉඩ දෙන්න ද?"</string>
-    <string name="summary_nearby_device_streaming" msgid="962267343109051648">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> හට ශ්‍රව්‍ය, ඡායාරූප, ගෙවීම් තොරතුරු, මුරපද සහ පණිවිඩ ඇතුළුව ඔබේ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> හි දෘශ්‍යමාන හෝ වාදනය වන ඕනෑම දෙයකට ප්‍රවේශය ඇත.&lt;br/&gt;&lt;br/&gt;ඔබ මෙම අවසරයට ප්‍රවේශය ඉවත් කරන තෙක් <xliff:g id="APP_NAME_1">%1$s</xliff:g> හට යෙදුම් සහ පද්ධති විශේෂාංග <xliff:g id="DEVICE_NAME">%3$s</xliff:g> වෙත ප්‍රවාහ කිරීමට හැකි වනු ඇත."</string>
-    <string name="helper_summary_nearby_device_streaming" msgid="8509848562931818793">"<xliff:g id="APP_NAME">%1$s</xliff:g> ඔබේ <xliff:g id="DEVICE_NAME">%2$s</xliff:g> වෙනුවෙන් ඔබේ උපාංග අතර යෙදුම් සහ අනෙකුත් පද්ධති විශේෂාංග ප්‍රවාහ කිරීමට අවසර ඉල්ලයි"</string>
+    <string name="title_nearby_device_streaming" msgid="2727103756701741359">"ඔබේ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> හි යෙදුම් &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt; වෙත ප්‍රවාහ කිරීමට &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; හට ඉඩ දෙන්න ද?"</string>
+    <string name="summary_nearby_device_streaming" msgid="70434958004946884">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> හට ශ්‍රව්‍ය, ඡායාරූප, ගෙවීම් තොරතුරු, මුරපද සහ පණිවිඩ ඇතුළුව <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g> හි දෘශ්‍යමාන හෝ වාදනය වන ඕනෑම දෙයකට ප්‍රවේශය ඇත.&lt;br/&gt;&lt;br/&gt;ඔබ මෙම අවසරයට ප්‍රවේශය ඉවත් කරන තෙක් <xliff:g id="APP_NAME_2">%1$s</xliff:g> හට <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> වෙත යෙදුම් ප්‍රවාහ කිරීමට හැකි වනු ඇත."</string>
+    <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="DEVICE_NAME">%2$s</xliff:g> වෙනුවෙන් ඔබේ <xliff:g id="DEVICE_TYPE">%3$s</xliff:g> වෙතින් යෙදුම් ප්‍රවාහ කිරීමට අවසර ඉල්ලා සිටියි"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"උපාංගය"</string>
     <string name="summary_generic" msgid="1761976003668044801">"මෙම යෙදුමට ඔබේ දුරකථනය සහ තෝරා ගත් උපාංගය අතර, අමතන කෙනෙකුගේ නම වැනි, තතු සමමුහුර්ත කිරීමට හැකි වනු ඇත"</string>
     <string name="consent_yes" msgid="8344487259618762872">"ඉඩ දෙන්න"</string>
diff --git a/packages/CompanionDeviceManager/res/values-sk/strings.xml b/packages/CompanionDeviceManager/res/values-sk/strings.xml
index 2819a92..bf96c5c 100644
--- a/packages/CompanionDeviceManager/res/values-sk/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-sk/strings.xml
@@ -25,17 +25,17 @@
     <string name="confirmation_title_glasses" msgid="8288346850537727333">"Chcete povoliť aplikácii &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; spravovať zariadenie &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
     <string name="profile_name_glasses" msgid="3506504967216601277">"zariadenie"</string>
     <string name="summary_glasses" msgid="5469208629679579157">"Táto aplikácia bude mať prístup k týmto povoleniam v zariadení <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
-    <string name="title_app_streaming" msgid="6845373585257287200">"Chcete povoliť aplikácii &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; streamovať aplikácie zo zariadenia <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> do zariadenia &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;?"</string>
-    <string name="summary_app_streaming" msgid="1274464413649731829">"Aplikácia <xliff:g id="APP_NAME_0">%1$s</xliff:g> bude mať prístup k všetkému, čo sa zobrazuje alebo prehráva v zariadení <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> vrátane zvuku, fotiek, hesiel a správ.&lt;br/&gt;&lt;br/&gt;Aplikácia <xliff:g id="APP_NAME_1">%1$s</xliff:g> bude môcť streamovať aplikácie do zariadenia <xliff:g id="DEVICE_NAME">%3$s</xliff:g>, kým prístup k tomuto povoleniu neodstránite."</string>
-    <string name="helper_summary_app_streaming" msgid="1944832605534698562">"Aplikácia <xliff:g id="APP_NAME">%1$s</xliff:g> vyžaduje pre zariadenie <xliff:g id="DEVICE_NAME">%2$s</xliff:g> povolenie zobrazovať a streamovať aplikácie medzi zariadeniami"</string>
+    <string name="title_app_streaming" msgid="1047090167914857893">"Chcete povoliť aplikácii &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; streamovať aplikácie a systémové funkcie zo zariadenia <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> do zariadenia &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;?"</string>
+    <string name="summary_app_streaming" msgid="7990244299655610920">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> bude mať prístup k všetkému, čo sa zobrazuje alebo prehráva v zariadení <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> vrátane zvuku, fotiek, platobných údajov, hesiel a správ.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_1">%1$s</xliff:g> bude môcť streamovať aplikácie do zariadenia <xliff:g id="DEVICE_NAME">%3$s</xliff:g>, kým prístup k tomuto povoleniu neodstránite."</string>
+    <string name="helper_summary_app_streaming" msgid="1872657107404139828">"<xliff:g id="APP_NAME">%1$s</xliff:g> vyžaduje v mene zariadenia <xliff:g id="DEVICE_NAME">%2$s</xliff:g> povolenie streamovať aplikácie a systémové funkcie z vášho zariadenia <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>"</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4782923323932440751">"Povoľte aplikácii &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; prístup k týmto informáciám zo zariadenia <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
     <string name="helper_summary_computer" msgid="2298803016482139668">"Aplikácia <xliff:g id="APP_NAME">%1$s</xliff:g> vyžaduje pre zariadenie <xliff:g id="DEVICE_NAME">%2$s</xliff:g> povolenie na prístup k fotkám, médiám a upozorneniam zariadenia <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>"</string>
-    <string name="title_nearby_device_streaming" msgid="4295322493408411976">"Chcete povoliť zariadeniu &lt;strong&gt;<xliff:g id="DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt; streamovať aplikácie a funkcie systému zo zariadenia <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> do zariadenia &lt;strong&gt;<xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>&lt;/strong&gt;?"</string>
-    <string name="summary_nearby_device_streaming" msgid="962267343109051648">"Aplikácia <xliff:g id="APP_NAME_0">%1$s</xliff:g> bude mať prístup k všetkému, čo sa zobrazuje alebo prehráva v zariadení <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> vrátane zvuku, fotiek, platobných údajov, hesiel a správ.&lt;br/&gt;&lt;br/&gt;Aplikácia <xliff:g id="APP_NAME_1">%1$s</xliff:g> bude môcť streamovať aplikácie a funkcie systému do zariadenia <xliff:g id="DEVICE_NAME">%3$s</xliff:g>, kým prístup k tomuto povoleniu neodstránite."</string>
-    <string name="helper_summary_nearby_device_streaming" msgid="8509848562931818793">"Aplikácia <xliff:g id="APP_NAME">%1$s</xliff:g> vyžaduje pre zariadenie <xliff:g id="DEVICE_NAME">%2$s</xliff:g> povolenie streamovať aplikácie a ďalšie funkcie systému medzi zariadeniami"</string>
+    <string name="title_nearby_device_streaming" msgid="2727103756701741359">"Chcete povoliť aplikácii &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; streamovať aplikácie zo zariadenia <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> do zariadenia &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;?"</string>
+    <string name="summary_nearby_device_streaming" msgid="70434958004946884">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> bude mať prístup k všetkému, čo sa zobrazuje alebo prehráva v zariadení <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g> vrátane zvuku, fotiek, platobných údajov, hesiel a správ.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_2">%1$s</xliff:g> bude môcť streamovať aplikácie do zariadenia <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g>, kým prístup k tomuto povoleniu neodstránite."</string>
+    <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"<xliff:g id="APP_NAME">%1$s</xliff:g> vyžaduje v mene zariadenia <xliff:g id="DEVICE_NAME">%2$s</xliff:g> povolenie streamovať aplikácie z vášho zariadenia <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"zariadenie"</string>
     <string name="summary_generic" msgid="1761976003668044801">"Táto aplikácia bude môcť synchronizovať informácie, napríklad meno volajúceho, medzi telefónom a vybraným zariadením"</string>
     <string name="consent_yes" msgid="8344487259618762872">"Povoliť"</string>
diff --git a/packages/CompanionDeviceManager/res/values-sl/strings.xml b/packages/CompanionDeviceManager/res/values-sl/strings.xml
index 3e4f8db..2c1edcd 100644
--- a/packages/CompanionDeviceManager/res/values-sl/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-sl/strings.xml
@@ -25,17 +25,17 @@
     <string name="confirmation_title_glasses" msgid="8288346850537727333">"Želite aplikaciji &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; dovoliti upravljanje naprave &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
     <string name="profile_name_glasses" msgid="3506504967216601277">"naprava"</string>
     <string name="summary_glasses" msgid="5469208629679579157">"Ta aplikacija bo lahko dostopala do teh dovoljenj v napravi »<xliff:g id="DEVICE_TYPE">%1$s</xliff:g>«."</string>
-    <string name="title_app_streaming" msgid="6845373585257287200">"Ali aplikaciji &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; dovolite, da pretočno predvaja aplikacije naprave »<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>« v napravi &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;?"</string>
-    <string name="summary_app_streaming" msgid="1274464413649731829">"Aplikacija <xliff:g id="APP_NAME_0">%1$s</xliff:g> bo imela dostop do vsega, kar je prikazano ali se predvaja v napravi »<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>«, vključno z zvokom, fotografijami, gesli in sporočili.&lt;br/&gt;&lt;br/&gt;Aplikacija <xliff:g id="APP_NAME_1">%1$s</xliff:g> bo lahko pretočno predvajala aplikacije v napravo »<xliff:g id="DEVICE_NAME">%3$s</xliff:g>«, dokler ne odstranite dostopa do tega dovoljenja."</string>
-    <string name="helper_summary_app_streaming" msgid="1944832605534698562">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> v imenu naprave »<xliff:g id="DEVICE_NAME">%2$s</xliff:g>« zahteva dovoljenje za prikaz in pretočno predvajanje aplikacij v vaših napravah."</string>
+    <string name="title_app_streaming" msgid="1047090167914857893">"Ali aplikaciji &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; dovolite, da pretočno predvaja aplikacije in sistemske funkcije naprave <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> v napravi &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;?"</string>
+    <string name="summary_app_streaming" msgid="7990244299655610920">"Aplikacija <xliff:g id="APP_NAME_0">%1$s</xliff:g> bo imela dostop do vsega, kar je prikazano ali se predvaja v vaši napravi <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>, vključno z zvokom, fotografijami, podatki za plačilo, gesli in sporočili.&lt;br/&gt;&lt;br/&gt;Aplikacija <xliff:g id="APP_NAME_1">%1$s</xliff:g> bo lahko pretočno predvajala aplikacije v napravo <xliff:g id="DEVICE_NAME">%3$s</xliff:g>, dokler ne odstranite dostopa do tega dovoljenja."</string>
+    <string name="helper_summary_app_streaming" msgid="1872657107404139828">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> v imenu naprave <xliff:g id="DEVICE_NAME">%2$s</xliff:g> zahteva dovoljenje za pretočno predvajanje aplikacij in sistemskih funkcij iz naprave <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>"</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4782923323932440751">"Dovolite, da &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; dostopa do teh podatkov v vaši napravi »<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>«."</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
     <string name="helper_summary_computer" msgid="2298803016482139668">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> v imenu naprave »<xliff:g id="DEVICE_NAME">%2$s</xliff:g>« zahteva dovoljenje za dostop do fotografij, predstavnosti in obvestil v napravi »<xliff:g id="DEVICE_TYPE">%3$s</xliff:g>«."</string>
-    <string name="title_nearby_device_streaming" msgid="4295322493408411976">"Ali napravi &lt;strong&gt;<xliff:g id="DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt; dovolite, da pretočno predvaja aplikacije in sistemske funkcije naprave »<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>« v napravi &lt;strong&gt;<xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>&lt;/strong&gt;?"</string>
-    <string name="summary_nearby_device_streaming" msgid="962267343109051648">"Aplikacija <xliff:g id="APP_NAME_0">%1$s</xliff:g> bo imela dostop do vsega, kar je prikazano ali se predvaja v napravi »<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>«, vključno z zvokom, fotografijami, podatki za plačilo, gesli in sporočili.&lt;br/&gt;&lt;br/&gt;Aplikacija <xliff:g id="APP_NAME_1">%1$s</xliff:g> bo lahko pretočno predvajala aplikacije in sistemske funkcije v napravo »<xliff:g id="DEVICE_NAME">%3$s</xliff:g>«, dokler ne odstranite dostopa do tega dovoljenja."</string>
-    <string name="helper_summary_nearby_device_streaming" msgid="8509848562931818793">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> v imenu naprave »<xliff:g id="DEVICE_NAME">%2$s</xliff:g>« zahteva dovoljenje za pretočno predvajanje aplikacij in drugih sistemskih funkcij v vaših napravah."</string>
+    <string name="title_nearby_device_streaming" msgid="2727103756701741359">"Ali aplikaciji &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; dovolite, da pretočno predvaja aplikacije naprave <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> v napravi &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;?"</string>
+    <string name="summary_nearby_device_streaming" msgid="70434958004946884">"Aplikacija <xliff:g id="APP_NAME_0">%1$s</xliff:g> bo imela dostop do vsega, kar je prikazano ali se predvaja v napravi <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>, vključno z zvokom, fotografijami, podatki za plačilo, gesli in sporočili.&lt;br/&gt;&lt;br/&gt;Aplikacija <xliff:g id="APP_NAME_2">%1$s</xliff:g> bo lahko pretočno predvajala aplikacije v napravo <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g>, dokler ne odstranite dostopa do tega dovoljenja."</string>
+    <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> v imenu naprave <xliff:g id="DEVICE_NAME">%2$s</xliff:g> zahteva dovoljenje za pretočno predvajanje aplikacij iz naprave <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"naprava"</string>
     <string name="summary_generic" msgid="1761976003668044801">"Ta aplikacija bo lahko sinhronizirala podatke, na primer ime klicatelja, v telefonu in izbrani napravi."</string>
     <string name="consent_yes" msgid="8344487259618762872">"Dovoli"</string>
diff --git a/packages/CompanionDeviceManager/res/values-sq/strings.xml b/packages/CompanionDeviceManager/res/values-sq/strings.xml
index 9d52281..14acdf0 100644
--- a/packages/CompanionDeviceManager/res/values-sq/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-sq/strings.xml
@@ -25,17 +25,23 @@
     <string name="confirmation_title_glasses" msgid="8288346850537727333">"Të lejohet që &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; të menaxhojë &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
     <string name="profile_name_glasses" msgid="3506504967216601277">"pajisje"</string>
     <string name="summary_glasses" msgid="5469208629679579157">"Këtij aplikacioni do t\'i lejohet qasja te këto leje te <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
-    <string name="title_app_streaming" msgid="6845373585257287200">"Të lejohet që &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; të transmetojë aplikacionet nga <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> te &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;?"</string>
-    <string name="summary_app_streaming" msgid="1274464413649731829">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> do të ketë qasje te çdo gjë që është e dukshme ose që luhet te <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>, duke përfshirë audion, fotografitë, fjalëkalimet dhe mesazhet.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_1">%1$s</xliff:g> do të mund t\'i transmetojë aplikacionet në <xliff:g id="DEVICE_NAME">%3$s</xliff:g> derisa ta heqësh qasjen për këtë leje."</string>
-    <string name="helper_summary_app_streaming" msgid="1944832605534698562">"<xliff:g id="APP_NAME">%1$s</xliff:g> po kërkon leje në emër të <xliff:g id="DEVICE_NAME">%2$s</xliff:g> për të shfaqur dhe transmetuar aplikacionet mes pajisjeve të tua"</string>
+    <!-- no translation found for title_app_streaming (1047090167914857893) -->
+    <skip />
+    <!-- no translation found for summary_app_streaming (7990244299655610920) -->
+    <skip />
+    <!-- no translation found for helper_summary_app_streaming (1872657107404139828) -->
+    <skip />
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4782923323932440751">"Lejo që &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; të ketë qasje në këto informacione te <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
     <string name="helper_summary_computer" msgid="2298803016482139668">"<xliff:g id="APP_NAME">%1$s</xliff:g> po kërkon leje në emër të <xliff:g id="DEVICE_NAME">%2$s</xliff:g> për të marrë qasje te fotografitë, media dhe njoftimet te <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>"</string>
-    <string name="title_nearby_device_streaming" msgid="4295322493408411976">"Të lejohet që &lt;strong&gt;<xliff:g id="DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt; të transmetojë aplikacionet dhe veçoritë e sistemit nga <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> te &lt;strong&gt;<xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>&lt;/strong&gt;?"</string>
-    <string name="summary_nearby_device_streaming" msgid="962267343109051648">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> do të ketë qasje te çdo gjë që është e dukshme ose që luhet te <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>, duke përfshirë audion, fotografitë, informacionet për pagesën, fjalëkalimet dhe mesazhet.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_1">%1$s</xliff:g> do të mund t\'i transmetojë aplikacionet dhe veçoritë e sistemit në <xliff:g id="DEVICE_NAME">%3$s</xliff:g> derisa ta heqësh qasjen për këtë leje."</string>
-    <string name="helper_summary_nearby_device_streaming" msgid="8509848562931818793">"<xliff:g id="APP_NAME">%1$s</xliff:g> po kërkon leje në emër të <xliff:g id="DEVICE_NAME">%2$s</xliff:g> për të transmetuar aplikacione dhe veçori të tjera të sistemit ndërmjet pajisjeve të tua"</string>
+    <!-- no translation found for title_nearby_device_streaming (2727103756701741359) -->
+    <skip />
+    <!-- no translation found for summary_nearby_device_streaming (70434958004946884) -->
+    <skip />
+    <!-- no translation found for helper_summary_nearby_device_streaming (4712712177819370967) -->
+    <skip />
     <string name="profile_name_generic" msgid="6851028682723034988">"pajisja"</string>
     <string name="summary_generic" msgid="1761976003668044801">"Ky aplikacion do të mund të sinkronizojë informacione, si p.sh emrin e dikujt që po telefonon, mes telefonit tënd dhe pajisjes së zgjedhur."</string>
     <string name="consent_yes" msgid="8344487259618762872">"Lejo"</string>
diff --git a/packages/CompanionDeviceManager/res/values-sr/strings.xml b/packages/CompanionDeviceManager/res/values-sr/strings.xml
index 69af8ab..582e832 100644
--- a/packages/CompanionDeviceManager/res/values-sr/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-sr/strings.xml
@@ -25,17 +25,17 @@
     <string name="confirmation_title_glasses" msgid="8288346850537727333">"Желите ли да дозволите да &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; управља уређајем &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
     <string name="profile_name_glasses" msgid="3506504967216601277">"уређај"</string>
     <string name="summary_glasses" msgid="5469208629679579157">"Овој апликацији ће бити дозвољено да приступа овим дозволама на уређају <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
-    <string name="title_app_streaming" msgid="6845373585257287200">"Желите ли да дозволите да &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; стримује апликације уређаја <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> на &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;?"</string>
-    <string name="summary_app_streaming" msgid="1274464413649731829">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> ће имати приступ свему што се види или пушта на уређају <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>, укључујући звук, слике, лозинке и поруке.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_1">%1$s</xliff:g> ће моћи да стримује апликације на <xliff:g id="DEVICE_NAME">%3$s</xliff:g> док не уклоните приступ овој дозволи."</string>
-    <string name="helper_summary_app_streaming" msgid="1944832605534698562">"<xliff:g id="APP_NAME">%1$s</xliff:g> тражи дозволу у име уређаја <xliff:g id="DEVICE_NAME">%2$s</xliff:g> да приказује и стримује апликације између уређаја"</string>
+    <string name="title_app_streaming" msgid="1047090167914857893">"Желите да дозволите да &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; стримује апликације и системске функције уређаја <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> на &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;?"</string>
+    <string name="summary_app_streaming" msgid="7990244299655610920">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> ће имати приступ свему што се види или пушта на уређају <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>, укључујући звук, слике, информације о плаћању, лозинке и поруке.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_1">%1$s</xliff:g> ће моћи да стримује апликације на <xliff:g id="DEVICE_NAME">%3$s</xliff:g> док не уклоните приступ овој дозволи."</string>
+    <string name="helper_summary_app_streaming" msgid="1872657107404139828">"<xliff:g id="APP_NAME">%1$s</xliff:g> тражи дозволу у име уређаја <xliff:g id="DEVICE_NAME">%2$s</xliff:g> да стримује апликације и системске функције са уређаја <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>"</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4782923323932440751">"Дозволите да &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; приступа овим информацијама са уређаја <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
     <string name="helper_summary_computer" msgid="2298803016482139668">"<xliff:g id="APP_NAME">%1$s</xliff:g> тражи дозволу у име уређаја <xliff:g id="DEVICE_NAME">%2$s</xliff:g> да приступа сликама, медијском садржају и обавештењима са уређаја <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>"</string>
-    <string name="title_nearby_device_streaming" msgid="4295322493408411976">"Желите ли да дозволите да &lt;strong&gt;<xliff:g id="DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt; стримује апликације и системске функције уређаја <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> на &lt;strong&gt;<xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>&lt;/strong&gt;?"</string>
-    <string name="summary_nearby_device_streaming" msgid="962267343109051648">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> ће имати приступ свему што се види или пушта на уређају <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>, укључујући звук, слике, информације о плаћању, лозинке и поруке.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_1">%1$s</xliff:g> ће моћи да стримује апликације и системске функције на <xliff:g id="DEVICE_NAME">%3$s</xliff:g> док не уклоните приступ овој дозволи."</string>
-    <string name="helper_summary_nearby_device_streaming" msgid="8509848562931818793">"<xliff:g id="APP_NAME">%1$s</xliff:g> тражи дозволу у име уређаја <xliff:g id="DEVICE_NAME">%2$s</xliff:g> да стримује апликације и друге системске функције између уређаја"</string>
+    <string name="title_nearby_device_streaming" msgid="2727103756701741359">"Желите да дозволите да &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; стримује апликације уређаја <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> на &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;?"</string>
+    <string name="summary_nearby_device_streaming" msgid="70434958004946884">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> ће имати приступ свему што се види или пушта на уређају <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>, укључујући звук, слике, информације о плаћању, лозинке и поруке.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_2">%1$s</xliff:g> ће моћи да стримује апликације на <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> док не уклоните приступ овој дозволи."</string>
+    <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"<xliff:g id="APP_NAME">%1$s</xliff:g> тражи дозволу у име уређаја <xliff:g id="DEVICE_NAME">%2$s</xliff:g> да стримује апликације са уређаја <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"уређај"</string>
     <string name="summary_generic" msgid="1761976003668044801">"Ова апликација ће моћи да синхронизује податке, попут имена особе која упућује позив, између телефона и одабраног уређаја"</string>
     <string name="consent_yes" msgid="8344487259618762872">"Дозволи"</string>
diff --git a/packages/CompanionDeviceManager/res/values-sv/strings.xml b/packages/CompanionDeviceManager/res/values-sv/strings.xml
index 6ec27d2..cb7b709 100644
--- a/packages/CompanionDeviceManager/res/values-sv/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-sv/strings.xml
@@ -25,17 +25,17 @@
     <string name="confirmation_title_glasses" msgid="8288346850537727333">"Tillåt att &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; hanterar &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="profile_name_glasses" msgid="3506504967216601277">"enhet"</string>
     <string name="summary_glasses" msgid="5469208629679579157">"Appen får åtkomst till dessa behörigheter på din <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
-    <string name="title_app_streaming" msgid="6845373585257287200">"Vill du tillåta &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; att streama appar på din <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> till &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;?"</string>
-    <string name="summary_app_streaming" msgid="1274464413649731829">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> får åtkomst till allt som visas eller spelas upp på din <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>, inklusive ljud, foton, lösenord och meddelanden.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_1">%1$s</xliff:g> kan streama appar till <xliff:g id="DEVICE_NAME">%3$s</xliff:g> tills du tar bort åtkomsten till den här behörigheten."</string>
-    <string name="helper_summary_app_streaming" msgid="1944832605534698562">"<xliff:g id="APP_NAME">%1$s</xliff:g> begär behörighet för din <xliff:g id="DEVICE_NAME">%2$s</xliff:g> att visa och streama appar mellan dina enheter"</string>
+    <string name="title_app_streaming" msgid="1047090167914857893">"Vill du tillåta &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; att streama appar och systemfunktioner på din <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> till &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;?"</string>
+    <string name="summary_app_streaming" msgid="7990244299655610920">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> får åtkomst till allt som visas eller spelas upp på din <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>, inklusive ljud, foton, betalningsuppgifter, lösenord och meddelanden.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_1">%1$s</xliff:g> kan streama appar till <xliff:g id="DEVICE_NAME">%3$s</xliff:g> tills du tar bort åtkomsten till den här behörigheten."</string>
+    <string name="helper_summary_app_streaming" msgid="1872657107404139828">"<xliff:g id="APP_NAME">%1$s</xliff:g> begär behörighet för <xliff:g id="DEVICE_NAME">%2$s</xliff:g> att streama appar och systemfunktioner från din <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>"</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4782923323932440751">"Ge &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; åtkomst till denna information på din <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
     <string name="helper_summary_computer" msgid="2298803016482139668">"<xliff:g id="APP_NAME">%1$s</xliff:g> begär behörighet för din <xliff:g id="DEVICE_NAME">%2$s</xliff:g> att få åtkomst till foton, mediefiler och aviseringar på din <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>"</string>
-    <string name="title_nearby_device_streaming" msgid="4295322493408411976">"Vill du tillåta &lt;strong&gt;<xliff:g id="DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt; att streama appar och systemfunktioner på din <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> till &lt;strong&gt;<xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>&lt;/strong&gt;?"</string>
-    <string name="summary_nearby_device_streaming" msgid="962267343109051648">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> får åtkomst till allt som visas eller spelas upp på din <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>, inklusive ljud, foton, betalningsuppgifter, lösenord och meddelanden.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_1">%1$s</xliff:g> kan streama appar och systemfunktioner till <xliff:g id="DEVICE_NAME">%3$s</xliff:g> tills du tar bort åtkomsten till den här behörigheten."</string>
-    <string name="helper_summary_nearby_device_streaming" msgid="8509848562931818793">"<xliff:g id="APP_NAME">%1$s</xliff:g> begär behörighet för din <xliff:g id="DEVICE_NAME">%2$s</xliff:g> att streama appar och andra systemfunktioner mellan dina enheter"</string>
+    <string name="title_nearby_device_streaming" msgid="2727103756701741359">"Vill du tillåta &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; att streama appar på din <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> till &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;?"</string>
+    <string name="summary_nearby_device_streaming" msgid="70434958004946884">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> får åtkomst till allt som visas eller spelas upp på <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>, inklusive ljud, foton, betalningsuppgifter, lösenord och meddelanden.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_2">%1$s</xliff:g> kan streama appar till <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> tills du tar bort åtkomsten till den här behörigheten."</string>
+    <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"<xliff:g id="APP_NAME">%1$s</xliff:g> begär behörighet för <xliff:g id="DEVICE_NAME">%2$s</xliff:g> att streama appar från din <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"enhet"</string>
     <string name="summary_generic" msgid="1761976003668044801">"Den här appen kommer att kunna synkronisera information mellan telefonen och den valda enheten, till exempel namnet på någon som ringer"</string>
     <string name="consent_yes" msgid="8344487259618762872">"Tillåt"</string>
diff --git a/packages/CompanionDeviceManager/res/values-sw/strings.xml b/packages/CompanionDeviceManager/res/values-sw/strings.xml
index 8efcb2b..6d623e5 100644
--- a/packages/CompanionDeviceManager/res/values-sw/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-sw/strings.xml
@@ -25,17 +25,17 @@
     <string name="confirmation_title_glasses" msgid="8288346850537727333">"Ungependa kuruhusu &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; idhibiti &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
     <string name="profile_name_glasses" msgid="3506504967216601277">"kifaa"</string>
     <string name="summary_glasses" msgid="5469208629679579157">"Programu hii itaruhusiwa kufikia ruhusa hizi kwenye <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> yako"</string>
-    <string name="title_app_streaming" msgid="6845373585257287200">"Ungependa kuruhusu &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; itiririshe programu za <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> yako kwenye &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;?"</string>
-    <string name="summary_app_streaming" msgid="1274464413649731829">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> itafikia chochote kinachoonekana au kuchezwa kwenye <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>, ikiwa ni pamoja na sauti, picha, manenosiri na ujumbe.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_1">%1$s</xliff:g> itaweza kutiririsha programu kwenye <xliff:g id="DEVICE_NAME">%3$s</xliff:g> hadi utakapoondoa ruhusa hii."</string>
-    <string name="helper_summary_app_streaming" msgid="1944832605534698562">"Programu ya <xliff:g id="APP_NAME">%1$s</xliff:g> inaomba ruhusa kwa niaba ya <xliff:g id="DEVICE_NAME">%2$s</xliff:g> yako ili ionyeshe na kutiririsha programu kati ya vifaa vyako"</string>
+    <string name="title_app_streaming" msgid="1047090167914857893">"Ungependa kuruhusu &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; itiririshe programu na vipengele vya mfumo vya <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> yako kwenye &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;?"</string>
+    <string name="summary_app_streaming" msgid="7990244299655610920">"Programu ya <xliff:g id="APP_NAME_0">%1$s</xliff:g> itafikia chochote kinachoonekana au kuchezwa kwenye <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> yako, ikiwa ni pamoja na sauti, picha, maelezo ya malipo, manenosiri na ujumbe.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_1">%1$s</xliff:g> itaweza kutiririsha programu kwenye <xliff:g id="DEVICE_NAME">%3$s</xliff:g> hadi utakapoondoa ruhusa hii."</string>
+    <string name="helper_summary_app_streaming" msgid="1872657107404139828">"Programu ya <xliff:g id="APP_NAME">%1$s</xliff:g> inaomba ruhusa kwa niaba ya <xliff:g id="DEVICE_NAME">%2$s</xliff:g> ili itiririshe programu na vipengele vya mfumo kwenye <xliff:g id="DEVICE_TYPE">%3$s</xliff:g> yako"</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4782923323932440751">"Ruhusu &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ifikie maelezo haya kutoka kwenye <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> yako"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
     <string name="helper_summary_computer" msgid="2298803016482139668">"Programu ya <xliff:g id="APP_NAME">%1$s</xliff:g> inaomba ruhusa kwa niaba ya <xliff:g id="DEVICE_NAME">%2$s</xliff:g> yako ili ifikie picha, maudhui na arifa za <xliff:g id="DEVICE_TYPE">%3$s</xliff:g> yako"</string>
-    <string name="title_nearby_device_streaming" msgid="4295322493408411976">"Ungependa kuruhusu &lt;strong&gt;<xliff:g id="DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt; itiririshe programu na vipengele vya mfumo vya <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> yako kwenye &lt;strong&gt;<xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>&lt;/strong&gt;?"</string>
-    <string name="summary_nearby_device_streaming" msgid="962267343109051648">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> itafikia chochote kinachoonekana au kuchezwa kwenye <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> yako, ikiwa ni pamoja na sauti, picha, maelezo ya malipo, manenosiri na ujumbe.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_1">%1$s</xliff:g> itaweza kutiririsha programu na vipengele vya mfumo kwenye <xliff:g id="DEVICE_NAME">%3$s</xliff:g> hadi utakapoondoa ruhusa hii."</string>
-    <string name="helper_summary_nearby_device_streaming" msgid="8509848562931818793">"Programu ya <xliff:g id="APP_NAME">%1$s</xliff:g> inaomba ruhusa kwa niaba ya <xliff:g id="DEVICE_NAME">%2$s</xliff:g> yako ili itiririshe programu na vipengele vingine vya mfumo kati ya vifaa vyako"</string>
+    <string name="title_nearby_device_streaming" msgid="2727103756701741359">"Ungependa kuruhusu &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; itiririshe programu za <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> yako kwenye &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;?"</string>
+    <string name="summary_nearby_device_streaming" msgid="70434958004946884">"Programu ya <xliff:g id="APP_NAME_0">%1$s</xliff:g> itafikia chochote kinachoonekana au kuchezwa kwenye <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>, ikiwa ni pamoja na sauti, picha, maelezo ya malipo, manenosiri na ujumbe.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_2">%1$s</xliff:g> itaweza kutiririsha programu kwenye <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> hadi utakapoondoa ruhusa hii."</string>
+    <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"Programu ya <xliff:g id="APP_NAME">%1$s</xliff:g> inaomba ruhusa kwa niaba ya <xliff:g id="DEVICE_NAME">%2$s</xliff:g> ili itiririshe programu kwenye <xliff:g id="DEVICE_TYPE">%3$s</xliff:g> yako"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"kifaa"</string>
     <string name="summary_generic" msgid="1761976003668044801">"Programu hii itaweza kusawazisha maelezo, kama vile jina la mtu anayepiga simu, kati ya simu yako na kifaa ulichochagua"</string>
     <string name="consent_yes" msgid="8344487259618762872">"Ruhusu"</string>
diff --git a/packages/CompanionDeviceManager/res/values-ta/strings.xml b/packages/CompanionDeviceManager/res/values-ta/strings.xml
index 1a59c09..76e6410 100644
--- a/packages/CompanionDeviceManager/res/values-ta/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ta/strings.xml
@@ -25,17 +25,23 @@
     <string name="confirmation_title_glasses" msgid="8288346850537727333">"&lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&amp;gt சாதனத்தை நிர்வகிக்க &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ஆப்ஸை அனுமதிக்கவா?"</string>
     <string name="profile_name_glasses" msgid="3506504967216601277">"சாதனம்"</string>
     <string name="summary_glasses" msgid="5469208629679579157">"உங்கள் <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> சாதனத்தில் இந்த அனுமதிகளை அணுக இந்த ஆப்ஸ் அனுமதிக்கப்படும்"</string>
-    <string name="title_app_streaming" msgid="6845373585257287200">"உங்கள் <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> சாதனத்தின் ஆப்ஸை &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt; சாதனத்தில் ஸ்ட்ரீம் செய்ய &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ஆப்ஸை அனுமதிக்கவா?"</string>
-    <string name="summary_app_streaming" msgid="1274464413649731829">"ஆடியோ, படங்கள், கடவுச்சொற்கள், மெசேஜ்கள் உட்பட <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> சாதனத்தில் காட்டப்படுகின்ற/பிளே செய்யப்படுகின்ற அனைத்தையும் <xliff:g id="APP_NAME_0">%1$s</xliff:g> அணுகும்.&lt;br/&gt;&lt;br/&gt;இந்த அனுமதிக்கான அணுகலை நீங்கள் அகற்றும் வரை <xliff:g id="DEVICE_NAME">%3$s</xliff:g> சாதனத்தில் ஆப்ஸை <xliff:g id="APP_NAME_1">%1$s</xliff:g> ஸ்ட்ரீம் செய்ய முடியும்."</string>
-    <string name="helper_summary_app_streaming" msgid="1944832605534698562">"உங்கள் சாதனங்களுக்கு இடையே ஆப்ஸைக் காட்சிப்படுத்தவும் ஸ்ட்ரீம் செய்யவும் உங்கள் <xliff:g id="DEVICE_NAME">%2$s</xliff:g> சார்பாக <xliff:g id="APP_NAME">%1$s</xliff:g> அனுமதி கேட்கிறது"</string>
+    <!-- no translation found for title_app_streaming (1047090167914857893) -->
+    <skip />
+    <!-- no translation found for summary_app_streaming (7990244299655610920) -->
+    <skip />
+    <!-- no translation found for helper_summary_app_streaming (1872657107404139828) -->
+    <skip />
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4782923323932440751">"உங்கள் <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> சாதனத்தில் உள்ள இந்தத் தகவல்களை அணுக, &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ஆப்ஸை அனுமதிக்கவும்"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
     <string name="helper_summary_computer" msgid="2298803016482139668">"உங்கள் <xliff:g id="DEVICE_TYPE">%3$s</xliff:g> சாதனத்தில் உள்ள படங்கள், மீடியா, அறிவிப்புகள் ஆகியவற்றை அணுக உங்கள் <xliff:g id="DEVICE_NAME">%2$s</xliff:g> சார்பாக <xliff:g id="APP_NAME">%1$s</xliff:g> அனுமதி கேட்கிறது"</string>
-    <string name="title_nearby_device_streaming" msgid="4295322493408411976">"உங்கள் <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> சாதனத்தின் ஆப்ஸையும் சிஸ்டம் அம்சங்களையும் &lt;strong&gt;<xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>&lt;/strong&gt; சாதனத்தில் ஸ்ட்ரீம் செய்ய &lt;strong&gt;<xliff:g id="DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt; சாதனத்தை அனுமதிக்கவா?"</string>
-    <string name="summary_nearby_device_streaming" msgid="962267343109051648">"ஆடியோ, படங்கள், பேமெண்ட் தகவல்கள், கடவுச்சொற்கள், மெசேஜ்கள் உட்பட <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> சாதனத்தில் காட்டப்படுகின்ற/பிளே செய்யப்படுகின்ற அனைத்தையும் <xliff:g id="APP_NAME_0">%1$s</xliff:g> அணுகும்.&lt;br/&gt;&lt;br/&gt;இந்த அனுமதிக்கான அணுகலை நீங்கள் அகற்றும் வரை <xliff:g id="DEVICE_NAME">%3$s</xliff:g> சாதனத்தில் ஆப்ஸையும் சிஸ்டம் அம்சங்களையும் <xliff:g id="APP_NAME_1">%1$s</xliff:g> ஸ்ட்ரீம் செய்ய முடியும்."</string>
-    <string name="helper_summary_nearby_device_streaming" msgid="8509848562931818793">"உங்கள் சாதனங்களுக்கு இடையே ஆப்ஸையும் பிற சிஸ்டம் அம்சங்களையும் ஸ்ட்ரீம் செய்ய உங்கள் <xliff:g id="DEVICE_NAME">%2$s</xliff:g> சார்பாக <xliff:g id="APP_NAME">%1$s</xliff:g> அனுமதி கேட்கிறது"</string>
+    <!-- no translation found for title_nearby_device_streaming (2727103756701741359) -->
+    <skip />
+    <!-- no translation found for summary_nearby_device_streaming (70434958004946884) -->
+    <skip />
+    <!-- no translation found for helper_summary_nearby_device_streaming (4712712177819370967) -->
+    <skip />
     <string name="profile_name_generic" msgid="6851028682723034988">"சாதனம்"</string>
     <string name="summary_generic" msgid="1761976003668044801">"அழைப்பவரின் பெயர் போன்ற தகவலை உங்கள் மொபைல் மற்றும் தேர்வுசெய்த சாதனத்திற்கு இடையில் இந்த ஆப்ஸால் ஒத்திசைக்க முடியும்"</string>
     <string name="consent_yes" msgid="8344487259618762872">"அனுமதி"</string>
diff --git a/packages/CompanionDeviceManager/res/values-te/strings.xml b/packages/CompanionDeviceManager/res/values-te/strings.xml
index 63d86fc..34671f9 100644
--- a/packages/CompanionDeviceManager/res/values-te/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-te/strings.xml
@@ -25,17 +25,17 @@
     <string name="confirmation_title_glasses" msgid="8288346850537727333">"&lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;‌ను మేనేజ్ చేయడానికి &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;‌ను అనుమతించాలా?"</string>
     <string name="profile_name_glasses" msgid="3506504967216601277">"పరికరం"</string>
     <string name="summary_glasses" msgid="5469208629679579157">"మీ <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>‌లో ఈ అనుమతులను యాక్సెస్ చేయడానికి ఈ యాప్ అనుమతించబడుతుంది"</string>
-    <string name="title_app_streaming" msgid="6845373585257287200">"మీ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> యాప్‌లను &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;‌కు స్ట్రీమ్ చేయడానికి &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;‌ను అనుమతించాలా?"</string>
-    <string name="summary_app_streaming" msgid="1274464413649731829">"ఆడియో, ఫోటోలు, పాస్‌వర్డ్‌లు, మెసేజ్‌లతో సహా మీ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>‌లో కనిపించే లేదా ప్లే అయ్యే దేనికైనా <xliff:g id="APP_NAME_0">%1$s</xliff:g>‌కు యాక్సెస్ ఉంటుంది.&lt;br/&gt;&lt;br/&gt;మీరు ఈ అనుమతికి యాక్సెస్‌ను తీసివేసే వరకు <xliff:g id="APP_NAME_1">%1$s</xliff:g> <xliff:g id="DEVICE_NAME">%3$s</xliff:g>‌కు యాప్‌లను స్ట్రీమ్ చేయగలదు."</string>
-    <string name="helper_summary_app_streaming" msgid="1944832605534698562">"మీ పరికరాలలో యాప్‌లను డిస్‌ప్లే చేయడానికి, స్ట్రీమ్ చేయడానికి <xliff:g id="APP_NAME">%1$s</xliff:g> మీ<xliff:g id="DEVICE_NAME">%2$s</xliff:g> తరఫున అనుమతిని రిక్వెస్ట్ చేస్తోంది"</string>
+    <string name="title_app_streaming" msgid="1047090167914857893">"మీ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> యాప్‌లను, సిస్టమ్ ఫీచర్‌లను &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;‌కు స్ట్రీమ్ చేయడానికి &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;‌ను అనుమతించాలా?"</string>
+    <string name="summary_app_streaming" msgid="7990244299655610920">"ఆడియో, ఫోటోలు, పేమెంట్ సమాచారం, పాస్‌వర్డ్‌లతో సహా మీ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>‌లో కనిపించే లేదా ప్లే అయ్యే దేనికైనా <xliff:g id="APP_NAME_0">%1$s</xliff:g>‌కు యాక్సెస్ ఉంటుంది.&lt;br/&gt;&lt;br/&gt;మీరు ఈ అనుమతికి యాక్సెస్‌ను తీసివేసే వరకు <xliff:g id="APP_NAME_1">%1$s</xliff:g> <xliff:g id="DEVICE_NAME">%3$s</xliff:g>‌కు యాప్‌లను స్ట్రీమ్ చేయగలదు."</string>
+    <string name="helper_summary_app_streaming" msgid="1872657107404139828">"మీ <xliff:g id="DEVICE_TYPE">%3$s</xliff:g> నుండి యాప్‌లను, సిస్టమ్ ఫీచర్‌లను స్ట్రీమ్ చేయడానికి <xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="DEVICE_NAME">%2$s</xliff:g> తరఫున అనుమతిని రిక్వెస్ట్ చేస్తోంది"</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4782923323932440751">"మీ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> నుండి ఈ సమాచారాన్ని యాక్సెస్ చేయడానికి &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;‌ను అనుమతించండి"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
     <string name="helper_summary_computer" msgid="2298803016482139668">"మీ <xliff:g id="DEVICE_TYPE">%3$s</xliff:g> ఫోటోలను, మీడియాను, ఇంకా నోటిఫికేషన్‌లను యాక్సెస్ చేయడానికి <xliff:g id="APP_NAME">%1$s</xliff:g> మీ <xliff:g id="DEVICE_NAME">%2$s</xliff:g> తరఫున అనుమతిని రిక్వెస్ట్ చేస్తోంది"</string>
-    <string name="title_nearby_device_streaming" msgid="4295322493408411976">"మీ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> యాప్‌లను, సిస్టమ్ ఫీచర్‌లను &lt;strong&gt;<xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>&lt;/strong&gt;‌కు స్ట్రీమ్ చేయడానికి &lt;strong&gt;<xliff:g id="DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt;‌ను అనుమతించాలా?"</string>
-    <string name="summary_nearby_device_streaming" msgid="962267343109051648">"ఆడియో, ఫోటోలు, పేమెంట్ సమాచారం, పాస్‌వర్డ్‌లతో సహా మీ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>‌లో కనిపించే లేదా ప్లే అయ్యే దేనికైనా <xliff:g id="APP_NAME_0">%1$s</xliff:g>‌కు యాక్సెస్ ఉంటుంది.&lt;br/&gt;&lt;br/&gt;మీరు ఈ అనుమతికి యాక్సెస్‌ను తీసివేసే వరకు <xliff:g id="APP_NAME_1">%1$s</xliff:g> <xliff:g id="DEVICE_NAME">%3$s</xliff:g>‌కు యాప్‌లను, సిస్టమ్ ఫీచర్‌లను స్ట్రీమ్ చేయగలదు."</string>
-    <string name="helper_summary_nearby_device_streaming" msgid="8509848562931818793">"మీ పరికరాలలో యాప్‌లను, ఇతర సిస్టమ్ ఫీచర్‌లను స్ట్రీమ్ చేయడానికి <xliff:g id="APP_NAME">%1$s</xliff:g> మీ <xliff:g id="DEVICE_NAME">%2$s</xliff:g> తరఫున అనుమతిని రిక్వెస్ట్ చేస్తోంది"</string>
+    <string name="title_nearby_device_streaming" msgid="2727103756701741359">"మీ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> యాప్‌లను &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;‌కు స్ట్రీమ్ చేయడానికి &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;‌ను అనుమతించాలా?"</string>
+    <string name="summary_nearby_device_streaming" msgid="70434958004946884">"ఆడియో, ఫోటోలు, పేమెంట్ సమాచారం, పాస్‌వర్డ్‌లతో సహా <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>‌లో కనిపించే లేదా ప్లే అయ్యే దేనికైనా <xliff:g id="APP_NAME_0">%1$s</xliff:g>‌కు యాక్సెస్ ఉంటుంది.&lt;br/&gt;&lt;br/&gt;మీరు ఈ అనుమతికి యాక్సెస్‌ను తీసివేసే వరకు <xliff:g id="APP_NAME_2">%1$s</xliff:g> <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g>‌కు యాప్‌లను స్ట్రీమ్ చేయగలదు."</string>
+    <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"మీ <xliff:g id="DEVICE_TYPE">%3$s</xliff:g> నుండి యాప్‌లను స్ట్రీమ్ చేయడానికి <xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="DEVICE_NAME">%2$s</xliff:g> తరఫున అనుమతిని రిక్వెస్ట్ చేస్తోంది"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"పరికరం"</string>
     <string name="summary_generic" msgid="1761976003668044801">"కాల్ చేస్తున్న వారి పేరు వంటి సమాచారాన్ని ఈ యాప్ మీ ఫోన్ కు, ఎంచుకున్న పరికరానికీ మధ్య సింక్ చేయగలుగుతుంది"</string>
     <string name="consent_yes" msgid="8344487259618762872">"అనుమతించండి"</string>
diff --git a/packages/CompanionDeviceManager/res/values-th/strings.xml b/packages/CompanionDeviceManager/res/values-th/strings.xml
index eb9a6ed..e74f96c 100644
--- a/packages/CompanionDeviceManager/res/values-th/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-th/strings.xml
@@ -25,17 +25,17 @@
     <string name="confirmation_title_glasses" msgid="8288346850537727333">"อนุญาตให้ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; จัดการ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ไหม"</string>
     <string name="profile_name_glasses" msgid="3506504967216601277">"อุปกรณ์"</string>
     <string name="summary_glasses" msgid="5469208629679579157">"แอปนี้จะได้รับสิทธิ์ดังต่อไปนี้ใน<xliff:g id="DEVICE_TYPE">%1$s</xliff:g>ของคุณ"</string>
-    <string name="title_app_streaming" msgid="6845373585257287200">"อนุญาตให้ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; สตรีมแอปใน<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>ของคุณไปยัง &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt; ไหม"</string>
-    <string name="summary_app_streaming" msgid="1274464413649731829">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> จะมีสิทธิ์เข้าถึงทุกอย่างที่ปรากฏหรือเล่นบน<xliff:g id="DEVICE_TYPE">%2$s</xliff:g> ซึ่งรวมถึงเสียง รูปภาพ รหัสผ่าน และข้อความ&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_1">%1$s</xliff:g> จะสามารถสตรีมแอปไปยัง <xliff:g id="DEVICE_NAME">%3$s</xliff:g> ได้จนกว่าคุณจะนำสิทธิ์เข้าถึงนี้ออก"</string>
-    <string name="helper_summary_app_streaming" msgid="1944832605534698562">"<xliff:g id="APP_NAME">%1$s</xliff:g> กำลังขอสิทธิ์ในนามของ <xliff:g id="DEVICE_NAME">%2$s</xliff:g> เพื่อแสดงและสตรีมแอประหว่างอุปกรณ์ต่างๆ ของคุณ"</string>
+    <string name="title_app_streaming" msgid="1047090167914857893">"อนุญาตให้ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; สตรีมแอปและฟีเจอร์ของระบบใน<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>ของคุณไปยัง &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt; ไหม"</string>
+    <string name="summary_app_streaming" msgid="7990244299655610920">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> จะมีสิทธิ์เข้าถึงทุกอย่างที่ปรากฏหรือเล่นบน<xliff:g id="DEVICE_TYPE">%2$s</xliff:g> ซึ่งรวมถึงเสียง รูปภาพ ข้อมูลการชำระเงิน รหัสผ่าน และข้อความ&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_1">%1$s</xliff:g> จะสามารถสตรีมแอปไปยัง <xliff:g id="DEVICE_NAME">%3$s</xliff:g> ได้จนกว่าคุณจะนำการให้สิทธิ์นี้ออก"</string>
+    <string name="helper_summary_app_streaming" msgid="1872657107404139828">"<xliff:g id="APP_NAME">%1$s</xliff:g> กำลังขอสิทธิ์ในนามของ <xliff:g id="DEVICE_NAME">%2$s</xliff:g> เพื่อสตรีมแอปและฟีเจอร์ของระบบจาก<xliff:g id="DEVICE_TYPE">%3$s</xliff:g>ของคุณ"</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4782923323932440751">"อนุญาตให้ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; เข้าถึงข้อมูลนี้จาก<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>ของคุณ"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
     <string name="helper_summary_computer" msgid="2298803016482139668">"<xliff:g id="APP_NAME">%1$s</xliff:g> กำลังขอสิทธิ์ในนามของ <xliff:g id="DEVICE_NAME">%2$s</xliff:g> เพื่อเข้าถึงรูปภาพ สื่อ และการแจ้งเตือนใน<xliff:g id="DEVICE_TYPE">%3$s</xliff:g>ของคุณ"</string>
-    <string name="title_nearby_device_streaming" msgid="4295322493408411976">"อนุญาตให้ &lt;strong&gt;<xliff:g id="DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt; สตรีมแอปและฟีเจอร์ของระบบใน<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>ของคุณไปยัง &lt;strong&gt;<xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>&lt;/strong&gt; ไหม"</string>
-    <string name="summary_nearby_device_streaming" msgid="962267343109051648">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> จะมีสิทธิ์เข้าถึงทุกอย่างที่ปรากฏหรือเล่นบน<xliff:g id="DEVICE_TYPE">%2$s</xliff:g> ซึ่งรวมถึงเสียง รูปภาพ ข้อมูลการชำระเงิน รหัสผ่าน และข้อความ&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_1">%1$s</xliff:g> จะสามารถสตรีมแอปและฟีเจอร์ของระบบไปยัง <xliff:g id="DEVICE_NAME">%3$s</xliff:g> ได้จนกว่าคุณจะนำสิทธิ์เข้าถึงนี้ออก"</string>
-    <string name="helper_summary_nearby_device_streaming" msgid="8509848562931818793">"<xliff:g id="APP_NAME">%1$s</xliff:g> กำลังขอสิทธิ์ในนามของ <xliff:g id="DEVICE_NAME">%2$s</xliff:g> เพื่อสตรีมแอปและฟีเจอร์อื่นๆ ของระบบระหว่างอุปกรณ์"</string>
+    <string name="title_nearby_device_streaming" msgid="2727103756701741359">"อนุญาตให้ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; สตรีมแอปใน<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>ของคุณไปยัง &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt; ไหม"</string>
+    <string name="summary_nearby_device_streaming" msgid="70434958004946884">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> จะมีสิทธิ์เข้าถึงทุกอย่างที่ปรากฏหรือเล่นบน <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g> ซึ่งรวมถึงเสียง รูปภาพ ข้อมูลการชำระเงิน รหัสผ่าน และข้อความ&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_2">%1$s</xliff:g> จะสามารถสตรีมแอปไปยัง <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> ได้จนกว่าคุณจะนำการให้สิทธิ์นี้ออก"</string>
+    <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"<xliff:g id="APP_NAME">%1$s</xliff:g> กำลังขอสิทธิ์ในนามของ <xliff:g id="DEVICE_NAME">%2$s</xliff:g> เพื่อสตรีมแอปจาก<xliff:g id="DEVICE_TYPE">%3$s</xliff:g>ของคุณ"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"อุปกรณ์"</string>
     <string name="summary_generic" msgid="1761976003668044801">"แอปนี้จะสามารถซิงค์ข้อมูล เช่น ชื่อของบุคคลที่โทรเข้ามา ระหว่างโทรศัพท์ของคุณและอุปกรณ์ที่เลือกไว้ได้"</string>
     <string name="consent_yes" msgid="8344487259618762872">"อนุญาต"</string>
diff --git a/packages/CompanionDeviceManager/res/values-tl/strings.xml b/packages/CompanionDeviceManager/res/values-tl/strings.xml
index bce6c7c..ce907f7 100644
--- a/packages/CompanionDeviceManager/res/values-tl/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-tl/strings.xml
@@ -25,17 +25,17 @@
     <string name="confirmation_title_glasses" msgid="8288346850537727333">"Payagan ang &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; na pamahalaan ang &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
     <string name="profile_name_glasses" msgid="3506504967216601277">"device"</string>
     <string name="summary_glasses" msgid="5469208629679579157">"Papayagan ang app na ito na ma-access ang mga pahintulot na ito sa iyong <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
-    <string name="title_app_streaming" msgid="6845373585257287200">"Payagan ang &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; na i-stream ang mga app ng iyong <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> sa &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;?"</string>
-    <string name="summary_app_streaming" msgid="1274464413649731829">"Magkakaroon ang <xliff:g id="APP_NAME_0">%1$s</xliff:g> ng access sa kahit anong nakikita o pine-play sa <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>, kasama na ang audio, mga larawan, password, at mensahe.&lt;br/&gt;&lt;br/&gt;Magagawa ng <xliff:g id="APP_NAME_1">%1$s</xliff:g> na mag-stream ng mga app sa <xliff:g id="DEVICE_NAME">%3$s</xliff:g> hanggang sa alisin mo ang access sa pahintulot na ito."</string>
-    <string name="helper_summary_app_streaming" msgid="1944832605534698562">"Humihiling ng pahintulot ang <xliff:g id="APP_NAME">%1$s</xliff:g> para sa iyong <xliff:g id="DEVICE_NAME">%2$s</xliff:g> na makapagpakita at makapag-stream ng mga app sa mga device mo"</string>
+    <string name="title_app_streaming" msgid="1047090167914857893">"Payagan ang &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; na i-stream ang mga app at feature ng system ng iyong <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>’ sa &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;?"</string>
+    <string name="summary_app_streaming" msgid="7990244299655610920">"Magkakaroon ng access ang <xliff:g id="APP_NAME_0">%1$s</xliff:g> sa kahit anong nakikita o pine-play sa iyong <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>, kasama ang audio, mga larawan, impormasyon sa pagbabayad, mga password, at mga mensahe.&lt;br/&gt;&lt;br/&gt;Magagawa ng<xliff:g id="APP_NAME_1">%1$s</xliff:g> na mag-stream ng mga app sa <xliff:g id="DEVICE_NAME">%3$s</xliff:g> hanggang sa alisin mo ang access sa pahintulot na ito."</string>
+    <string name="helper_summary_app_streaming" msgid="1872657107404139828">"Humihingi ang <xliff:g id="APP_NAME">%1$s</xliff:g> ng pahintulot para sa <xliff:g id="DEVICE_NAME">%2$s</xliff:g> na mag-stream ng mga app at feature ng system mula sa iyong <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>"</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4782923323932440751">"Payagan ang &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; na i-access ang impormasyong ito sa iyong <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
     <string name="helper_summary_computer" msgid="2298803016482139668">"Humihiling ng pahintulot ang <xliff:g id="APP_NAME">%1$s</xliff:g> para sa iyong <xliff:g id="DEVICE_NAME">%2$s</xliff:g> na ma-access ang mga larawan, media, at notification ng <xliff:g id="DEVICE_TYPE">%3$s</xliff:g> mo"</string>
-    <string name="title_nearby_device_streaming" msgid="4295322493408411976">"Payagan ang &lt;strong&gt;<xliff:g id="DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt; na i-stream ang mga app at feature ng system ng iyong <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>’ sa &lt;strong&gt;<xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>&lt;/strong&gt;?"</string>
-    <string name="summary_nearby_device_streaming" msgid="962267343109051648">"Magkakaroon ng access ang <xliff:g id="APP_NAME_0">%1$s</xliff:g> sa kahit anong nakikita o pine-play sa iyong <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>, kasama ang audio, mga larawan, impormasyon sa pagbabayad, mga password, at mga mensahe.&lt;br/&gt;&lt;br/&gt;Magagawa ng <xliff:g id="APP_NAME_1">%1$s</xliff:g> na mag-stream ng mga app sa <xliff:g id="DEVICE_NAME">%3$s</xliff:g> hanggang sa alisin mo ang access sa pahintulot na ito."</string>
-    <string name="helper_summary_nearby_device_streaming" msgid="8509848562931818793">"Humihiling ng pahintulot ang <xliff:g id="APP_NAME">%1$s</xliff:g> para sa iyong <xliff:g id="DEVICE_NAME">%2$s</xliff:g> na mag-stream ng mga app at iba pang feature ng system sa pagitan ng mga device mo"</string>
+    <string name="title_nearby_device_streaming" msgid="2727103756701741359">"Payagan ang &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; na i-stream ang mga app ng iyong <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> sa &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;?"</string>
+    <string name="summary_nearby_device_streaming" msgid="70434958004946884">"Magkakaroon ng access ang <xliff:g id="APP_NAME_0">%1$s</xliff:g> sa kahit anong nakikita o pine-play sa <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>, kasama ang audio, mga larawan, impormasyon sa pagbabayad, mga password, at mga mensahe.&lt;br/&gt;&lt;br/&gt;Magagawa ng <xliff:g id="APP_NAME_2">%1$s</xliff:g> na mag-stream ng mga app sa <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> hanggang sa alisin mo ang access sa pahintulot na ito."</string>
+    <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"Humihingi ang <xliff:g id="APP_NAME">%1$s</xliff:g> ng pahintulot para sa <xliff:g id="DEVICE_NAME">%2$s</xliff:g> na mag-stream ng mga app mula sa iyong <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"device"</string>
     <string name="summary_generic" msgid="1761976003668044801">"Magagawa ng app na ito na mag-sync ng impormasyon, tulad ng pangalan ng isang taong tumatawag, sa pagitan ng iyong telepono at ng napiling device"</string>
     <string name="consent_yes" msgid="8344487259618762872">"Payagan"</string>
diff --git a/packages/CompanionDeviceManager/res/values-tr/strings.xml b/packages/CompanionDeviceManager/res/values-tr/strings.xml
index 131f2e3..44d6bf7 100644
--- a/packages/CompanionDeviceManager/res/values-tr/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-tr/strings.xml
@@ -25,17 +25,23 @@
     <string name="confirmation_title_glasses" msgid="8288346850537727333">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; uygulamasına &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; cihazını yönetmesi için izin verilsin mi?"</string>
     <string name="profile_name_glasses" msgid="3506504967216601277">"Cihaz"</string>
     <string name="summary_glasses" msgid="5469208629679579157">"Bu uygulamanın <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> cihazınızda şu izinlere erişmesine izin verilecek:"</string>
-    <string name="title_app_streaming" msgid="6845373585257287200">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; adlı uygulamanın <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> cihazınızdaki uygulamaları &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt; cihazına aktarmasına izin verilsin mi?"</string>
-    <string name="summary_app_streaming" msgid="1274464413649731829">"<xliff:g id="APP_NAME_0">%1$s</xliff:g>; ses, fotoğraflar, şifreler ve mesajlar da dahil olmak üzere <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> cihazında görünen veya oynatılan her şeye erişebilecek.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_1">%1$s</xliff:g> siz bu iznin erişimini kaldırana kadar uygulamaları <xliff:g id="DEVICE_NAME">%3$s</xliff:g> cihazına aktarabilecek."</string>
-    <string name="helper_summary_app_streaming" msgid="1944832605534698562">"<xliff:g id="APP_NAME">%1$s</xliff:g>, cihazlarınız arasında uygulamaları göstermek ve aktarmak için <xliff:g id="DEVICE_NAME">%2$s</xliff:g> cihazınız adına izin istiyor"</string>
+    <!-- no translation found for title_app_streaming (1047090167914857893) -->
+    <skip />
+    <!-- no translation found for summary_app_streaming (7990244299655610920) -->
+    <skip />
+    <!-- no translation found for helper_summary_app_streaming (1872657107404139828) -->
+    <skip />
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4782923323932440751">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; uygulamasının, <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> cihazınızdaki bu bilgilere erişmesine izin verin"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
     <string name="helper_summary_computer" msgid="2298803016482139668">"<xliff:g id="APP_NAME">%1$s</xliff:g>, <xliff:g id="DEVICE_TYPE">%3$s</xliff:g> içindeki fotoğraf, medya ve bildirimlere erişmek için <xliff:g id="DEVICE_NAME">%2$s</xliff:g> cihazınız adına izin istiyor"</string>
-    <string name="title_nearby_device_streaming" msgid="4295322493408411976">"&lt;strong&gt;<xliff:g id="DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt; adlı uygulamanın <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> cihazınızdaki uygulamaları ve sistem özelliklerini &lt;strong&gt;<xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>&lt;/strong&gt; cihazına aktarmasına izin verilsin mi?"</string>
-    <string name="summary_nearby_device_streaming" msgid="962267343109051648">"<xliff:g id="APP_NAME_0">%1$s</xliff:g>; ses, fotoğraflar, ödeme bilgileri, şifreler ve mesajlar da dahil olmak üzere <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> cihazınızda görünen veya oynatılan her şeye erişebilecek.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_1">%1$s</xliff:g> siz bu iznin erişimini kaldırana kadar uygulamaları ve diğer sistem özelliklerini <xliff:g id="DEVICE_NAME">%3$s</xliff:g> cihazına aktarabilecek."</string>
-    <string name="helper_summary_nearby_device_streaming" msgid="8509848562931818793">"<xliff:g id="APP_NAME">%1$s</xliff:g>, cihazlarınız arasında uygulamaları ve diğer sistem özelliklerini aktarmak için <xliff:g id="DEVICE_NAME">%2$s</xliff:g> cihazınız adına izin istiyor"</string>
+    <!-- no translation found for title_nearby_device_streaming (2727103756701741359) -->
+    <skip />
+    <!-- no translation found for summary_nearby_device_streaming (70434958004946884) -->
+    <skip />
+    <!-- no translation found for helper_summary_nearby_device_streaming (4712712177819370967) -->
+    <skip />
     <string name="profile_name_generic" msgid="6851028682723034988">"cihaz"</string>
     <string name="summary_generic" msgid="1761976003668044801">"Bu uygulama, arayan kişinin adı gibi bilgileri telefonunuz ve seçili cihaz arasında senkronize edebilir"</string>
     <string name="consent_yes" msgid="8344487259618762872">"İzin ver"</string>
diff --git a/packages/CompanionDeviceManager/res/values-uk/strings.xml b/packages/CompanionDeviceManager/res/values-uk/strings.xml
index f170d3c..1d248b6 100644
--- a/packages/CompanionDeviceManager/res/values-uk/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-uk/strings.xml
@@ -25,17 +25,23 @@
     <string name="confirmation_title_glasses" msgid="8288346850537727333">"Дозволити додатку &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; керувати пристроєм &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
     <string name="profile_name_glasses" msgid="3506504967216601277">"пристрій"</string>
     <string name="summary_glasses" msgid="5469208629679579157">"Цей додаток матиме доступ до перелічених нижче дозволів на вашому <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
-    <string name="title_app_streaming" msgid="6845373585257287200">"Дозволити додатку &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; транслювати додатки на вашому <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> на пристрій &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;?"</string>
-    <string name="summary_app_streaming" msgid="1274464413649731829">"Додаток <xliff:g id="APP_NAME_0">%1$s</xliff:g> матиме доступ до контенту, що відображається чи відтворюється на <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>, зокрема до аудіо, фото, паролів і повідомлень.&lt;br/&gt;&lt;br/&gt;Додаток <xliff:g id="APP_NAME_1">%1$s</xliff:g> зможе транслювати додатки на пристрої \"<xliff:g id="DEVICE_NAME">%3$s</xliff:g>\", поки ви не скасуєте цей дозвіл."</string>
-    <string name="helper_summary_app_streaming" msgid="1944832605534698562">"Додаток <xliff:g id="APP_NAME">%1$s</xliff:g> від імені вашого пристрою \"<xliff:g id="DEVICE_NAME">%2$s</xliff:g>\" запитує дозвіл на відображення й транслювання додатків на ваших пристроях"</string>
+    <!-- no translation found for title_app_streaming (1047090167914857893) -->
+    <skip />
+    <!-- no translation found for summary_app_streaming (7990244299655610920) -->
+    <skip />
+    <!-- no translation found for helper_summary_app_streaming (1872657107404139828) -->
+    <skip />
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4782923323932440751">"Дозвольте додатку &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; доступ до цієї інформації на вашому <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
     <string name="helper_summary_computer" msgid="2298803016482139668">"Додаток <xliff:g id="APP_NAME">%1$s</xliff:g> від імені вашого пристрою \"<xliff:g id="DEVICE_NAME">%2$s</xliff:g>\" запитує дозвіл на доступ до фотографій, медіафайлів і сповіщень на вашому <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>"</string>
-    <string name="title_nearby_device_streaming" msgid="4295322493408411976">"Дозволити пристрою &lt;strong&gt;<xliff:g id="DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt; транслювати додатки й системні функції на <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> на пристрій &lt;strong&gt;<xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>&lt;/strong&gt;?"</string>
-    <string name="summary_nearby_device_streaming" msgid="962267343109051648">"Додаток <xliff:g id="APP_NAME_0">%1$s</xliff:g>матиме доступ до контенту, що відображається чи відтворюється на вашому <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>, зокрема до аудіо, фото, платіжної інформації, паролів і повідомлень.&lt;br/&gt;&lt;br/&gt;Додаток <xliff:g id="APP_NAME_1">%1$s</xliff:g> зможе транслювати додатки й системні функції на <xliff:g id="DEVICE_NAME">%3$s</xliff:g>, поки ви не скасуєте цей дозвіл."</string>
-    <string name="helper_summary_nearby_device_streaming" msgid="8509848562931818793">"Додаток <xliff:g id="APP_NAME">%1$s</xliff:g> від імені вашого пристрою \"<xliff:g id="DEVICE_NAME">%2$s</xliff:g>\" запитує дозвіл на транслювання додатків й інших системних функцій на ваших пристроях"</string>
+    <!-- no translation found for title_nearby_device_streaming (2727103756701741359) -->
+    <skip />
+    <!-- no translation found for summary_nearby_device_streaming (70434958004946884) -->
+    <skip />
+    <!-- no translation found for helper_summary_nearby_device_streaming (4712712177819370967) -->
+    <skip />
     <string name="profile_name_generic" msgid="6851028682723034988">"пристрій"</string>
     <string name="summary_generic" msgid="1761976003668044801">"Цей додаток зможе синхронізувати інформацію (наприклад, ім’я абонента, який викликає) між телефоном і вибраним пристроєм"</string>
     <string name="consent_yes" msgid="8344487259618762872">"Дозволити"</string>
diff --git a/packages/CompanionDeviceManager/res/values-ur/strings.xml b/packages/CompanionDeviceManager/res/values-ur/strings.xml
index fd6537e..24fd827 100644
--- a/packages/CompanionDeviceManager/res/values-ur/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ur/strings.xml
@@ -25,17 +25,17 @@
     <string name="confirmation_title_glasses" msgid="8288346850537727333">"‏&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; کو &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; کا نظم کرنے کی اجازت دیں؟"</string>
     <string name="profile_name_glasses" msgid="3506504967216601277">"آلہ"</string>
     <string name="summary_glasses" msgid="5469208629679579157">"اس ایپ کو آپ کے <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> پر ان اجازتوں تک رسائی کی اجازت ہوگی"</string>
-    <string name="title_app_streaming" msgid="6845373585257287200">"‏&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; کو آپ کے <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> کی ایپس کو <xliff:g id="DEVICE_NAME">%3$s</xliff:g> پر سلسلہ بندی کرنے کی اجازت دیں؟"</string>
-    <string name="summary_app_streaming" msgid="1274464413649731829">"‏<xliff:g id="APP_NAME_0">%1$s</xliff:g> کو <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> پر دکھائی دینے والی یا چلائی جانے والی کسی بھی چیز تک رسائی حاصل ہوگی، بشمول آڈیو، تصاویر، پاس ورڈز اور پیغامات۔&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_1">%1$s</xliff:g> <xliff:g id="DEVICE_NAME">%3$s</xliff:g> پر اس وقت تک ایپس کی سلسلہ بندی کر سکے گی جب تک آپ اس اجازت تک رسائی کو ہٹا نہیں دیتے۔"</string>
-    <string name="helper_summary_app_streaming" msgid="1944832605534698562">"<xliff:g id="APP_NAME">%1$s</xliff:g> ایپ آپ کے <xliff:g id="DEVICE_NAME">%2$s</xliff:g> کی جانب سے آپ کے آلات کے درمیان ایپس کو ڈسپلے اور اسٹریم کرنے کے لیے اجازت کی درخواست کر رہی ہے"</string>
+    <string name="title_app_streaming" msgid="1047090167914857893">"‏‎&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;‎ کو آپ کے <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> کی ایپس اور سسٹم کی خصوصیات کو ‎&lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;‎ پر سلسلہ بندی کرنے کی اجازت دیں؟"</string>
+    <string name="summary_app_streaming" msgid="7990244299655610920">"‏<xliff:g id="APP_NAME_0">%1$s</xliff:g> کو آپ کے <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> پر دکھائی دینے والی یا چلائی جانے والی کسی بھی چیز تک رسائی حاصل ہوگی، بشمول آڈیو، تصاویر، ادائیگی کی معلومات، پاس ورڈز اور پیغامات۔;lt;br/&gt;&lt;br/&amp;gt&amp;<xliff:g id="APP_NAME_1">%1$s</xliff:g> <xliff:g id="DEVICE_NAME">%3$s</xliff:g> پر اس وقت تک ایپس کی سلسلہ بندی کر سکے گی جب تک آپ اس اجازت تک رسائی کو ہٹا نہیں دیتے۔"</string>
+    <string name="helper_summary_app_streaming" msgid="1872657107404139828">"<xliff:g id="APP_NAME">%1$s</xliff:g> ایپ <xliff:g id="DEVICE_NAME">%2$s</xliff:g> کی جانب سے آپ کے <xliff:g id="DEVICE_TYPE">%3$s</xliff:g> سے ایپس اور سسٹم کی خصوصیات کی سلسلہ بندی کرنے کی اجازت کی درخواست کر رہی ہے"</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4782923323932440751">"‏‎&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;‎ کو آپ کے <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> سے ان معلومات تک رسائی حاصل کرنے کی اجازت دیں"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
     <string name="helper_summary_computer" msgid="2298803016482139668">"<xliff:g id="APP_NAME">%1$s</xliff:g> ایپ آپ کے <xliff:g id="DEVICE_NAME">%2$s</xliff:g> کی جانب سے آپ کے <xliff:g id="DEVICE_TYPE">%3$s</xliff:g> کی تصاویر، میڈیا اور اطلاعات تک رسائی کی اجازت کی درخواست کر رہی ہے"</string>
-    <string name="title_nearby_device_streaming" msgid="4295322493408411976">"‏‎&lt;strong&gt;<xliff:g id="DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt;‎ کو آپ کے <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> کی ایپس اور سسٹم کی خصوصیات کو ‎&lt;strong&gt;<xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>&lt;/strong&gt;‎ پر سلسلہ بندی کرنے کی اجازت دیں؟"</string>
-    <string name="summary_nearby_device_streaming" msgid="962267343109051648">"‏<xliff:g id="APP_NAME_0">%1$s</xliff:g> کو آپ کے <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> پر دکھائی دینے والی یا چلائی جانے والی کسی بھی چیز تک رسائی حاصل ہوگی، بشمول آڈیو، تصاویر، ادائیگی کی معلومات، پاس ورڈز اور پیغامات۔;lt;br/&gt;&lt;br/&amp;gt&amp;<xliff:g id="APP_NAME_1">%1$s</xliff:g> <xliff:g id="DEVICE_NAME">%3$s</xliff:g> پر اس وقت تک ایپس اور سسٹم کی خصوصیات کی سلسلہ بندی کر سکے گی جب تک آپ اس اجازت تک رسائی کو ہٹا نہیں دیتے۔"</string>
-    <string name="helper_summary_nearby_device_streaming" msgid="8509848562931818793">"<xliff:g id="APP_NAME">%1$s</xliff:g> ایپ آپ کے <xliff:g id="DEVICE_NAME">%2$s</xliff:g> کی جانب سے آپ کے آلات کے درمیان ایپس اور سسٹم کی دیگر خصوصیات کی سلسلہ بندی کرنے کی اجازت کی درخواست کر رہی ہے"</string>
+    <string name="title_nearby_device_streaming" msgid="2727103756701741359">"‏&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; کو آپ کے <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> کی ایپس کو <xliff:g id="DEVICE_NAME">%3$s</xliff:g> پر سلسلہ بندی کرنے کی اجازت دیں؟"</string>
+    <string name="summary_nearby_device_streaming" msgid="70434958004946884">"‏<xliff:g id="APP_NAME_0">%1$s</xliff:g> کو <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g> پر دکھائی دینے والی یا چلائی جانے والی کسی بھی چیز تک رسائی حاصل ہوگی، بشمول آڈیو، تصاویر، ادائیگی کی معلومات، پاس ورڈز اور پیغامات۔&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_2">%1$s</xliff:g> <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> پر اس وقت تک ایپس کی سلسلہ بندی کر سکے گی جب تک آپ اس اجازت تک رسائی کو ہٹا نہیں دیتے۔"</string>
+    <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"<xliff:g id="APP_NAME">%1$s</xliff:g> ایپ <xliff:g id="DEVICE_NAME">%2$s</xliff:g> کی جانب سے آپ کے <xliff:g id="DEVICE_TYPE">%3$s</xliff:g> سے ایپس کی سلسلہ بندی کرنے کی اجازت کی درخواست کر رہی ہے"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"آلہ"</string>
     <string name="summary_generic" msgid="1761976003668044801">"یہ ایپ آپ کے فون اور منتخب کردہ آلے کے درمیان معلومات، جیسے کسی کال کرنے والے کے نام، کی مطابقت پذیری کر سکے گی"</string>
     <string name="consent_yes" msgid="8344487259618762872">"اجازت دیں"</string>
diff --git a/packages/CompanionDeviceManager/res/values-uz/strings.xml b/packages/CompanionDeviceManager/res/values-uz/strings.xml
index f7a1ef7..3335551 100644
--- a/packages/CompanionDeviceManager/res/values-uz/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-uz/strings.xml
@@ -25,17 +25,17 @@
     <string name="confirmation_title_glasses" msgid="8288346850537727333">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ilovasiga &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; qurilmasini boshqarish uchun ruxsat berilsinmi?"</string>
     <string name="profile_name_glasses" msgid="3506504967216601277">"qurilma"</string>
     <string name="summary_glasses" msgid="5469208629679579157">"Bu ilova <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> qurilmasida quyidagi ruxsatlarni oladi"</string>
-    <string name="title_app_streaming" msgid="6845373585257287200">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>dagi ilovalarni &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt; qurilmasiga striming qilishiga ruxsat berasizmi?"</string>
-    <string name="summary_app_streaming" msgid="1274464413649731829">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>da koʻrinadigan yoki ijro etiladigan hamma narsaga, jumladan, audio, rasmlar, parollar va xabarlarga kirish huquqini oladi.&lt;br/&gt;&lt;br/&gt;Bu ruxsatni olib tashlamaguningizcha, <xliff:g id="APP_NAME_1">%1$s</xliff:g> ilovalarni <xliff:g id="DEVICE_NAME">%3$s</xliff:g> qurilmasiga striming qila oladi."</string>
-    <string name="helper_summary_app_streaming" msgid="1944832605534698562">"<xliff:g id="APP_NAME">%1$s</xliff:g> ilovasi <xliff:g id="DEVICE_NAME">%2$s</xliff:g> nomidan ilovalarni koʻrsatish va striming qilishga ruxsat soʻramoqda"</string>
+    <string name="title_app_streaming" msgid="1047090167914857893">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>dagi ilovalar va tizim funksiyalarini &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt; qurilmasiga striming qilishiga ruxsat berasizmi?"</string>
+    <string name="summary_app_streaming" msgid="7990244299655610920">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>da koʻrinadigan yoki ijro etiladigan hamma narsaga, jumladan, audio, rasmlar, toʻlov axboroti, parollar va xabarlarga kirish huquqini oladi.&lt;br/&gt;&lt;br/&gt;Bu ruxsatni olib tashlamaguningizcha, <xliff:g id="APP_NAME_1">%1$s</xliff:g> ilovalarni <xliff:g id="DEVICE_NAME">%3$s</xliff:g> qurilmasiga striming qila oladi."</string>
+    <string name="helper_summary_app_streaming" msgid="1872657107404139828">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="DEVICE_NAME">%2$s</xliff:g> nomidan <xliff:g id="DEVICE_TYPE">%3$s</xliff:g> orqali ilovalar va tizim funksiyalarini uzatish uchun ruxsat olmoqchi"</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4782923323932440751">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ilovasiga <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>dagi ushbu maʼlumot uchun ruxsat bering"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
     <string name="helper_summary_computer" msgid="2298803016482139668">"<xliff:g id="APP_NAME">%1$s</xliff:g> ilovasi <xliff:g id="DEVICE_NAME">%2$s</xliff:g> nomidan <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>dagi suratlar, media va bildirishnomalarga kirish uchun ruxsat soʻramoqda"</string>
-    <string name="title_nearby_device_streaming" msgid="4295322493408411976">"&lt;strong&gt;<xliff:g id="DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt; <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>dagi ilovalar va tizim funksiyalarini &lt;strong&gt;<xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>&lt;/strong&gt; qurilmasiga striming qilishiga ruxsat berasizmi?"</string>
-    <string name="summary_nearby_device_streaming" msgid="962267343109051648">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>da koʻrinadigan yoki ijro etiladigan hamma narsaga, jumladan, audio, rasmlar, toʻlov axboroti, parollar va xabarlarga kirish huquqini oladi.&lt;br/&gt;&lt;br/&gt;Bu ruxsatni olib tashlamaguningizcha, <xliff:g id="APP_NAME_1">%1$s</xliff:g> ilovalarni va tizim funksiyalarini <xliff:g id="DEVICE_NAME">%3$s</xliff:g> qurilmasiga striming qila oladi."</string>
-    <string name="helper_summary_nearby_device_streaming" msgid="8509848562931818793">"<xliff:g id="APP_NAME">%1$s</xliff:g> qurilmalaringiz orasida ilovalar va boshqa tizim funksiyalarini striming qilish uchun <xliff:g id="DEVICE_NAME">%2$s</xliff:g> nomidan ruxsat soʻramoqda"</string>
+    <string name="title_nearby_device_streaming" msgid="2727103756701741359">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>dagi ilovalarni &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt; qurilmasiga striming qilishiga ruxsat berasizmi?"</string>
+    <string name="summary_nearby_device_streaming" msgid="70434958004946884">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>da koʻrinadigan yoki ijro etiladigan hamma narsaga, jumladan, audio, rasmlar, parollar va xabarlarga kirish huquqini oladi.&lt;br/&gt;&lt;br/&gt;Bu ruxsatni olib tashlamaguningizcha, <xliff:g id="APP_NAME_2">%1$s</xliff:g> ilovalarni <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> qurilmasiga striming qila oladi."</string>
+    <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="DEVICE_NAME">%2$s</xliff:g> nomidan <xliff:g id="DEVICE_TYPE">%3$s</xliff:g> orqali ilovalarni uzatish uchun ruxsat olmoqchi"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"qurilma"</string>
     <string name="summary_generic" msgid="1761976003668044801">"Bu ilova telefoningiz va tanlangan qurilmada chaqiruvchining ismi kabi maʼlumotlarni sinxronlay oladi"</string>
     <string name="consent_yes" msgid="8344487259618762872">"Ruxsat"</string>
diff --git a/packages/CompanionDeviceManager/res/values-vi/strings.xml b/packages/CompanionDeviceManager/res/values-vi/strings.xml
index e668a69..7f6d5b1 100644
--- a/packages/CompanionDeviceManager/res/values-vi/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-vi/strings.xml
@@ -25,17 +25,17 @@
     <string name="confirmation_title_glasses" msgid="8288346850537727333">"Cho phép &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; quản lý &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
     <string name="profile_name_glasses" msgid="3506504967216601277">"thiết bị"</string>
     <string name="summary_glasses" msgid="5469208629679579157">"Ứng dụng này sẽ được phép dùng những quyền sau trên <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> của bạn"</string>
-    <string name="title_app_streaming" msgid="6845373585257287200">"Cho phép &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; truyền trực tuyến các ứng dụng trên <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> của bạn đến &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;?"</string>
-    <string name="summary_app_streaming" msgid="1274464413649731829">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> sẽ có quyền truy cập vào mọi nội dung hiển thị hoặc phát trên <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>, bao gồm cả âm thanh, ảnh, mật khẩu và tin nhắn.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_1">%1$s</xliff:g> sẽ có thể truyền trực tuyến các ứng dụng đến <xliff:g id="DEVICE_NAME">%3$s</xliff:g> cho đến khi bạn thu hồi quyền này."</string>
-    <string name="helper_summary_app_streaming" msgid="1944832605534698562">"<xliff:g id="APP_NAME">%1$s</xliff:g> đang yêu cầu quyền thay cho <xliff:g id="DEVICE_NAME">%2$s</xliff:g> để hiển thị và truyền trực tuyến các ứng dụng giữa các thiết bị của bạn"</string>
+    <string name="title_app_streaming" msgid="1047090167914857893">"Cho phép &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; truyền trực tuyến các ứng dụng và tính năng của hệ thống trên <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> của bạn đến &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;?"</string>
+    <string name="summary_app_streaming" msgid="7990244299655610920">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> sẽ có quyền truy cập vào mọi nội dung hiển thị hoặc phát trên <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> của bạn, bao gồm cả âm thanh, ảnh, thông tin thanh toán, mật khẩu và tin nhắn.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_1">%1$s</xliff:g> sẽ có thể truyền trực tuyến các ứng dụng đến <xliff:g id="DEVICE_NAME">%3$s</xliff:g> cho đến khi bạn thu hồi quyền này."</string>
+    <string name="helper_summary_app_streaming" msgid="1872657107404139828">"<xliff:g id="APP_NAME">%1$s</xliff:g> đang yêu cầu quyền thay cho <xliff:g id="DEVICE_NAME">%2$s</xliff:g> để truyền trực tuyến các ứng dụng và tính năng của hệ thống từ <xliff:g id="DEVICE_TYPE">%3$s</xliff:g> của bạn"</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4782923323932440751">"Cho phép &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; truy cập vào thông tin này trên <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> của bạn"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
     <string name="helper_summary_computer" msgid="2298803016482139668">"<xliff:g id="APP_NAME">%1$s</xliff:g> đang yêu cầu quyền thay cho <xliff:g id="DEVICE_NAME">%2$s</xliff:g> để truy cập vào ảnh, nội dung nghe nhìn và thông báo trên <xliff:g id="DEVICE_TYPE">%3$s</xliff:g> của bạn"</string>
-    <string name="title_nearby_device_streaming" msgid="4295322493408411976">"Cho phép &lt;strong&gt;<xliff:g id="DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt; truyền trực tuyến các ứng dụng và tính năng của hệ thống trên <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> của bạn đến &lt;strong&gt;<xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>&lt;/strong&gt;?"</string>
-    <string name="summary_nearby_device_streaming" msgid="962267343109051648">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> sẽ có quyền truy cập vào mọi nội dung hiển thị hoặc phát trên <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> của bạn, bao gồm cả âm thanh, ảnh, thông tin thanh toán, mật khẩu và tin nhắn.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_1">%1$s</xliff:g> sẽ có thể truyền trực tuyến các ứng dụng và tính năng của hệ thống đến <xliff:g id="DEVICE_NAME">%3$s</xliff:g> cho đến khi bạn thu hồi quyền này."</string>
-    <string name="helper_summary_nearby_device_streaming" msgid="8509848562931818793">"<xliff:g id="APP_NAME">%1$s</xliff:g> đang yêu cầu quyền thay cho <xliff:g id="DEVICE_NAME">%2$s</xliff:g> để truyền trực tuyến các ứng dụng và những tính năng khác của hệ thống giữa các thiết bị của bạn"</string>
+    <string name="title_nearby_device_streaming" msgid="2727103756701741359">"Cho phép &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; truyền trực tuyến các ứng dụng trên <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> của bạn đến &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;?"</string>
+    <string name="summary_nearby_device_streaming" msgid="70434958004946884">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> sẽ có quyền truy cập vào mọi nội dung hiển thị hoặc phát trên <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>, bao gồm cả âm thanh, ảnh, thông tin thanh toán, mật khẩu và tin nhắn.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_2">%1$s</xliff:g> sẽ có thể truyền trực tuyến các ứng dụng đến <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> cho đến khi bạn thu hồi quyền này."</string>
+    <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"<xliff:g id="APP_NAME">%1$s</xliff:g> đang yêu cầu quyền thay cho <xliff:g id="DEVICE_NAME">%2$s</xliff:g> để truyền trực tuyến các ứng dụng từ <xliff:g id="DEVICE_TYPE">%3$s</xliff:g> của bạn"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"thiết bị"</string>
     <string name="summary_generic" msgid="1761976003668044801">"Ứng dụng này sẽ đồng bộ hoá thông tin (ví dụ: tên người gọi) giữa điện thoại của bạn và thiết bị bạn chọn"</string>
     <string name="consent_yes" msgid="8344487259618762872">"Cho phép"</string>
diff --git a/packages/CompanionDeviceManager/res/values-zh-rCN/strings.xml b/packages/CompanionDeviceManager/res/values-zh-rCN/strings.xml
index 8adb160..c54c452 100644
--- a/packages/CompanionDeviceManager/res/values-zh-rCN/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-zh-rCN/strings.xml
@@ -25,17 +25,17 @@
     <string name="confirmation_title_glasses" msgid="8288346850537727333">"允许&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;管理&lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
     <string name="profile_name_glasses" msgid="3506504967216601277">"设备"</string>
     <string name="summary_glasses" msgid="5469208629679579157">"该应用将能获得您<xliff:g id="DEVICE_TYPE">%1$s</xliff:g>上的以下权限"</string>
-    <string name="title_app_streaming" msgid="6845373585257287200">"允许&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;将您<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>上的应用流式传输到&lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;吗?"</string>
-    <string name="summary_app_streaming" msgid="1274464413649731829">"“<xliff:g id="APP_NAME_0">%1$s</xliff:g>”将能访问<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>上可见或播放的任何内容,包括音频、照片、密码和消息。&lt;br/&gt;&lt;br/&gt;“<xliff:g id="APP_NAME_1">%1$s</xliff:g>”能将应用流式传输到“<xliff:g id="DEVICE_NAME">%3$s</xliff:g>”,除非您撤消此访问权限。"</string>
-    <string name="helper_summary_app_streaming" msgid="1944832605534698562">"“<xliff:g id="APP_NAME">%1$s</xliff:g>”正代表您的“<xliff:g id="DEVICE_NAME">%2$s</xliff:g>”请求在设备之间显示和流式传输应用"</string>
+    <string name="title_app_streaming" msgid="1047090167914857893">"允许&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;将您的<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>上的应用和系统功能流式传输到&lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;吗?"</string>
+    <string name="summary_app_streaming" msgid="7990244299655610920">"“<xliff:g id="APP_NAME_0">%1$s</xliff:g>”将能够访问您的<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>上显示或播放的任何内容,包括音频、照片、付款信息、密码和消息。&lt;br/&gt;&lt;br/&gt;“<xliff:g id="APP_NAME_1">%1$s</xliff:g>”可将应用流式传输到“<xliff:g id="DEVICE_NAME">%3$s</xliff:g>”,除非您撤消此访问权限。"</string>
+    <string name="helper_summary_app_streaming" msgid="1872657107404139828">"“<xliff:g id="APP_NAME">%1$s</xliff:g>”正代表“<xliff:g id="DEVICE_NAME">%2$s</xliff:g>”请求获得从您的<xliff:g id="DEVICE_TYPE">%3$s</xliff:g>流式传输应用和系统功能的权限"</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4782923323932440751">"允许&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;访问您<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>中的这项信息"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
     <string name="helper_summary_computer" msgid="2298803016482139668">"“<xliff:g id="APP_NAME">%1$s</xliff:g>”正代表您的“<xliff:g id="DEVICE_NAME">%2$s</xliff:g>”请求访问您<xliff:g id="DEVICE_TYPE">%3$s</xliff:g>上的照片、媒体内容和通知"</string>
-    <string name="title_nearby_device_streaming" msgid="4295322493408411976">"允许&lt;strong&gt;<xliff:g id="DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt;将您<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>上的应用和系统功能流式传输到&lt;strong&gt;<xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>&lt;/strong&gt;吗?"</string>
-    <string name="summary_nearby_device_streaming" msgid="962267343109051648">"“<xliff:g id="APP_NAME_0">%1$s</xliff:g>”将能访问您<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>上可见或播放的任何内容,包括音频、照片、付款信息、密码和消息。&lt;br/&gt;&lt;br/&gt;“<xliff:g id="APP_NAME_1">%1$s</xliff:g>”能将应用和系统功能流式传输到“<xliff:g id="DEVICE_NAME">%3$s</xliff:g>”,除非您撤消此访问权限。"</string>
-    <string name="helper_summary_nearby_device_streaming" msgid="8509848562931818793">"“<xliff:g id="APP_NAME">%1$s</xliff:g>”正代表您的“<xliff:g id="DEVICE_NAME">%2$s</xliff:g>”请求在设备之间流式传输应用和其他系统功能"</string>
+    <string name="title_nearby_device_streaming" msgid="2727103756701741359">"允许&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;将您的<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>上的应用流式传输到&lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;吗?"</string>
+    <string name="summary_nearby_device_streaming" msgid="70434958004946884">"“<xliff:g id="APP_NAME_0">%1$s</xliff:g>”将能够访问“<xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>”上显示或播放的任何内容,包括音频、照片、付款信息、密码和消息。&lt;br/&gt;&lt;br/&gt;“<xliff:g id="APP_NAME_2">%1$s</xliff:g>”可将应用流式传输到“<xliff:g id="DEVICE_NAME_3">%3$s</xliff:g>”,除非您撤消此访问权限。"</string>
+    <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"“<xliff:g id="APP_NAME">%1$s</xliff:g>”正代表“<xliff:g id="DEVICE_NAME">%2$s</xliff:g>”请求获得从您的<xliff:g id="DEVICE_TYPE">%3$s</xliff:g>流式传输应用的权限"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"设备"</string>
     <string name="summary_generic" msgid="1761976003668044801">"此应用将能在您的手机和所选设备之间同步信息,例如来电者的姓名"</string>
     <string name="consent_yes" msgid="8344487259618762872">"允许"</string>
diff --git a/packages/CompanionDeviceManager/res/values-zh-rHK/strings.xml b/packages/CompanionDeviceManager/res/values-zh-rHK/strings.xml
index fee37dd..e47dfa0 100644
--- a/packages/CompanionDeviceManager/res/values-zh-rHK/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-zh-rHK/strings.xml
@@ -25,17 +25,17 @@
     <string name="confirmation_title_glasses" msgid="8288346850537727333">"要允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」&lt;strong&gt;&lt;/strong&gt;管理「<xliff:g id="DEVICE_NAME">%2$s</xliff:g>」&lt;strong&gt;&lt;/strong&gt;嗎?"</string>
     <string name="profile_name_glasses" msgid="3506504967216601277">"裝置"</string>
     <string name="summary_glasses" msgid="5469208629679579157">"此應用程式將可在<xliff:g id="DEVICE_TYPE">%1$s</xliff:g>上取得以下權限"</string>
-    <string name="title_app_streaming" msgid="6845373585257287200">"要允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」串流<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>應用程式內容至「<xliff:g id="DEVICE_NAME">%3$s</xliff:g>」嗎?"</string>
-    <string name="summary_app_streaming" msgid="1274464413649731829">"「<xliff:g id="APP_NAME_0">%1$s</xliff:g>」將能存取<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>上顯示或播放的任何內容,包括音訊、相片、密碼和訊息。&lt;br/&gt;&lt;br/&gt;「<xliff:g id="APP_NAME_1">%1$s</xliff:g>」將能串流應用程式內容至「<xliff:g id="DEVICE_NAME">%3$s</xliff:g>」,直至你移除此存取權限為止。"</string>
-    <string name="helper_summary_app_streaming" msgid="1944832605534698562">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」正在代表「<xliff:g id="DEVICE_NAME">%2$s</xliff:g>」要求權限,以便在裝置間顯示和串流應用程式的內容"</string>
+    <string name="title_app_streaming" msgid="1047090167914857893">"要允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」串流<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>應用程式內容和系統功能至 <xliff:g id="DEVICE_NAME">%3$s</xliff:g> 嗎?"</string>
+    <string name="summary_app_streaming" msgid="7990244299655610920">"「<xliff:g id="APP_NAME_0">%1$s</xliff:g>」將能存取<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>上顯示或播放的任何內容,包括音訊、相片、付款資料、密碼和訊息。&lt;br/&gt;&lt;br/&gt;「<xliff:g id="APP_NAME_1">%1$s</xliff:g>」將能串流應用程式內容至 <xliff:g id="DEVICE_NAME">%3$s</xliff:g>,直至你移除此存取權限為止。"</string>
+    <string name="helper_summary_app_streaming" msgid="1872657107404139828">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」正在代表 <xliff:g id="DEVICE_NAME">%2$s</xliff:g> 要求權限,以便從你的<xliff:g id="DEVICE_TYPE">%3$s</xliff:g>串流應用程式內容和系統功能"</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4782923323932440751">"允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」在<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>上存取這項資料"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
     <string name="helper_summary_computer" msgid="2298803016482139668">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」正在代表「<xliff:g id="DEVICE_NAME">%2$s</xliff:g>」要求權限,以便存取<xliff:g id="DEVICE_TYPE">%3$s</xliff:g>上的相片、媒體和通知"</string>
-    <string name="title_nearby_device_streaming" msgid="4295322493408411976">"要允許「<xliff:g id="DEVICE_NAME_0">%1$s</xliff:g>」串流<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>應用程式內容和系統功能至「<xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>」嗎?"</string>
-    <string name="summary_nearby_device_streaming" msgid="962267343109051648">"「<xliff:g id="APP_NAME_0">%1$s</xliff:g>」將能存取<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>上顯示或播放的任何內容,包括音訊、相片、付款資料、密碼和訊息。&lt;br/&gt;&lt;br/&gt;「<xliff:g id="APP_NAME_1">%1$s</xliff:g>」將能串流應用程式內容和系統功能至「<xliff:g id="DEVICE_NAME">%3$s</xliff:g>」,直至你移除此存取權限為止。"</string>
-    <string name="helper_summary_nearby_device_streaming" msgid="8509848562931818793">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」正在代表「<xliff:g id="DEVICE_NAME">%2$s</xliff:g>」要求權限,以便在裝置間串流應用程式內容和其他系統功能"</string>
+    <string name="title_nearby_device_streaming" msgid="2727103756701741359">"要允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」串流<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>應用程式內容至 <xliff:g id="DEVICE_NAME">%3$s</xliff:g> 嗎?"</string>
+    <string name="summary_nearby_device_streaming" msgid="70434958004946884">"「<xliff:g id="APP_NAME_0">%1$s</xliff:g>」將能存取「<xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>」上顯示或播放的任何內容,包括音訊、相片、付款資料、密碼和訊息。&lt;br/&gt;&lt;br/&gt;「<xliff:g id="APP_NAME_2">%1$s</xliff:g>」將能串流應用程式內容至 <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g>,直至你移除此存取權限為止。"</string>
+    <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」正在代表 <xliff:g id="DEVICE_NAME">%2$s</xliff:g> 要求權限,以便從你的<xliff:g id="DEVICE_TYPE">%3$s</xliff:g>串流應用程式內容"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"裝置"</string>
     <string name="summary_generic" msgid="1761976003668044801">"此應用程式將可同步手機和所選裝置的資訊,例如來電者的名稱"</string>
     <string name="consent_yes" msgid="8344487259618762872">"允許"</string>
diff --git a/packages/CompanionDeviceManager/res/values-zh-rTW/strings.xml b/packages/CompanionDeviceManager/res/values-zh-rTW/strings.xml
index 28a3baf..b91024a 100644
--- a/packages/CompanionDeviceManager/res/values-zh-rTW/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-zh-rTW/strings.xml
@@ -25,17 +25,17 @@
     <string name="confirmation_title_glasses" msgid="8288346850537727333">"要允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」&lt;strong&gt;&lt;/strong&gt;管理「<xliff:g id="DEVICE_NAME">%2$s</xliff:g>」&lt;strong&gt;&lt;/strong&gt;嗎?"</string>
     <string name="profile_name_glasses" msgid="3506504967216601277">"裝置"</string>
     <string name="summary_glasses" msgid="5469208629679579157">"這個應用程式將可取得<xliff:g id="DEVICE_TYPE">%1$s</xliff:g>上的這些權限"</string>
-    <string name="title_app_streaming" msgid="6845373585257287200">"要允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」&lt;strong&gt;&lt;/strong&gt;將<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>的應用程式串流傳輸到 &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt; 嗎?"</string>
-    <string name="summary_app_streaming" msgid="1274464413649731829">"「<xliff:g id="APP_NAME_0">%1$s</xliff:g>」將可存取<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>顯示或播放的所有內容,包括音訊、相片、密碼和訊息。&lt;br/&gt;&lt;br/&gt;「<xliff:g id="APP_NAME_1">%1$s</xliff:g>」可將應用程式串流傳輸到 <xliff:g id="DEVICE_NAME">%3$s</xliff:g>,直到你移除這個權限為止。"</string>
-    <string name="helper_summary_app_streaming" msgid="1944832605534698562">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」正在代表你的 <xliff:g id="DEVICE_NAME">%2$s</xliff:g> 要求必要權限,以便在裝置間顯示及串流傳輸應用程式"</string>
+    <string name="title_app_streaming" msgid="1047090167914857893">"要允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」&lt;strong&gt;&lt;/strong&gt;將<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>的應用程式和系統功能串流傳輸到 &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt; 嗎?"</string>
+    <string name="summary_app_streaming" msgid="7990244299655610920">"「<xliff:g id="APP_NAME_0">%1$s</xliff:g>」將可存取<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>顯示或播放的所有內容,包括音訊、相片、付款資訊、密碼和訊息。&lt;br/&gt;&lt;br/&gt;「<xliff:g id="APP_NAME_1">%1$s</xliff:g>」可將應用程式串流傳輸到 <xliff:g id="DEVICE_NAME">%3$s</xliff:g>,直到你移除這個權限為止。"</string>
+    <string name="helper_summary_app_streaming" msgid="1872657107404139828">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」正在代表 <xliff:g id="DEVICE_NAME">%2$s</xliff:g> 要求必要權限,以便從<xliff:g id="DEVICE_TYPE">%3$s</xliff:g>串流傳輸應用程式和系統功能"</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4782923323932440751">"允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」&lt;strong&gt;&lt;/strong&gt;存取<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>中的這項資訊"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
     <string name="helper_summary_computer" msgid="2298803016482139668">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」正在代表你的 <xliff:g id="DEVICE_NAME">%2$s</xliff:g> 要求必要權限,以便存取<xliff:g id="DEVICE_TYPE">%3$s</xliff:g>上的相片、媒體和通知"</string>
-    <string name="title_nearby_device_streaming" msgid="4295322493408411976">"要允許「<xliff:g id="DEVICE_NAME_0">%1$s</xliff:g>」&lt;strong&gt;&lt;/strong&gt;將<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>的應用程式和系統功能串流傳輸到 &lt;strong&gt;<xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>&lt;/strong&gt; 嗎?"</string>
-    <string name="summary_nearby_device_streaming" msgid="962267343109051648">"「<xliff:g id="APP_NAME_0">%1$s</xliff:g>」將可存取<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>顯示或播放的所有內容,包括音訊、相片、付款資訊、密碼和訊息。&lt;br/&gt;&lt;br/&gt;「<xliff:g id="APP_NAME_1">%1$s</xliff:g>」可將應用程式和系統功能串流傳輸到 <xliff:g id="DEVICE_NAME">%3$s</xliff:g>,直到你移除這個權限為止。"</string>
-    <string name="helper_summary_nearby_device_streaming" msgid="8509848562931818793">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」正在代表 <xliff:g id="DEVICE_NAME">%2$s</xliff:g> 要求必要權限,以便在裝置間串流傳輸應用程式和其他系統功能"</string>
+    <string name="title_nearby_device_streaming" msgid="2727103756701741359">"要允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」&lt;strong&gt;&lt;/strong&gt;將<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>的應用程式串流傳輸到 &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt; 嗎?"</string>
+    <string name="summary_nearby_device_streaming" msgid="70434958004946884">"「<xliff:g id="APP_NAME_0">%1$s</xliff:g>」將可存取 <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g> 顯示或播放的所有內容,包括音訊、相片、付款資訊、密碼和訊息。&lt;br/&gt;&lt;br/&gt;「<xliff:g id="APP_NAME_2">%1$s</xliff:g>」可將應用程式串流傳輸到 <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g>,直到你移除這個權限為止。"</string>
+    <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」正在代表 <xliff:g id="DEVICE_NAME">%2$s</xliff:g> 要求必要權限,以便從<xliff:g id="DEVICE_TYPE">%3$s</xliff:g>串流傳輸應用程式"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"裝置"</string>
     <string name="summary_generic" msgid="1761976003668044801">"這個應用程式將可在手機和指定裝置間同步資訊,例如來電者名稱"</string>
     <string name="consent_yes" msgid="8344487259618762872">"允許"</string>
diff --git a/packages/CompanionDeviceManager/res/values-zu/strings.xml b/packages/CompanionDeviceManager/res/values-zu/strings.xml
index 5966f8b..160332e 100644
--- a/packages/CompanionDeviceManager/res/values-zu/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-zu/strings.xml
@@ -25,17 +25,17 @@
     <string name="confirmation_title_glasses" msgid="8288346850537727333">"Vumela i-&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ukuthi ifinyelele i-&lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="profile_name_glasses" msgid="3506504967216601277">"idivayisi"</string>
     <string name="summary_glasses" msgid="5469208629679579157">"Le-app izovunyelwa ukufinyelela lezi zimvume ku-<xliff:g id="DEVICE_TYPE">%1$s</xliff:g> yakho"</string>
-    <string name="title_app_streaming" msgid="6845373585257287200">"Vumela &lt;strong&gt;i-<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ukuze isakaze ama-app e-<xliff:g id="DEVICE_TYPE">%2$s</xliff:g> yakho &lt;strong&gt;ku-<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;?"</string>
-    <string name="summary_app_streaming" msgid="1274464413649731829">"I-<xliff:g id="APP_NAME_0">%1$s</xliff:g> izokwazi ukufinyelela kunoma yini ebonakalayo noma edlalwayo ku-<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>, okuhlanganisa umsindo, izithombe, amaphasiwedi, nemilayezo.&lt;br/&gt;&lt;br/&gt;I-<xliff:g id="APP_NAME_1">%1$s</xliff:g> izokwazi ukusakaza ama-app ku-<xliff:g id="DEVICE_NAME">%3$s</xliff:g> uze ususe ukufinyelela kule mvume."</string>
-    <string name="helper_summary_app_streaming" msgid="1944832605534698562">"I-<xliff:g id="APP_NAME">%1$s</xliff:g> icela imvume esikhundleni se-<xliff:g id="DEVICE_NAME">%2$s</xliff:g> yakho yokubonisa nokusakaza ama-app phakathi kwamadivayisi wakho"</string>
+    <string name="title_app_streaming" msgid="1047090167914857893">"Vumela &lt;strong&gt;i-<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ukuba isakaze ama-app e-<xliff:g id="DEVICE_TYPE">%2$s</xliff:g> yakho nezakhi zesistimu &lt;strong&gt;ku-<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;?"</string>
+    <string name="summary_app_streaming" msgid="7990244299655610920">"I-<xliff:g id="APP_NAME_0">%1$s</xliff:g> izokwazi ukufinyelela kunoma yini ebonakalayo noma edlalwayo ku-<xliff:g id="DEVICE_TYPE">%2$s</xliff:g> yakho, okuhlanganisa umsindo, izithombe, ulwazi lokukhokha, amaphasiwedi, nemilayezo.&lt;br/&gt;&lt;br/&gt;I-<xliff:g id="APP_NAME_1">%1$s</xliff:g> izokwazi ukusakaza ama-app ku-<xliff:g id="DEVICE_NAME">%3$s</xliff:g> uze ususe ukufinyelela kule mvume."</string>
+    <string name="helper_summary_app_streaming" msgid="1872657107404139828">"I-<xliff:g id="APP_NAME">%1$s</xliff:g> icela imvume esikhundleni se-<xliff:g id="DEVICE_NAME">%2$s</xliff:g> ukuze isakaze ama-app nezakhi zesistimu ukusuka ku-<xliff:g id="DEVICE_TYPE">%3$s</xliff:g> yakho"</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4782923323932440751">"Vumela &lt;strong&gt;i-<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ukuze ifinyelele lolu lwazi ukusuka ku-<xliff:g id="DEVICE_TYPE">%2$s</xliff:g> yakho"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
     <string name="helper_summary_computer" msgid="2298803016482139668">"I-<xliff:g id="APP_NAME">%1$s</xliff:g> icela imvume esikhundleni se-<xliff:g id="DEVICE_NAME">%2$s</xliff:g> yakho ukuze ifinyelele izithombe ze-<xliff:g id="DEVICE_TYPE">%3$s</xliff:g> yakho, imidiya nezaziso"</string>
-    <string name="title_nearby_device_streaming" msgid="4295322493408411976">"Vumela &lt;strong&gt;i-<xliff:g id="DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt; ukuze isakaze ama-app e-<xliff:g id="DEVICE_TYPE">%2$s</xliff:g> yakho nezakhi zesistimu &lt;strong&gt;ku-<xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>&lt;/strong&gt;?"</string>
-    <string name="summary_nearby_device_streaming" msgid="962267343109051648">"I-<xliff:g id="APP_NAME_0">%1$s</xliff:g> izokwazi ukufinyelela kunoma yini ebonakalayo noma edlalwayo ku-<xliff:g id="DEVICE_TYPE">%2$s</xliff:g> yakho, okuhlanganisa umsindo, izithombe, ulwazi lokukhokha, amaphasiwedi, nemilayezo.&lt;br/&gt;&lt;br/&gt;I-<xliff:g id="APP_NAME_1">%1$s</xliff:g> izokwazi ukusakaza ama-app nezakhi zesistimu ku-<xliff:g id="DEVICE_NAME">%3$s</xliff:g> uze ususe ukufinyelela kule mvume."</string>
-    <string name="helper_summary_nearby_device_streaming" msgid="8509848562931818793">"I-<xliff:g id="APP_NAME">%1$s</xliff:g> icela imvume esikhundleni se-<xliff:g id="DEVICE_NAME">%2$s</xliff:g> yakho ukuze isakaze ama-app nezinye zakhi zesistimu phakathi kwamadivayisi wakho"</string>
+    <string name="title_nearby_device_streaming" msgid="2727103756701741359">"Vumela &lt;strong&gt;i-<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ukuze isakaze ama-app e-<xliff:g id="DEVICE_TYPE">%2$s</xliff:g> yakho &lt;strong&gt;ku-<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;?"</string>
+    <string name="summary_nearby_device_streaming" msgid="70434958004946884">"I-<xliff:g id="APP_NAME_0">%1$s</xliff:g> izokwazi ukufinyelela kunoma yini ebonakalayo noma edlalwayo ku-<xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>, okuhlanganisa umsindo, izithombe, ulwazi lokukhokha, amaphasiwedi, nemilayezo.&lt;br/&gt;&lt;br/&gt;I-<xliff:g id="APP_NAME_2">%1$s</xliff:g> izokwazi ukusakaza ama-app ku-<xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> uze ususe ukufinyelela kule mvume."</string>
+    <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"I-<xliff:g id="APP_NAME">%1$s</xliff:g> icela imvume esikhundleni se-<xliff:g id="DEVICE_NAME">%2$s</xliff:g> ukuze isakaze ama-app nezakhi ukusuka ku-<xliff:g id="DEVICE_TYPE">%3$s</xliff:g> yakho"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"idivayisi"</string>
     <string name="summary_generic" msgid="1761976003668044801">"Le app izokwazi ukuvumelanisa ulwazi, njengegama lomuntu othile ofonayo, phakathi kwefoni yakho nedivayisi ekhethiwe"</string>
     <string name="consent_yes" msgid="8344487259618762872">"Vumela"</string>
diff --git a/packages/CompanionDeviceManager/res/values/styles.xml b/packages/CompanionDeviceManager/res/values/styles.xml
index fe7cfc6..a161a50 100644
--- a/packages/CompanionDeviceManager/res/values/styles.xml
+++ b/packages/CompanionDeviceManager/res/values/styles.xml
@@ -137,4 +137,10 @@
         <item name="android:textAppearance">@android:style/TextAppearance.DeviceDefault.Medium</item>
     </style>
 
+    <style name="DeviceIcon">
+        <item name="android:layout_width">24dp</item>
+        <item name="android:layout_height">24dp</item>
+        <item name="android:layout_gravity">center</item>
+    </style>
+
 </resources>
\ No newline at end of file
diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionAssociationActivity.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionAssociationActivity.java
index 7974a37..50419f7 100644
--- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionAssociationActivity.java
+++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionAssociationActivity.java
@@ -61,6 +61,7 @@
 import android.graphics.BlendModeColorFilter;
 import android.graphics.Color;
 import android.graphics.drawable.Drawable;
+import android.graphics.drawable.Icon;
 import android.net.MacAddress;
 import android.os.Bundle;
 import android.os.Handler;
@@ -130,6 +131,8 @@
 
     // Present for single device and multiple device only.
     private ImageView mProfileIcon;
+    // Present for self managed association only;
+    private ImageView mDeviceIcon;
 
     // Only present for selfManaged devices.
     private ImageView mVendorHeaderImage;
@@ -260,8 +263,8 @@
     }
 
     @Override
-    protected void onStop() {
-        super.onStop();
+    protected void onDestroy() {
+        super.onDestroy();
 
         // TODO: handle config changes without cancelling.
         if (!isDone()) {
@@ -306,6 +309,8 @@
         mVendorHeaderName = findViewById(R.id.vendor_header_name);
         mVendorHeaderButton = findViewById(R.id.vendor_header_button);
 
+        mDeviceIcon = findViewById(R.id.device_icon);
+
         mDeviceListRecyclerView = findViewById(R.id.device_list);
 
         mMultipleDeviceSpinner = findViewById(R.id.spinner_multiple_device);
@@ -430,6 +435,7 @@
         final Drawable vendorIcon;
         final CharSequence vendorName;
         final Spanned title;
+        final Icon deviceIcon = mRequest.getDeviceIcon();
 
         if (!SUPPORTED_SELF_MANAGED_PROFILES.contains(deviceProfile)) {
             throw new RuntimeException("Unsupported profile " + deviceProfile);
@@ -452,6 +458,11 @@
         title = getHtmlFromResources(this, PROFILE_TITLES.get(deviceProfile), mAppLabel,
                 getString(R.string.device_type), deviceName);
 
+        if (deviceIcon != null) {
+            mDeviceIcon.setImageIcon(deviceIcon);
+            mDeviceIcon.setVisibility(View.VISIBLE);
+        }
+
         if (PROFILE_SUMMARIES.containsKey(deviceProfile)) {
             final int summaryResourceId = PROFILE_SUMMARIES.get(deviceProfile);
             final Spanned summary = getHtmlFromResources(this, summaryResourceId,
diff --git a/packages/CrashRecovery/adaptor/Android.bp b/packages/CrashRecovery/adaptor/Android.bp
new file mode 100644
index 0000000..df7c3dd
--- /dev/null
+++ b/packages/CrashRecovery/adaptor/Android.bp
@@ -0,0 +1,12 @@
+filegroup {
+    name: "crashrecovery-platform-adaptor-srcs",
+    srcs: select(soong_config_variable("ANDROID", "release_crashrecovery_module"), {
+        "true": [
+            "postModularization/java/**/*.java",
+        ],
+        default: [
+            "preModularization/java/**/*.java",
+        ],
+    }),
+    visibility: ["//frameworks/base:__subpackages__"],
+}
diff --git a/packages/CrashRecovery/adaptor/postModularization/java/com/android/server/crashrecovery/CrashRecoveryAdaptor.java b/packages/CrashRecovery/adaptor/postModularization/java/com/android/server/crashrecovery/CrashRecoveryAdaptor.java
new file mode 100644
index 0000000..b2d798e2
--- /dev/null
+++ b/packages/CrashRecovery/adaptor/postModularization/java/com/android/server/crashrecovery/CrashRecoveryAdaptor.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.crashrecovery;
+
+import android.content.Context;
+
+import com.android.server.PackageWatchdog;
+import com.android.server.SystemServiceManager;
+
+import java.util.List;
+
+/**
+ * This class mediates calls to hidden APIs in CrashRecovery module.
+ * This class is used when the CrashRecovery classes are moved to separate module.
+ *
+ * @hide
+ */
+public class CrashRecoveryAdaptor {
+    private static final String TAG = "CrashRecoveryAdaptor";
+    private static final String CRASHRECOVERY_MODULE_LIFECYCLE_CLASS =
+            "com.android.server.crashrecovery.CrashRecoveryModule$Lifecycle";
+
+    /**  Start CrashRecoveryModule LifeCycleService */
+    public static void initializeCrashrecoveryModuleService(
+            SystemServiceManager mSystemServiceManager) {
+        mSystemServiceManager.startService(CRASHRECOVERY_MODULE_LIFECYCLE_CLASS);
+    }
+
+    /**  Does Nothing */
+    public static void packageWatchdogNoteBoot(Context mSystemContext) {
+        // do nothing
+    }
+
+    /**  Does Nothing */
+    public static void packageWatchdogWriteNow(Context mContext) {
+        // do nothing
+    }
+
+    /**  Does Nothing */
+    public static void packageWatchdogOnPackagesReady(PackageWatchdog mPackageWatchdog) {
+        // do nothing
+    }
+
+    /**  Does Nothing */
+    public static void rescuePartyRegisterHealthObserver(Context mSystemContext) {
+        // do nothing
+    }
+
+    /**  Does Nothing */
+    public static void rescuePartyOnSettingsProviderPublished(Context mContext) {
+        // do nothing
+    }
+
+    /**  Does Nothing */
+    public static void rescuePartyResetDeviceConfigForPackages(List<String> packageNames) {
+        // do nothing
+    }
+}
diff --git a/packages/CrashRecovery/adaptor/preModularization/java/com/android/server/crashrecovery/CrashRecoveryAdaptor.java b/packages/CrashRecovery/adaptor/preModularization/java/com/android/server/crashrecovery/CrashRecoveryAdaptor.java
new file mode 100644
index 0000000..74c647c
--- /dev/null
+++ b/packages/CrashRecovery/adaptor/preModularization/java/com/android/server/crashrecovery/CrashRecoveryAdaptor.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.crashrecovery;
+
+import android.content.Context;
+
+import com.android.server.PackageWatchdog;
+import com.android.server.RescueParty;
+import com.android.server.SystemServiceManager;
+
+import java.util.List;
+
+/**
+ * This class mediates calls to hidden APIs in CrashRecovery module.
+ * This class is used when CrashRecovery classes are still in platform.
+ *
+ * @hide
+ */
+public class CrashRecoveryAdaptor {
+    private static final String TAG = "CrashRecoveryAdaptor";
+
+    /**  Start CrashRecoveryModule LifeCycleService */
+    public static void initializeCrashrecoveryModuleService(
+            SystemServiceManager mSystemServiceManager) {
+        mSystemServiceManager.startService(CrashRecoveryModule.Lifecycle.class);
+    }
+
+    /**  Forward calls to PackageWatchdog noteboot  */
+    public static void packageWatchdogNoteBoot(Context mSystemContext) {
+        PackageWatchdog.getInstance(mSystemContext).noteBoot();
+    }
+
+    /**  Forward calls to PackageWatchdog writeNow */
+    public static void packageWatchdogWriteNow(Context mContext) {
+        PackageWatchdog.getInstance(mContext).writeNow();
+    }
+
+    /**  Forward calls to PackageWatchdog OnPackagesReady */
+    public static void packageWatchdogOnPackagesReady(PackageWatchdog mPackageWatchdog) {
+        mPackageWatchdog.onPackagesReady();
+    }
+
+    /**  Forward calls to RescueParty RegisterHealthObserver */
+    public static void rescuePartyRegisterHealthObserver(Context mSystemContext) {
+        RescueParty.registerHealthObserver(mSystemContext);
+    }
+
+    /**  Forward calls to RescueParty OnSettingsProviderPublished */
+    public static void rescuePartyOnSettingsProviderPublished(Context mContext) {
+        RescueParty.onSettingsProviderPublished(mContext);
+    }
+
+    /**  Forward calls to RescueParty ResetDeviceConfigForPackages */
+    public static void rescuePartyResetDeviceConfigForPackages(List<String> packageNames) {
+        RescueParty.resetDeviceConfigForPackages(packageNames);
+    }
+}
diff --git a/packages/CrashRecovery/framework/Android.bp b/packages/CrashRecovery/framework/Android.bp
index 9480327..1be776d 100644
--- a/packages/CrashRecovery/framework/Android.bp
+++ b/packages/CrashRecovery/framework/Android.bp
@@ -1,53 +1,12 @@
-soong_config_module_type {
-    name: "platform_filegroup",
-    module_type: "filegroup",
-    config_namespace: "ANDROID",
-    bool_variables: [
-        "crashrecovery_files_in_platform",
-    ],
-    properties: [
-        "srcs",
-    ],
-}
-
-platform_filegroup {
+filegroup {
     name: "framework-crashrecovery-sources",
-    soong_config_variables: {
-        // if this flag is enabled, then files are part of platform
-        crashrecovery_files_in_platform: {
-            srcs: [
-                "java/**/*.java",
-                "java/**/*.aidl",
-            ],
-        },
-    },
-    path: "java",
-    visibility: ["//frameworks/base:__subpackages__"],
-}
-
-soong_config_module_type {
-    name: "module_filegroup",
-    module_type: "filegroup",
-    config_namespace: "ANDROID",
-    bool_variables: [
-        "crashrecovery_files_in_module",
+    srcs: [
+        "java/**/*.java",
+        "java/**/*.aidl",
     ],
-    properties: [
-        "srcs",
-    ],
-}
-
-module_filegroup {
-    name: "framework-crashrecovery-module-sources",
-    soong_config_variables: {
-        // if this flag is enabled, then files are part of module
-        crashrecovery_files_in_module: {
-            srcs: [
-                "java/**/*.java",
-                "java/**/*.aidl",
-            ],
-        },
-    },
     path: "java",
-    visibility: ["//packages/modules/CrashRecovery/framework"],
+    visibility: [
+        "//frameworks/base:__subpackages__",
+        "//packages/modules/CrashRecovery/framework",
+    ],
 }
diff --git a/packages/CrashRecovery/services/Android.bp b/packages/CrashRecovery/services/Android.bp
index 961b41f..1c84402 100644
--- a/packages/CrashRecovery/services/Android.bp
+++ b/packages/CrashRecovery/services/Android.bp
@@ -1,54 +1,18 @@
-soong_config_module_type {
-    name: "platform_filegroup",
-    module_type: "filegroup",
-    config_namespace: "ANDROID",
-    bool_variables: [
-        "crashrecovery_files_in_platform",
-    ],
-    properties: [
-        "srcs",
-    ],
-}
-
-platform_filegroup {
+filegroup {
     name: "services-crashrecovery-sources",
-    soong_config_variables: {
-        // if this flag is enabled, then files are part of platform
-        crashrecovery_files_in_platform: {
-            srcs: [
-                "java/**/*.java",
-                "java/**/*.aidl",
-                ":statslog-crashrecovery-java-gen",
-            ],
-        },
-    },
+    srcs: [
+        ":crashrecovery-platform-adaptor-srcs",
+        ":statslog-crashrecovery-java-gen",
+    ] + select(soong_config_variable("ANDROID", "release_crashrecovery_module"), {
+        "true": [],
+        default: ["platform/java/**/*.java"],
+    }),
     visibility: ["//frameworks/base:__subpackages__"],
 }
 
-soong_config_module_type {
-    name: "module_filegroup",
-    module_type: "filegroup",
-    config_namespace: "ANDROID",
-    bool_variables: [
-        "crashrecovery_files_in_module",
-    ],
-    properties: [
-        "srcs",
-    ],
-}
-
-module_filegroup {
+filegroup {
     name: "services-crashrecovery-module-sources",
-    soong_config_variables: {
-        // if this flag is enabled, then files are part of module
-        crashrecovery_files_in_module: {
-            srcs: [
-                "java/**/*.java",
-                "java/**/*.aidl",
-                ":statslog-crashrecovery-java-gen",
-            ],
-        },
-    },
+    srcs: ["module/java/**/*.java"],
     visibility: ["//packages/modules/CrashRecovery/service"],
 }
 
diff --git a/packages/CrashRecovery/services/module/java/com/android/server/ExplicitHealthCheckController.java b/packages/CrashRecovery/services/module/java/com/android/server/ExplicitHealthCheckController.java
new file mode 100644
index 0000000..da9a139
--- /dev/null
+++ b/packages/CrashRecovery/services/module/java/com/android/server/ExplicitHealthCheckController.java
@@ -0,0 +1,447 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server;
+
+import static android.service.watchdog.ExplicitHealthCheckService.EXTRA_HEALTH_CHECK_PASSED_PACKAGE;
+import static android.service.watchdog.ExplicitHealthCheckService.EXTRA_REQUESTED_PACKAGES;
+import static android.service.watchdog.ExplicitHealthCheckService.EXTRA_SUPPORTED_PACKAGES;
+import static android.service.watchdog.ExplicitHealthCheckService.PackageConfig;
+
+import android.Manifest;
+import android.annotation.MainThread;
+import android.annotation.Nullable;
+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.ServiceInfo;
+import android.os.IBinder;
+import android.os.RemoteCallback;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.service.watchdog.ExplicitHealthCheckService;
+import android.service.watchdog.IExplicitHealthCheckService;
+import android.text.TextUtils;
+import android.util.ArraySet;
+import android.util.Slog;
+
+import com.android.internal.annotations.GuardedBy;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Objects;
+import java.util.Set;
+import java.util.function.Consumer;
+
+// TODO(b/120598832): Add tests
+/**
+ * Controls the connections with {@link ExplicitHealthCheckService}.
+ */
+class ExplicitHealthCheckController {
+    private static final String TAG = "ExplicitHealthCheckController";
+    private final Object mLock = new Object();
+    private final Context mContext;
+
+    // Called everytime a package passes the health check, so the watchdog is notified of the
+    // passing check. In practice, should never be null after it has been #setEnabled.
+    // To prevent deadlocks between the controller and watchdog threads, we have
+    // a lock invariant to ALWAYS acquire the PackageWatchdog#mLock before #mLock in this class.
+    // It's easier to just NOT hold #mLock when calling into watchdog code on this consumer.
+    @GuardedBy("mLock") @Nullable private Consumer<String> mPassedConsumer;
+    // Called everytime after a successful #syncRequest call, so the watchdog can receive packages
+    // supporting health checks and update its internal state. In practice, should never be null
+    // after it has been #setEnabled.
+    // To prevent deadlocks between the controller and watchdog threads, we have
+    // a lock invariant to ALWAYS acquire the PackageWatchdog#mLock before #mLock in this class.
+    // It's easier to just NOT hold #mLock when calling into watchdog code on this consumer.
+    @GuardedBy("mLock") @Nullable private Consumer<List<PackageConfig>> mSupportedConsumer;
+    // Called everytime we need to notify the watchdog to sync requests between itself and the
+    // health check service. In practice, should never be null after it has been #setEnabled.
+    // To prevent deadlocks between the controller and watchdog threads, we have
+    // a lock invariant to ALWAYS acquire the PackageWatchdog#mLock before #mLock in this class.
+    // It's easier to just NOT hold #mLock when calling into watchdog code on this runnable.
+    @GuardedBy("mLock") @Nullable private Runnable mNotifySyncRunnable;
+    // Actual binder object to the explicit health check service.
+    @GuardedBy("mLock") @Nullable private IExplicitHealthCheckService mRemoteService;
+    // Connection to the explicit health check service, necessary to unbind.
+    // We should only try to bind if mConnection is null, non-null indicates we
+    // are connected or at least connecting.
+    @GuardedBy("mLock") @Nullable private ServiceConnection mConnection;
+    // Bind state of the explicit health check service.
+    @GuardedBy("mLock") private boolean mEnabled;
+
+    ExplicitHealthCheckController(Context context) {
+        mContext = context;
+    }
+
+    /** Enables or disables explicit health checks. */
+    public void setEnabled(boolean enabled) {
+        synchronized (mLock) {
+            Slog.i(TAG, "Explicit health checks " + (enabled ? "enabled." : "disabled."));
+            mEnabled = enabled;
+        }
+    }
+
+    /**
+     * Sets callbacks to listen to important events from the controller.
+     *
+     * <p> Should be called once at initialization before any other calls to the controller to
+     * ensure a happens-before relationship of the set parameters and visibility on other threads.
+     */
+    public void setCallbacks(Consumer<String> passedConsumer,
+            Consumer<List<PackageConfig>> supportedConsumer, Runnable notifySyncRunnable) {
+        synchronized (mLock) {
+            if (mPassedConsumer != null || mSupportedConsumer != null
+                    || mNotifySyncRunnable != null) {
+                Slog.wtf(TAG, "Resetting health check controller callbacks");
+            }
+
+            mPassedConsumer = Objects.requireNonNull(passedConsumer);
+            mSupportedConsumer = Objects.requireNonNull(supportedConsumer);
+            mNotifySyncRunnable = Objects.requireNonNull(notifySyncRunnable);
+        }
+    }
+
+    /**
+     * Calls the health check service to request or cancel packages based on
+     * {@code newRequestedPackages}.
+     *
+     * <p> Supported packages in {@code newRequestedPackages} that have not been previously
+     * requested will be requested while supported packages not in {@code newRequestedPackages}
+     * but were previously requested will be cancelled.
+     *
+     * <p> This handles binding and unbinding to the health check service as required.
+     *
+     * <p> Note, calling this may modify {@code newRequestedPackages}.
+     *
+     * <p> Note, this method is not thread safe, all calls should be serialized.
+     */
+    public void syncRequests(Set<String> newRequestedPackages) {
+        boolean enabled;
+        synchronized (mLock) {
+            enabled = mEnabled;
+        }
+
+        if (!enabled) {
+            Slog.i(TAG, "Health checks disabled, no supported packages");
+            // Call outside lock
+            mSupportedConsumer.accept(Collections.emptyList());
+            return;
+        }
+
+        getSupportedPackages(supportedPackageConfigs -> {
+            // Notify the watchdog without lock held
+            mSupportedConsumer.accept(supportedPackageConfigs);
+            getRequestedPackages(previousRequestedPackages -> {
+                synchronized (mLock) {
+                    // Hold lock so requests and cancellations are sent atomically.
+                    // It is important we don't mix requests from multiple threads.
+
+                    Set<String> supportedPackages = new ArraySet<>();
+                    for (PackageConfig config : supportedPackageConfigs) {
+                        supportedPackages.add(config.getPackageName());
+                    }
+                    // Note, this may modify newRequestedPackages
+                    newRequestedPackages.retainAll(supportedPackages);
+
+                    // Cancel packages no longer requested
+                    actOnDifference(previousRequestedPackages,
+                            newRequestedPackages, p -> cancel(p));
+                    // Request packages not yet requested
+                    actOnDifference(newRequestedPackages,
+                            previousRequestedPackages, p -> request(p));
+
+                    if (newRequestedPackages.isEmpty()) {
+                        Slog.i(TAG, "No more health check requests, unbinding...");
+                        unbindService();
+                        return;
+                    }
+                }
+            });
+        });
+    }
+
+    private void actOnDifference(Collection<String> collection1, Collection<String> collection2,
+            Consumer<String> action) {
+        Iterator<String> iterator = collection1.iterator();
+        while (iterator.hasNext()) {
+            String packageName = iterator.next();
+            if (!collection2.contains(packageName)) {
+                action.accept(packageName);
+            }
+        }
+    }
+
+    /**
+     * Requests an explicit health check for {@code packageName}.
+     * After this request, the callback registered on {@link #setCallbacks} can receive explicit
+     * health check passed results.
+     */
+    private void request(String packageName) {
+        synchronized (mLock) {
+            if (!prepareServiceLocked("request health check for " + packageName)) {
+                return;
+            }
+
+            Slog.i(TAG, "Requesting health check for package " + packageName);
+            try {
+                mRemoteService.request(packageName);
+            } catch (RemoteException e) {
+                Slog.w(TAG, "Failed to request health check for package " + packageName, e);
+            }
+        }
+    }
+
+    /**
+     * Cancels all explicit health checks for {@code packageName}.
+     * After this request, the callback registered on {@link #setCallbacks} can no longer receive
+     * explicit health check passed results.
+     */
+    private void cancel(String packageName) {
+        synchronized (mLock) {
+            if (!prepareServiceLocked("cancel health check for " + packageName)) {
+                return;
+            }
+
+            Slog.i(TAG, "Cancelling health check for package " + packageName);
+            try {
+                mRemoteService.cancel(packageName);
+            } catch (RemoteException e) {
+                // Do nothing, if the service is down, when it comes up, we will sync requests,
+                // if there's some other error, retrying wouldn't fix anyways.
+                Slog.w(TAG, "Failed to cancel health check for package " + packageName, e);
+            }
+        }
+    }
+
+    /**
+     * Returns the packages that we can request explicit health checks for.
+     * The packages will be returned to the {@code consumer}.
+     */
+    private void getSupportedPackages(Consumer<List<PackageConfig>> consumer) {
+        synchronized (mLock) {
+            if (!prepareServiceLocked("get health check supported packages")) {
+                return;
+            }
+
+            Slog.d(TAG, "Getting health check supported packages");
+            try {
+                mRemoteService.getSupportedPackages(new RemoteCallback(result -> {
+                    List<PackageConfig> packages =
+                            result.getParcelableArrayList(EXTRA_SUPPORTED_PACKAGES, android.service.watchdog.ExplicitHealthCheckService.PackageConfig.class);
+                    Slog.i(TAG, "Explicit health check supported packages " + packages);
+                    consumer.accept(packages);
+                }));
+            } catch (RemoteException e) {
+                // Request failed, treat as if all observed packages are supported, if any packages
+                // expire during this period, we may incorrectly treat it as failing health checks
+                // even if we don't support health checks for the package.
+                Slog.w(TAG, "Failed to get health check supported packages", e);
+            }
+        }
+    }
+
+    /**
+     * Returns the packages for which health checks are currently in progress.
+     * The packages will be returned to the {@code consumer}.
+     */
+    private void getRequestedPackages(Consumer<List<String>> consumer) {
+        synchronized (mLock) {
+            if (!prepareServiceLocked("get health check requested packages")) {
+                return;
+            }
+
+            Slog.d(TAG, "Getting health check requested packages");
+            try {
+                mRemoteService.getRequestedPackages(new RemoteCallback(result -> {
+                    List<String> packages = result.getStringArrayList(EXTRA_REQUESTED_PACKAGES);
+                    Slog.i(TAG, "Explicit health check requested packages " + packages);
+                    consumer.accept(packages);
+                }));
+            } catch (RemoteException e) {
+                // Request failed, treat as if we haven't requested any packages, if any packages
+                // were actually requested, they will not be cancelled now. May be cancelled later
+                Slog.w(TAG, "Failed to get health check requested packages", e);
+            }
+        }
+    }
+
+    /**
+     * Binds to the explicit health check service if the controller is enabled and
+     * not already bound.
+     */
+    private void bindService() {
+        synchronized (mLock) {
+            if (!mEnabled || mConnection != null || mRemoteService != null) {
+                if (!mEnabled) {
+                    Slog.i(TAG, "Not binding to service, service disabled");
+                } else if (mRemoteService != null) {
+                    Slog.i(TAG, "Not binding to service, service already connected");
+                } else {
+                    Slog.i(TAG, "Not binding to service, service already connecting");
+                }
+                return;
+            }
+            ComponentName component = getServiceComponentNameLocked();
+            if (component == null) {
+                Slog.wtf(TAG, "Explicit health check service not found");
+                return;
+            }
+
+            Intent intent = new Intent();
+            intent.setComponent(component);
+            mConnection = new ServiceConnection() {
+                @Override
+                public void onServiceConnected(ComponentName name, IBinder service) {
+                    Slog.i(TAG, "Explicit health check service is connected " + name);
+                    initState(service);
+                }
+
+                @Override
+                @MainThread
+                public void onServiceDisconnected(ComponentName name) {
+                    // Service crashed or process was killed, #onServiceConnected will be called.
+                    // Don't need to re-bind.
+                    Slog.i(TAG, "Explicit health check service is disconnected " + name);
+                    synchronized (mLock) {
+                        mRemoteService = null;
+                    }
+                }
+
+                @Override
+                public void onBindingDied(ComponentName name) {
+                    // Application hosting service probably got updated
+                    // Need to re-bind.
+                    Slog.i(TAG, "Explicit health check service binding is dead. Rebind: " + name);
+                    unbindService();
+                    bindService();
+                }
+
+                @Override
+                public void onNullBinding(ComponentName name) {
+                    // Should never happen. Service returned null from #onBind.
+                    Slog.wtf(TAG, "Explicit health check service binding is null?? " + name);
+                }
+            };
+
+            mContext.bindServiceAsUser(intent, mConnection,
+                    Context.BIND_AUTO_CREATE, UserHandle.SYSTEM);
+            Slog.i(TAG, "Explicit health check service is bound");
+        }
+    }
+
+    /** Unbinds the explicit health check service. */
+    private void unbindService() {
+        synchronized (mLock) {
+            if (mRemoteService != null) {
+                mContext.unbindService(mConnection);
+                mRemoteService = null;
+                mConnection = null;
+            }
+            Slog.i(TAG, "Explicit health check service is unbound");
+        }
+    }
+
+    @GuardedBy("mLock")
+    @Nullable
+    private ServiceInfo getServiceInfoLocked() {
+        final Intent intent = new Intent(ExplicitHealthCheckService.SERVICE_INTERFACE);
+        final ResolveInfo resolveInfo = mContext.getPackageManager().resolveService(intent,
+                PackageManager.GET_SERVICES | PackageManager.GET_META_DATA
+                        |  PackageManager.MATCH_SYSTEM_ONLY);
+        if (resolveInfo == null || resolveInfo.serviceInfo == null) {
+            Slog.w(TAG, "No valid components found.");
+            return null;
+        }
+        return resolveInfo.serviceInfo;
+    }
+
+    @GuardedBy("mLock")
+    @Nullable
+    private ComponentName getServiceComponentNameLocked() {
+        final ServiceInfo serviceInfo = getServiceInfoLocked();
+        if (serviceInfo == null) {
+            return null;
+        }
+
+        final ComponentName name = new ComponentName(serviceInfo.packageName, serviceInfo.name);
+        if (!Manifest.permission.BIND_EXPLICIT_HEALTH_CHECK_SERVICE
+                .equals(serviceInfo.permission)) {
+            Slog.w(TAG, name.flattenToShortString() + " does not require permission "
+                    + Manifest.permission.BIND_EXPLICIT_HEALTH_CHECK_SERVICE);
+            return null;
+        }
+        return name;
+    }
+
+    private void initState(IBinder service) {
+        synchronized (mLock) {
+            if (!mEnabled) {
+                Slog.w(TAG, "Attempting to connect disabled service?? Unbinding...");
+                // Very unlikely, but we disabled the service after binding but before we connected
+                unbindService();
+                return;
+            }
+            mRemoteService = IExplicitHealthCheckService.Stub.asInterface(service);
+            try {
+                mRemoteService.setCallback(new RemoteCallback(result -> {
+                    String packageName = result.getString(EXTRA_HEALTH_CHECK_PASSED_PACKAGE);
+                    if (!TextUtils.isEmpty(packageName)) {
+                        if (mPassedConsumer == null) {
+                            Slog.wtf(TAG, "Health check passed for package " + packageName
+                                    + "but no consumer registered.");
+                        } else {
+                            // Call without lock held
+                            mPassedConsumer.accept(packageName);
+                        }
+                    } else {
+                        Slog.wtf(TAG, "Empty package passed explicit health check?");
+                    }
+                }));
+                Slog.i(TAG, "Service initialized, syncing requests");
+            } catch (RemoteException e) {
+                Slog.wtf(TAG, "Could not setCallback on explicit health check service");
+            }
+        }
+        // Calling outside lock
+        mNotifySyncRunnable.run();
+    }
+
+    /**
+     * Prepares the health check service to receive requests.
+     *
+     * @return {@code true} if it is ready and we can proceed with a request,
+     * {@code false} otherwise. If it is not ready, and the service is enabled,
+     * we will bind and the request should be automatically attempted later.
+     */
+    @GuardedBy("mLock")
+    private boolean prepareServiceLocked(String action) {
+        if (mRemoteService != null && mEnabled) {
+            return true;
+        }
+        Slog.i(TAG, "Service not ready to " + action
+                + (mEnabled ? ". Binding..." : ". Disabled"));
+        if (mEnabled) {
+            bindService();
+        }
+        return false;
+    }
+}
diff --git a/packages/CrashRecovery/services/module/java/com/android/server/PackageWatchdog.java b/packages/CrashRecovery/services/module/java/com/android/server/PackageWatchdog.java
new file mode 100644
index 0000000..9a8261c
--- /dev/null
+++ b/packages/CrashRecovery/services/module/java/com/android/server/PackageWatchdog.java
@@ -0,0 +1,2094 @@
+/*
+ * 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.server;
+
+import static android.content.Intent.ACTION_REBOOT;
+import static android.content.Intent.ACTION_SHUTDOWN;
+import static android.service.watchdog.ExplicitHealthCheckService.PackageConfig;
+
+import static com.android.server.crashrecovery.CrashRecoveryUtils.dumpCrashRecoveryEvents;
+
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.VersionedPackage;
+import android.crashrecovery.flags.Flags;
+import android.os.Environment;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Process;
+import android.os.SystemProperties;
+import android.provider.DeviceConfig;
+import android.sysprop.CrashRecoveryProperties;
+import android.text.TextUtils;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+import android.util.AtomicFile;
+import android.util.EventLog;
+import android.util.IndentingPrintWriter;
+import android.util.LongArrayQueue;
+import android.util.Slog;
+import android.util.Xml;
+import android.util.XmlUtils;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.modules.utils.BackgroundThread;
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
+
+import libcore.io.IoUtils;
+
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.PrintWriter;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.NoSuchElementException;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Monitors the health of packages on the system and notifies interested observers when packages
+ * fail. On failure, the registered observer with the least user impacting mitigation will
+ * be notified.
+ * @hide
+ */
+public class PackageWatchdog {
+    private static final String TAG = "PackageWatchdog";
+
+    static final String PROPERTY_WATCHDOG_TRIGGER_DURATION_MILLIS =
+            "watchdog_trigger_failure_duration_millis";
+    static final String PROPERTY_WATCHDOG_TRIGGER_FAILURE_COUNT =
+            "watchdog_trigger_failure_count";
+    static final String PROPERTY_WATCHDOG_EXPLICIT_HEALTH_CHECK_ENABLED =
+            "watchdog_explicit_health_check_enabled";
+
+    // TODO: make the following values configurable via DeviceConfig
+    private static final long NATIVE_CRASH_POLLING_INTERVAL_MILLIS =
+            TimeUnit.SECONDS.toMillis(30);
+    private static final long NUMBER_OF_NATIVE_CRASH_POLLS = 10;
+
+
+    /** Reason for package failure could not be determined. */
+    public static final int FAILURE_REASON_UNKNOWN = 0;
+
+    /** The package had a native crash. */
+    public static final int FAILURE_REASON_NATIVE_CRASH = 1;
+
+    /** The package failed an explicit health check. */
+    public static final int FAILURE_REASON_EXPLICIT_HEALTH_CHECK = 2;
+
+    /** The app crashed. */
+    public static final int FAILURE_REASON_APP_CRASH = 3;
+
+    /** The app was not responding. */
+    public static final int FAILURE_REASON_APP_NOT_RESPONDING = 4;
+
+    /** The device was boot looping. */
+    public static final int FAILURE_REASON_BOOT_LOOP = 5;
+
+    /** @hide */
+    @IntDef(prefix = { "FAILURE_REASON_" }, value = {
+            FAILURE_REASON_UNKNOWN,
+            FAILURE_REASON_NATIVE_CRASH,
+            FAILURE_REASON_EXPLICIT_HEALTH_CHECK,
+            FAILURE_REASON_APP_CRASH,
+            FAILURE_REASON_APP_NOT_RESPONDING,
+            FAILURE_REASON_BOOT_LOOP
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface FailureReasons {}
+
+    // Duration to count package failures before it resets to 0
+    @VisibleForTesting
+    static final int DEFAULT_TRIGGER_FAILURE_DURATION_MS =
+            (int) TimeUnit.MINUTES.toMillis(1);
+    // Number of package failures within the duration above before we notify observers
+    @VisibleForTesting
+    static final int DEFAULT_TRIGGER_FAILURE_COUNT = 5;
+    @VisibleForTesting
+    static final long DEFAULT_OBSERVING_DURATION_MS = TimeUnit.DAYS.toMillis(2);
+    // Sliding window for tracking how many mitigation calls were made for a package.
+    @VisibleForTesting
+    static final long DEFAULT_DEESCALATION_WINDOW_MS = TimeUnit.HOURS.toMillis(1);
+    // Whether explicit health checks are enabled or not
+    private static final boolean DEFAULT_EXPLICIT_HEALTH_CHECK_ENABLED = true;
+
+    @VisibleForTesting
+    static final int DEFAULT_BOOT_LOOP_TRIGGER_COUNT = 5;
+
+    static final long DEFAULT_BOOT_LOOP_TRIGGER_WINDOW_MS = TimeUnit.MINUTES.toMillis(10);
+
+    // Time needed to apply mitigation
+    private static final String MITIGATION_WINDOW_MS =
+            "persist.device_config.configuration.mitigation_window_ms";
+    @VisibleForTesting
+    static final long DEFAULT_MITIGATION_WINDOW_MS = TimeUnit.SECONDS.toMillis(5);
+
+    // Threshold level at which or above user might experience significant disruption.
+    private static final String MAJOR_USER_IMPACT_LEVEL_THRESHOLD =
+            "persist.device_config.configuration.major_user_impact_level_threshold";
+    private static final int DEFAULT_MAJOR_USER_IMPACT_LEVEL_THRESHOLD =
+            PackageHealthObserverImpact.USER_IMPACT_LEVEL_71;
+
+    // Comma separated list of all packages exempt from user impact level threshold. If a package
+    // in the list is crash looping, all the mitigations including factory reset will be performed.
+    private static final String PACKAGES_EXEMPT_FROM_IMPACT_LEVEL_THRESHOLD =
+            "persist.device_config.configuration.packages_exempt_from_impact_level_threshold";
+
+    // Comma separated list of default packages exempt from user impact level threshold.
+    private static final String DEFAULT_PACKAGES_EXEMPT_FROM_IMPACT_LEVEL_THRESHOLD =
+            "com.android.systemui";
+
+    private long mNumberOfNativeCrashPollsRemaining;
+
+    private static final int DB_VERSION = 1;
+    private static final String TAG_PACKAGE_WATCHDOG = "package-watchdog";
+    private static final String TAG_PACKAGE = "package";
+    private static final String TAG_OBSERVER = "observer";
+    private static final String ATTR_VERSION = "version";
+    private static final String ATTR_NAME = "name";
+    private static final String ATTR_DURATION = "duration";
+    private static final String ATTR_EXPLICIT_HEALTH_CHECK_DURATION = "health-check-duration";
+    private static final String ATTR_PASSED_HEALTH_CHECK = "passed-health-check";
+    private static final String ATTR_MITIGATION_CALLS = "mitigation-calls";
+    private static final String ATTR_MITIGATION_COUNT = "mitigation-count";
+
+    // A file containing information about the current mitigation count in the case of a boot loop.
+    // This allows boot loop information to persist in the case of an fs-checkpoint being
+    // aborted.
+    private static final String METADATA_FILE = "/metadata/watchdog/mitigation_count.txt";
+
+    /**
+     * EventLog tags used when logging into the event log. Note the values must be sync with
+     * frameworks/base/services/core/java/com/android/server/EventLogTags.logtags to get correct
+     * name translation.
+     */
+    private static final int LOG_TAG_RESCUE_NOTE = 2900;
+
+    private static final Object sPackageWatchdogLock = new Object();
+    @GuardedBy("sPackageWatchdogLock")
+    private static PackageWatchdog sPackageWatchdog;
+
+    private final Object mLock = new Object();
+    // System server context
+    private final Context mContext;
+    // Handler to run short running tasks
+    private final Handler mShortTaskHandler;
+    // Handler for processing IO and long running tasks
+    private final Handler mLongTaskHandler;
+    // Contains (observer-name -> observer-handle) that have ever been registered from
+    // previous boots. Observers with all packages expired are periodically pruned.
+    // It is saved to disk on system shutdown and repouplated on startup so it survives reboots.
+    @GuardedBy("mLock")
+    private final ArrayMap<String, ObserverInternal> mAllObservers = new ArrayMap<>();
+    // File containing the XML data of monitored packages /data/system/package-watchdog.xml
+    private final AtomicFile mPolicyFile;
+    private final ExplicitHealthCheckController mHealthCheckController;
+    private final Runnable mSyncRequests = this::syncRequests;
+    private final Runnable mSyncStateWithScheduledReason = this::syncStateWithScheduledReason;
+    private final Runnable mSaveToFile = this::saveToFile;
+    private final SystemClock mSystemClock;
+    private final BootThreshold mBootThreshold;
+    private final DeviceConfig.OnPropertiesChangedListener
+            mOnPropertyChangedListener = this::onPropertyChanged;
+
+    private final Set<String> mPackagesExemptFromImpactLevelThreshold = new ArraySet<>();
+
+    // The set of packages that have been synced with the ExplicitHealthCheckController
+    @GuardedBy("mLock")
+    private Set<String> mRequestedHealthCheckPackages = new ArraySet<>();
+    @GuardedBy("mLock")
+    private boolean mIsPackagesReady;
+    // Flag to control whether explicit health checks are supported or not
+    @GuardedBy("mLock")
+    private boolean mIsHealthCheckEnabled = DEFAULT_EXPLICIT_HEALTH_CHECK_ENABLED;
+    @GuardedBy("mLock")
+    private int mTriggerFailureDurationMs = DEFAULT_TRIGGER_FAILURE_DURATION_MS;
+    @GuardedBy("mLock")
+    private int mTriggerFailureCount = DEFAULT_TRIGGER_FAILURE_COUNT;
+    // SystemClock#uptimeMillis when we last executed #syncState
+    // 0 if no prune is scheduled.
+    @GuardedBy("mLock")
+    private long mUptimeAtLastStateSync;
+    // If true, sync explicit health check packages with the ExplicitHealthCheckController.
+    @GuardedBy("mLock")
+    private boolean mSyncRequired = false;
+
+    @GuardedBy("mLock")
+    private long mLastMitigation = -1000000;
+
+    @FunctionalInterface
+    @VisibleForTesting
+    interface SystemClock {
+        long uptimeMillis();
+    }
+
+    private PackageWatchdog(Context context) {
+        // Needs to be constructed inline
+        this(context, new AtomicFile(
+                        new File(new File(Environment.getDataDirectory(), "system"),
+                                "package-watchdog.xml")),
+                new Handler(Looper.myLooper()), BackgroundThread.getHandler(),
+                new ExplicitHealthCheckController(context),
+                android.os.SystemClock::uptimeMillis);
+    }
+
+    /**
+     * Creates a PackageWatchdog that allows injecting dependencies.
+     */
+    @VisibleForTesting
+    PackageWatchdog(Context context, AtomicFile policyFile, Handler shortTaskHandler,
+            Handler longTaskHandler, ExplicitHealthCheckController controller,
+            SystemClock clock) {
+        mContext = context;
+        mPolicyFile = policyFile;
+        mShortTaskHandler = shortTaskHandler;
+        mLongTaskHandler = longTaskHandler;
+        mHealthCheckController = controller;
+        mSystemClock = clock;
+        mNumberOfNativeCrashPollsRemaining = NUMBER_OF_NATIVE_CRASH_POLLS;
+        mBootThreshold = new BootThreshold(DEFAULT_BOOT_LOOP_TRIGGER_COUNT,
+                DEFAULT_BOOT_LOOP_TRIGGER_WINDOW_MS);
+
+        loadFromFile();
+        sPackageWatchdog = this;
+    }
+
+    /** Creates or gets singleton instance of PackageWatchdog. */
+    public static  @NonNull PackageWatchdog getInstance(@NonNull Context context) {
+        synchronized (sPackageWatchdogLock) {
+            if (sPackageWatchdog == null) {
+                new PackageWatchdog(context);
+            }
+            return sPackageWatchdog;
+        }
+    }
+
+    /**
+     * Called during boot to notify when packages are ready on the device so we can start
+     * binding.
+     * @hide
+     */
+    public void onPackagesReady() {
+        synchronized (mLock) {
+            mIsPackagesReady = true;
+            mHealthCheckController.setCallbacks(packageName -> onHealthCheckPassed(packageName),
+                    packages -> onSupportedPackages(packages),
+                    this::onSyncRequestNotified);
+            setPropertyChangedListenerLocked();
+            updateConfigs();
+        }
+    }
+
+    /**
+     * Registers {@code observer} to listen for package failures. Add a new ObserverInternal for
+     * this observer if it does not already exist.
+     *
+     * <p>Observers are expected to call this on boot. It does not specify any packages but
+     * it will resume observing any packages requested from a previous boot.
+     * @hide
+     */
+    public void registerHealthObserver(PackageHealthObserver observer) {
+        synchronized (mLock) {
+            ObserverInternal internalObserver = mAllObservers.get(observer.getUniqueIdentifier());
+            if (internalObserver != null) {
+                internalObserver.registeredObserver = observer;
+            } else {
+                internalObserver = new ObserverInternal(observer.getUniqueIdentifier(),
+                        new ArrayList<>());
+                internalObserver.registeredObserver = observer;
+                mAllObservers.put(observer.getUniqueIdentifier(), internalObserver);
+                syncState("added new observer");
+            }
+        }
+    }
+
+    /**
+     * Starts observing the health of the {@code packages} for {@code observer} and notifies
+     * {@code observer} of any package failures within the monitoring duration.
+     *
+     * <p>If monitoring a package supporting explicit health check, at the end of the monitoring
+     * duration if {@link #onHealthCheckPassed} was never called,
+     * {@link PackageHealthObserver#execute} will be called as if the package failed.
+     *
+     * <p>If {@code observer} is already monitoring a package in {@code packageNames},
+     * the monitoring window of that package will be reset to {@code durationMs} and the health
+     * check state will be reset to a default depending on if the package is contained in
+     * {@link mPackagesWithExplicitHealthCheckEnabled}.
+     *
+     * <p>If {@code packageNames} is empty, this will be a no-op.
+     *
+     * <p>If {@code durationMs} is less than 1, a default monitoring duration
+     * {@link #DEFAULT_OBSERVING_DURATION_MS} will be used.
+     * @hide
+     */
+    public void startObservingHealth(PackageHealthObserver observer, List<String> packageNames,
+            long durationMs) {
+        if (packageNames.isEmpty()) {
+            Slog.wtf(TAG, "No packages to observe, " + observer.getUniqueIdentifier());
+            return;
+        }
+        if (durationMs < 1) {
+            Slog.wtf(TAG, "Invalid duration " + durationMs + "ms for observer "
+                    + observer.getUniqueIdentifier() + ". Not observing packages " + packageNames);
+            durationMs = DEFAULT_OBSERVING_DURATION_MS;
+        }
+
+        List<MonitoredPackage> packages = new ArrayList<>();
+        for (int i = 0; i < packageNames.size(); i++) {
+            // Health checks not available yet so health check state will start INACTIVE
+            MonitoredPackage pkg = newMonitoredPackage(packageNames.get(i), durationMs, false);
+            if (pkg != null) {
+                packages.add(pkg);
+            } else {
+                Slog.w(TAG, "Failed to create MonitoredPackage for pkg=" + packageNames.get(i));
+            }
+        }
+
+        if (packages.isEmpty()) {
+            return;
+        }
+
+        // Sync before we add the new packages to the observers. This will #pruneObservers,
+        // causing any elapsed time to be deducted from all existing packages before we add new
+        // packages. This maintains the invariant that the elapsed time for ALL (new and existing)
+        // packages is the same.
+        mLongTaskHandler.post(() -> {
+            syncState("observing new packages");
+
+            synchronized (mLock) {
+                ObserverInternal oldObserver = mAllObservers.get(observer.getUniqueIdentifier());
+                if (oldObserver == null) {
+                    Slog.d(TAG, observer.getUniqueIdentifier() + " started monitoring health "
+                            + "of packages " + packageNames);
+                    mAllObservers.put(observer.getUniqueIdentifier(),
+                            new ObserverInternal(observer.getUniqueIdentifier(), packages));
+                } else {
+                    Slog.d(TAG, observer.getUniqueIdentifier() + " added the following "
+                            + "packages to monitor " + packageNames);
+                    oldObserver.updatePackagesLocked(packages);
+                }
+            }
+
+            // Register observer in case not already registered
+            registerHealthObserver(observer);
+
+            // Sync after we add the new packages to the observers. We may have received packges
+            // requiring an earlier schedule than we are currently scheduled for.
+            syncState("updated observers");
+        });
+
+    }
+
+    /**
+     * Unregisters {@code observer} from listening to package failure.
+     * Additionally, this stops observing any packages that may have previously been observed
+     * even from a previous boot.
+     * @hide
+     */
+    public void unregisterHealthObserver(PackageHealthObserver observer) {
+        mLongTaskHandler.post(() -> {
+            synchronized (mLock) {
+                mAllObservers.remove(observer.getUniqueIdentifier());
+            }
+            syncState("unregistering observer: " + observer.getUniqueIdentifier());
+        });
+    }
+
+    /**
+     * Called when a process fails due to a crash, ANR or explicit health check.
+     *
+     * <p>For each package contained in the process, one registered observer with the least user
+     * impact will be notified for mitigation.
+     *
+     * <p>This method could be called frequently if there is a severe problem on the device.
+     */
+    public void onPackageFailure(@NonNull List<VersionedPackage> packages,
+            @FailureReasons int failureReason) {
+        if (packages == null) {
+            Slog.w(TAG, "Could not resolve a list of failing packages");
+            return;
+        }
+        synchronized (mLock) {
+            final long now = mSystemClock.uptimeMillis();
+            if (Flags.recoverabilityDetection()) {
+                if (now >= mLastMitigation
+                        && (now - mLastMitigation) < getMitigationWindowMs()) {
+                    Slog.i(TAG, "Skipping onPackageFailure mitigation");
+                    return;
+                }
+            }
+        }
+        mLongTaskHandler.post(() -> {
+            synchronized (mLock) {
+                if (mAllObservers.isEmpty()) {
+                    return;
+                }
+                boolean requiresImmediateAction = (failureReason == FAILURE_REASON_NATIVE_CRASH
+                        || failureReason == FAILURE_REASON_EXPLICIT_HEALTH_CHECK);
+                if (requiresImmediateAction) {
+                    handleFailureImmediately(packages, failureReason);
+                } else {
+                    for (int pIndex = 0; pIndex < packages.size(); pIndex++) {
+                        VersionedPackage versionedPackage = packages.get(pIndex);
+                        // Observer that will receive failure for versionedPackage
+                        PackageHealthObserver currentObserverToNotify = null;
+                        int currentObserverImpact = Integer.MAX_VALUE;
+                        MonitoredPackage currentMonitoredPackage = null;
+
+                        // Find observer with least user impact
+                        for (int oIndex = 0; oIndex < mAllObservers.size(); oIndex++) {
+                            ObserverInternal observer = mAllObservers.valueAt(oIndex);
+                            PackageHealthObserver registeredObserver = observer.registeredObserver;
+                            if (registeredObserver != null
+                                    && observer.onPackageFailureLocked(
+                                    versionedPackage.getPackageName())) {
+                                MonitoredPackage p = observer.getMonitoredPackage(
+                                        versionedPackage.getPackageName());
+                                int mitigationCount = 1;
+                                if (p != null) {
+                                    mitigationCount = p.getMitigationCountLocked() + 1;
+                                }
+                                int impact = registeredObserver.onHealthCheckFailed(
+                                        versionedPackage, failureReason, mitigationCount);
+                                if (impact != PackageHealthObserverImpact.USER_IMPACT_LEVEL_0
+                                        && impact < currentObserverImpact) {
+                                    currentObserverToNotify = registeredObserver;
+                                    currentObserverImpact = impact;
+                                    currentMonitoredPackage = p;
+                                }
+                            }
+                        }
+
+                        // Execute action with least user impact
+                        if (currentObserverToNotify != null) {
+                            int mitigationCount = 1;
+                            if (currentMonitoredPackage != null) {
+                                currentMonitoredPackage.noteMitigationCallLocked();
+                                mitigationCount =
+                                        currentMonitoredPackage.getMitigationCountLocked();
+                            }
+                            if (Flags.recoverabilityDetection()) {
+                                maybeExecute(currentObserverToNotify, versionedPackage,
+                                        failureReason, currentObserverImpact, mitigationCount);
+                            } else {
+                                currentObserverToNotify.execute(versionedPackage,
+                                        failureReason, mitigationCount);
+                            }
+                        }
+                    }
+                }
+            }
+        });
+    }
+
+    /**
+     * For native crashes or explicit health check failures, call directly into each observer to
+     * mitigate the error without going through failure threshold logic.
+     */
+    private void handleFailureImmediately(List<VersionedPackage> packages,
+            @FailureReasons int failureReason) {
+        VersionedPackage failingPackage = packages.size() > 0 ? packages.get(0) : null;
+        PackageHealthObserver currentObserverToNotify = null;
+        int currentObserverImpact = Integer.MAX_VALUE;
+        for (ObserverInternal observer: mAllObservers.values()) {
+            PackageHealthObserver registeredObserver = observer.registeredObserver;
+            if (registeredObserver != null) {
+                int impact = registeredObserver.onHealthCheckFailed(
+                        failingPackage, failureReason, 1);
+                if (impact != PackageHealthObserverImpact.USER_IMPACT_LEVEL_0
+                        && impact < currentObserverImpact) {
+                    currentObserverToNotify = registeredObserver;
+                    currentObserverImpact = impact;
+                }
+            }
+        }
+        if (currentObserverToNotify != null) {
+            if (Flags.recoverabilityDetection()) {
+                maybeExecute(currentObserverToNotify, failingPackage, failureReason,
+                        currentObserverImpact, /*mitigationCount=*/ 1);
+            } else {
+                currentObserverToNotify.execute(failingPackage,  failureReason, 1);
+            }
+        }
+    }
+
+    private void maybeExecute(PackageHealthObserver currentObserverToNotify,
+                              VersionedPackage versionedPackage,
+                              @FailureReasons int failureReason,
+                              int currentObserverImpact,
+                              int mitigationCount) {
+        if (allowMitigations(currentObserverImpact, versionedPackage)) {
+            synchronized (mLock) {
+                mLastMitigation = mSystemClock.uptimeMillis();
+            }
+            currentObserverToNotify.execute(versionedPackage, failureReason, mitigationCount);
+        }
+    }
+
+    private boolean allowMitigations(int currentObserverImpact,
+            VersionedPackage versionedPackage) {
+        return currentObserverImpact < getUserImpactLevelLimit()
+                || getPackagesExemptFromImpactLevelThreshold().contains(
+                versionedPackage.getPackageName());
+    }
+
+    private long getMitigationWindowMs() {
+        return SystemProperties.getLong(MITIGATION_WINDOW_MS, DEFAULT_MITIGATION_WINDOW_MS);
+    }
+
+
+    /**
+     * Called when the system server boots. If the system server is detected to be in a boot loop,
+     * query each observer and perform the mitigation action with the lowest user impact.
+     *
+     * Note: PackageWatchdog considers system_server restart loop as bootloop. Full reboots
+     * are not counted in bootloop.
+     * @hide
+     */
+    @SuppressWarnings("GuardedBy")
+    public void noteBoot() {
+        synchronized (mLock) {
+            // if boot count has reached threshold, start mitigation.
+            // We wait until threshold number of restarts only for the first time. Perform
+            // mitigations for every restart after that.
+            boolean mitigate = mBootThreshold.incrementAndTest();
+            if (mitigate) {
+                if (!Flags.recoverabilityDetection()) {
+                    mBootThreshold.reset();
+                }
+                int mitigationCount = mBootThreshold.getMitigationCount() + 1;
+                PackageHealthObserver currentObserverToNotify = null;
+                ObserverInternal currentObserverInternal = null;
+                int currentObserverImpact = Integer.MAX_VALUE;
+                for (int i = 0; i < mAllObservers.size(); i++) {
+                    final ObserverInternal observer = mAllObservers.valueAt(i);
+                    PackageHealthObserver registeredObserver = observer.registeredObserver;
+                    if (registeredObserver != null) {
+                        int impact = Flags.recoverabilityDetection()
+                                ? registeredObserver.onBootLoop(
+                                        observer.getBootMitigationCount() + 1)
+                                : registeredObserver.onBootLoop(mitigationCount);
+                        if (impact != PackageHealthObserverImpact.USER_IMPACT_LEVEL_0
+                                && impact < currentObserverImpact) {
+                            currentObserverToNotify = registeredObserver;
+                            currentObserverInternal = observer;
+                            currentObserverImpact = impact;
+                        }
+                    }
+                }
+                if (currentObserverToNotify != null) {
+                    if (Flags.recoverabilityDetection()) {
+                        int currentObserverMitigationCount =
+                                currentObserverInternal.getBootMitigationCount() + 1;
+                        currentObserverInternal.setBootMitigationCount(
+                                currentObserverMitigationCount);
+                        saveAllObserversBootMitigationCountToMetadata(METADATA_FILE);
+                        currentObserverToNotify.executeBootLoopMitigation(
+                                currentObserverMitigationCount);
+                    } else {
+                        mBootThreshold.setMitigationCount(mitigationCount);
+                        mBootThreshold.saveMitigationCountToMetadata();
+                        currentObserverToNotify.executeBootLoopMitigation(mitigationCount);
+                    }
+                }
+            }
+        }
+    }
+
+    // TODO(b/120598832): Optimize write? Maybe only write a separate smaller file? Also
+    // avoid holding lock?
+    // This currently adds about 7ms extra to shutdown thread
+    /** @hide Writes the package information to file during shutdown. */
+    public void writeNow() {
+        synchronized (mLock) {
+            // Must only run synchronous tasks as this runs on the ShutdownThread and no other
+            // thread is guaranteed to run during shutdown.
+            if (!mAllObservers.isEmpty()) {
+                mLongTaskHandler.removeCallbacks(mSaveToFile);
+                pruneObserversLocked();
+                saveToFile();
+                Slog.i(TAG, "Last write to update package durations");
+            }
+        }
+    }
+
+    /**
+     * Enables or disables explicit health checks.
+     * <p> If explicit health checks are enabled, the health check service is started.
+     * <p> If explicit health checks are disabled, pending explicit health check requests are
+     * passed and the health check service is stopped.
+     */
+    private void setExplicitHealthCheckEnabled(boolean enabled) {
+        synchronized (mLock) {
+            mIsHealthCheckEnabled = enabled;
+            mHealthCheckController.setEnabled(enabled);
+            mSyncRequired = true;
+            // Prune to update internal state whenever health check is enabled/disabled
+            syncState("health check state " + (enabled ? "enabled" : "disabled"));
+        }
+    }
+
+    /**
+     * This method should be only called on mShortTaskHandler, since it modifies
+     * {@link #mNumberOfNativeCrashPollsRemaining}.
+     */
+    private void checkAndMitigateNativeCrashes() {
+        mNumberOfNativeCrashPollsRemaining--;
+        // Check if native watchdog reported a crash
+        if ("1".equals(SystemProperties.get("sys.init.updatable_crashing"))) {
+            // We rollback all available low impact rollbacks when crash is unattributable
+            onPackageFailure(Collections.EMPTY_LIST, FAILURE_REASON_NATIVE_CRASH);
+            // we stop polling after an attempt to execute rollback, regardless of whether the
+            // attempt succeeds or not
+        } else {
+            if (mNumberOfNativeCrashPollsRemaining > 0) {
+                mShortTaskHandler.postDelayed(() -> checkAndMitigateNativeCrashes(),
+                        NATIVE_CRASH_POLLING_INTERVAL_MILLIS);
+            }
+        }
+    }
+
+    /**
+     * Since this method can eventually trigger a rollback, it should be called
+     * only once boot has completed {@code onBootCompleted} and not earlier, because the install
+     * session must be entirely completed before we try to rollback.
+     * @hide
+     */
+    public void scheduleCheckAndMitigateNativeCrashes() {
+        Slog.i(TAG, "Scheduling " + mNumberOfNativeCrashPollsRemaining + " polls to check "
+                + "and mitigate native crashes");
+        mShortTaskHandler.post(()->checkAndMitigateNativeCrashes());
+    }
+
+    private int getUserImpactLevelLimit() {
+        return SystemProperties.getInt(MAJOR_USER_IMPACT_LEVEL_THRESHOLD,
+                DEFAULT_MAJOR_USER_IMPACT_LEVEL_THRESHOLD);
+    }
+
+    private Set<String> getPackagesExemptFromImpactLevelThreshold() {
+        if (mPackagesExemptFromImpactLevelThreshold.isEmpty()) {
+            String packageNames = SystemProperties.get(PACKAGES_EXEMPT_FROM_IMPACT_LEVEL_THRESHOLD,
+                    DEFAULT_PACKAGES_EXEMPT_FROM_IMPACT_LEVEL_THRESHOLD);
+            return Set.of(packageNames.split("\\s*,\\s*"));
+        }
+        return mPackagesExemptFromImpactLevelThreshold;
+    }
+
+    /** Possible severity values of the user impact of a {@link PackageHealthObserver#execute}.
+     * @hide
+     */
+    @Retention(SOURCE)
+    @IntDef(value = {PackageHealthObserverImpact.USER_IMPACT_LEVEL_0,
+                     PackageHealthObserverImpact.USER_IMPACT_LEVEL_10,
+                     PackageHealthObserverImpact.USER_IMPACT_LEVEL_20,
+                     PackageHealthObserverImpact.USER_IMPACT_LEVEL_30,
+                     PackageHealthObserverImpact.USER_IMPACT_LEVEL_40,
+                     PackageHealthObserverImpact.USER_IMPACT_LEVEL_50,
+                     PackageHealthObserverImpact.USER_IMPACT_LEVEL_70,
+                     PackageHealthObserverImpact.USER_IMPACT_LEVEL_71,
+                     PackageHealthObserverImpact.USER_IMPACT_LEVEL_75,
+                     PackageHealthObserverImpact.USER_IMPACT_LEVEL_80,
+                     PackageHealthObserverImpact.USER_IMPACT_LEVEL_90,
+                     PackageHealthObserverImpact.USER_IMPACT_LEVEL_100})
+    public @interface PackageHealthObserverImpact {
+        /** No action to take. */
+        int USER_IMPACT_LEVEL_0 = 0;
+        /* Action has low user impact, user of a device will barely notice. */
+        int USER_IMPACT_LEVEL_10 = 10;
+        /* Actions having medium user impact, user of a device will likely notice. */
+        int USER_IMPACT_LEVEL_20 = 20;
+        int USER_IMPACT_LEVEL_30 = 30;
+        int USER_IMPACT_LEVEL_40 = 40;
+        int USER_IMPACT_LEVEL_50 = 50;
+        int USER_IMPACT_LEVEL_70 = 70;
+        /* Action has high user impact, a last resort, user of a device will be very frustrated. */
+        int USER_IMPACT_LEVEL_71 = 71;
+        int USER_IMPACT_LEVEL_75 = 75;
+        int USER_IMPACT_LEVEL_80 = 80;
+        int USER_IMPACT_LEVEL_90 = 90;
+        int USER_IMPACT_LEVEL_100 = 100;
+    }
+
+    /** Register instances of this interface to receive notifications on package failure. */
+    public interface PackageHealthObserver {
+        /**
+         * Called when health check fails for the {@code versionedPackage}.
+         *
+         * @param versionedPackage the package that is failing. This may be null if a native
+         *                          service is crashing.
+         * @param failureReason   the type of failure that is occurring.
+         * @param mitigationCount the number of times mitigation has been called for this package
+         *                        (including this time).
+         *
+         *
+         * @return any one of {@link PackageHealthObserverImpact} to express the impact
+         * to the user on {@link #execute}
+         */
+        @PackageHealthObserverImpact int onHealthCheckFailed(
+                @Nullable VersionedPackage versionedPackage,
+                @FailureReasons int failureReason,
+                int mitigationCount);
+
+        /**
+         * Executes mitigation for {@link #onHealthCheckFailed}.
+         *
+         * @param versionedPackage the package that is failing. This may be null if a native
+         *                          service is crashing.
+         * @param failureReason   the type of failure that is occurring.
+         * @param mitigationCount the number of times mitigation has been called for this package
+         *                        (including this time).
+         * @return {@code true} if action was executed successfully, {@code false} otherwise
+         */
+        boolean execute(@Nullable VersionedPackage versionedPackage,
+                @FailureReasons int failureReason, int mitigationCount);
+
+
+        /**
+         * Called when the system server has booted several times within a window of time, defined
+         * by {@link #mBootThreshold}
+         *
+         * @param mitigationCount the number of times mitigation has been attempted for this
+         *                        boot loop (including this time).
+         */
+        default @PackageHealthObserverImpact int onBootLoop(int mitigationCount) {
+            return PackageHealthObserverImpact.USER_IMPACT_LEVEL_0;
+        }
+
+        /**
+         * Executes mitigation for {@link #onBootLoop}
+         * @param mitigationCount the number of times mitigation has been attempted for this
+         *                        boot loop (including this time).
+         */
+        default boolean executeBootLoopMitigation(int mitigationCount) {
+            return false;
+        }
+
+        // TODO(b/120598832): Ensure uniqueness?
+        /**
+         * Identifier for the observer, should not change across device updates otherwise the
+         * watchdog may drop observing packages with the old name.
+         */
+        @NonNull String getUniqueIdentifier();
+
+        /**
+         * An observer will not be pruned if this is set, even if the observer is not explicitly
+         * monitoring any packages.
+         */
+        default boolean isPersistent() {
+            return false;
+        }
+
+        /**
+         * Returns {@code true} if this observer wishes to observe the given package, {@code false}
+         * otherwise
+         *
+         * <p> A persistent observer may choose to start observing certain failing packages, even if
+         * it has not explicitly asked to watch the package with {@link #startObservingHealth}.
+         */
+        default boolean mayObservePackage(@NonNull String packageName) {
+            return false;
+        }
+    }
+
+    @VisibleForTesting
+    long getTriggerFailureCount() {
+        synchronized (mLock) {
+            return mTriggerFailureCount;
+        }
+    }
+
+    @VisibleForTesting
+    long getTriggerFailureDurationMs() {
+        synchronized (mLock) {
+            return mTriggerFailureDurationMs;
+        }
+    }
+
+    /**
+     * Serializes and syncs health check requests with the {@link ExplicitHealthCheckController}.
+     */
+    private void syncRequestsAsync() {
+        mShortTaskHandler.removeCallbacks(mSyncRequests);
+        mShortTaskHandler.post(mSyncRequests);
+    }
+
+    /**
+     * Syncs health check requests with the {@link ExplicitHealthCheckController}.
+     * Calls to this must be serialized.
+     *
+     * @see #syncRequestsAsync
+     */
+    private void syncRequests() {
+        boolean syncRequired = false;
+        synchronized (mLock) {
+            if (mIsPackagesReady) {
+                Set<String> packages = getPackagesPendingHealthChecksLocked();
+                if (mSyncRequired || !packages.equals(mRequestedHealthCheckPackages)
+                        || packages.isEmpty()) {
+                    syncRequired = true;
+                    mRequestedHealthCheckPackages = packages;
+                }
+            } // else, we will sync requests when packages become ready
+        }
+
+        // Call outside lock to avoid holding lock when calling into the controller.
+        if (syncRequired) {
+            Slog.i(TAG, "Syncing health check requests for packages: "
+                    + mRequestedHealthCheckPackages);
+            mHealthCheckController.syncRequests(mRequestedHealthCheckPackages);
+            mSyncRequired = false;
+        }
+    }
+
+    /**
+     * Updates the observers monitoring {@code packageName} that explicit health check has passed.
+     *
+     * <p> This update is strictly for registered observers at the time of the call
+     * Observers that register after this signal will have no knowledge of prior signals and will
+     * effectively behave as if the explicit health check hasn't passed for {@code packageName}.
+     *
+     * <p> {@code packageName} can still be considered failed if reported by
+     * {@link #onPackageFailureLocked} before the package expires.
+     *
+     * <p> Triggered by components outside the system server when they are fully functional after an
+     * update.
+     */
+    private void onHealthCheckPassed(String packageName) {
+        Slog.i(TAG, "Health check passed for package: " + packageName);
+        boolean isStateChanged = false;
+
+        synchronized (mLock) {
+            for (int observerIdx = 0; observerIdx < mAllObservers.size(); observerIdx++) {
+                ObserverInternal observer = mAllObservers.valueAt(observerIdx);
+                MonitoredPackage monitoredPackage = observer.getMonitoredPackage(packageName);
+
+                if (monitoredPackage != null) {
+                    int oldState = monitoredPackage.getHealthCheckStateLocked();
+                    int newState = monitoredPackage.tryPassHealthCheckLocked();
+                    isStateChanged |= oldState != newState;
+                }
+            }
+        }
+
+        if (isStateChanged) {
+            syncState("health check passed for " + packageName);
+        }
+    }
+
+    private void onSupportedPackages(List<PackageConfig> supportedPackages) {
+        boolean isStateChanged = false;
+
+        Map<String, Long> supportedPackageTimeouts = new ArrayMap<>();
+        Iterator<PackageConfig> it = supportedPackages.iterator();
+        while (it.hasNext()) {
+            PackageConfig info = it.next();
+            supportedPackageTimeouts.put(info.getPackageName(), info.getHealthCheckTimeoutMillis());
+        }
+
+        synchronized (mLock) {
+            Slog.d(TAG, "Received supported packages " + supportedPackages);
+            Iterator<ObserverInternal> oit = mAllObservers.values().iterator();
+            while (oit.hasNext()) {
+                Iterator<MonitoredPackage> pit = oit.next().getMonitoredPackages()
+                        .values().iterator();
+                while (pit.hasNext()) {
+                    MonitoredPackage monitoredPackage = pit.next();
+                    String packageName = monitoredPackage.getName();
+                    int oldState = monitoredPackage.getHealthCheckStateLocked();
+                    int newState;
+
+                    if (supportedPackageTimeouts.containsKey(packageName)) {
+                        // Supported packages become ACTIVE if currently INACTIVE
+                        newState = monitoredPackage.setHealthCheckActiveLocked(
+                                supportedPackageTimeouts.get(packageName));
+                    } else {
+                        // Unsupported packages are marked as PASSED unless already FAILED
+                        newState = monitoredPackage.tryPassHealthCheckLocked();
+                    }
+                    isStateChanged |= oldState != newState;
+                }
+            }
+        }
+
+        if (isStateChanged) {
+            syncState("updated health check supported packages " + supportedPackages);
+        }
+    }
+
+    private void onSyncRequestNotified() {
+        synchronized (mLock) {
+            mSyncRequired = true;
+            syncRequestsAsync();
+        }
+    }
+
+    @GuardedBy("mLock")
+    private Set<String> getPackagesPendingHealthChecksLocked() {
+        Set<String> packages = new ArraySet<>();
+        Iterator<ObserverInternal> oit = mAllObservers.values().iterator();
+        while (oit.hasNext()) {
+            ObserverInternal observer = oit.next();
+            Iterator<MonitoredPackage> pit =
+                    observer.getMonitoredPackages().values().iterator();
+            while (pit.hasNext()) {
+                MonitoredPackage monitoredPackage = pit.next();
+                String packageName = monitoredPackage.getName();
+                if (monitoredPackage.isPendingHealthChecksLocked()) {
+                    packages.add(packageName);
+                }
+            }
+        }
+        return packages;
+    }
+
+    /**
+     * Syncs the state of the observers.
+     *
+     * <p> Prunes all observers, saves new state to disk, syncs health check requests with the
+     * health check service and schedules the next state sync.
+     */
+    private void syncState(String reason) {
+        synchronized (mLock) {
+            Slog.i(TAG, "Syncing state, reason: " + reason);
+            pruneObserversLocked();
+
+            saveToFileAsync();
+            syncRequestsAsync();
+
+            // Done syncing state, schedule the next state sync
+            scheduleNextSyncStateLocked();
+        }
+    }
+
+    private void syncStateWithScheduledReason() {
+        syncState("scheduled");
+    }
+
+    @GuardedBy("mLock")
+    private void scheduleNextSyncStateLocked() {
+        long durationMs = getNextStateSyncMillisLocked();
+        mShortTaskHandler.removeCallbacks(mSyncStateWithScheduledReason);
+        if (durationMs == Long.MAX_VALUE) {
+            Slog.i(TAG, "Cancelling state sync, nothing to sync");
+            mUptimeAtLastStateSync = 0;
+        } else {
+            mUptimeAtLastStateSync = mSystemClock.uptimeMillis();
+            mShortTaskHandler.postDelayed(mSyncStateWithScheduledReason, durationMs);
+        }
+    }
+
+    /**
+     * Returns the next duration in millis to sync the watchdog state.
+     *
+     * @returns Long#MAX_VALUE if there are no observed packages.
+     */
+    @GuardedBy("mLock")
+    private long getNextStateSyncMillisLocked() {
+        long shortestDurationMs = Long.MAX_VALUE;
+        for (int oIndex = 0; oIndex < mAllObservers.size(); oIndex++) {
+            ArrayMap<String, MonitoredPackage> packages = mAllObservers.valueAt(oIndex)
+                    .getMonitoredPackages();
+            for (int pIndex = 0; pIndex < packages.size(); pIndex++) {
+                MonitoredPackage mp = packages.valueAt(pIndex);
+                long duration = mp.getShortestScheduleDurationMsLocked();
+                if (duration < shortestDurationMs) {
+                    shortestDurationMs = duration;
+                }
+            }
+        }
+        return shortestDurationMs;
+    }
+
+    /**
+     * Removes {@code elapsedMs} milliseconds from all durations on monitored packages
+     * and updates other internal state.
+     */
+    @GuardedBy("mLock")
+    private void pruneObserversLocked() {
+        long elapsedMs = mUptimeAtLastStateSync == 0
+                ? 0 : mSystemClock.uptimeMillis() - mUptimeAtLastStateSync;
+        if (elapsedMs <= 0) {
+            Slog.i(TAG, "Not pruning observers, elapsed time: " + elapsedMs + "ms");
+            return;
+        }
+
+        Iterator<ObserverInternal> it = mAllObservers.values().iterator();
+        while (it.hasNext()) {
+            ObserverInternal observer = it.next();
+            Set<MonitoredPackage> failedPackages =
+                    observer.prunePackagesLocked(elapsedMs);
+            if (!failedPackages.isEmpty()) {
+                onHealthCheckFailed(observer, failedPackages);
+            }
+            if (observer.getMonitoredPackages().isEmpty() && (observer.registeredObserver == null
+                    || !observer.registeredObserver.isPersistent())) {
+                Slog.i(TAG, "Discarding observer " + observer.name + ". All packages expired");
+                it.remove();
+            }
+        }
+    }
+
+    private void onHealthCheckFailed(ObserverInternal observer,
+            Set<MonitoredPackage> failedPackages) {
+        mLongTaskHandler.post(() -> {
+            synchronized (mLock) {
+                PackageHealthObserver registeredObserver = observer.registeredObserver;
+                if (registeredObserver != null) {
+                    Iterator<MonitoredPackage> it = failedPackages.iterator();
+                    while (it.hasNext()) {
+                        VersionedPackage versionedPkg = getVersionedPackage(it.next().getName());
+                        if (versionedPkg != null) {
+                            Slog.i(TAG,
+                                    "Explicit health check failed for package " + versionedPkg);
+                            registeredObserver.execute(versionedPkg,
+                                    PackageWatchdog.FAILURE_REASON_EXPLICIT_HEALTH_CHECK, 1);
+                        }
+                    }
+                }
+            }
+        });
+    }
+
+    /**
+     * Gets PackageInfo for the given package. Matches any user and apex.
+     *
+     * @throws PackageManager.NameNotFoundException if no such package is installed.
+     */
+    private PackageInfo getPackageInfo(String packageName)
+            throws PackageManager.NameNotFoundException {
+        PackageManager pm = mContext.getPackageManager();
+        try {
+            // The MATCH_ANY_USER flag doesn't mix well with the MATCH_APEX
+            // flag, so make two separate attempts to get the package info.
+            // We don't need both flags at the same time because we assume
+            // apex files are always installed for all users.
+            return pm.getPackageInfo(packageName, PackageManager.MATCH_ANY_USER);
+        } catch (PackageManager.NameNotFoundException e) {
+            return pm.getPackageInfo(packageName, PackageManager.MATCH_APEX);
+        }
+    }
+
+    @Nullable
+    private VersionedPackage getVersionedPackage(String packageName) {
+        final PackageManager pm = mContext.getPackageManager();
+        if (pm == null || TextUtils.isEmpty(packageName)) {
+            return null;
+        }
+        try {
+            final long versionCode = getPackageInfo(packageName).getLongVersionCode();
+            return new VersionedPackage(packageName, versionCode);
+        } catch (PackageManager.NameNotFoundException e) {
+            return null;
+        }
+    }
+
+    /**
+     * Loads mAllObservers from file.
+     *
+     * <p>Note that this is <b>not</b> thread safe and should only called be called
+     * from the constructor.
+     */
+    private void loadFromFile() {
+        InputStream infile = null;
+        mAllObservers.clear();
+        try {
+            infile = mPolicyFile.openRead();
+            final TypedXmlPullParser parser = Xml.resolvePullParser(infile);
+            XmlUtils.beginDocument(parser, TAG_PACKAGE_WATCHDOG);
+            int outerDepth = parser.getDepth();
+            while (XmlUtils.nextElementWithin(parser, outerDepth)) {
+                ObserverInternal observer = ObserverInternal.read(parser, this);
+                if (observer != null) {
+                    mAllObservers.put(observer.name, observer);
+                }
+            }
+        } catch (FileNotFoundException e) {
+            // Nothing to monitor
+        } catch (IOException | NumberFormatException | XmlPullParserException e) {
+            Slog.wtf(TAG, "Unable to read monitored packages, deleting file", e);
+            mPolicyFile.delete();
+        } finally {
+            IoUtils.closeQuietly(infile);
+        }
+    }
+
+    private void onPropertyChanged(DeviceConfig.Properties properties) {
+        try {
+            updateConfigs();
+        } catch (Exception ignore) {
+            Slog.w(TAG, "Failed to reload device config changes");
+        }
+    }
+
+    /** Adds a {@link DeviceConfig#OnPropertiesChangedListener}. */
+    private void setPropertyChangedListenerLocked() {
+        DeviceConfig.addOnPropertiesChangedListener(
+                DeviceConfig.NAMESPACE_ROLLBACK,
+                mContext.getMainExecutor(),
+                mOnPropertyChangedListener);
+    }
+
+    @VisibleForTesting
+    void removePropertyChangedListener() {
+        DeviceConfig.removeOnPropertiesChangedListener(mOnPropertyChangedListener);
+    }
+
+    /**
+     * Health check is enabled or disabled after reading the flags
+     * from DeviceConfig.
+     */
+    @VisibleForTesting
+    void updateConfigs() {
+        synchronized (mLock) {
+            mTriggerFailureCount = DeviceConfig.getInt(
+                    DeviceConfig.NAMESPACE_ROLLBACK,
+                    PROPERTY_WATCHDOG_TRIGGER_FAILURE_COUNT,
+                    DEFAULT_TRIGGER_FAILURE_COUNT);
+            if (mTriggerFailureCount <= 0) {
+                mTriggerFailureCount = DEFAULT_TRIGGER_FAILURE_COUNT;
+            }
+
+            mTriggerFailureDurationMs = DeviceConfig.getInt(
+                    DeviceConfig.NAMESPACE_ROLLBACK,
+                    PROPERTY_WATCHDOG_TRIGGER_DURATION_MILLIS,
+                    DEFAULT_TRIGGER_FAILURE_DURATION_MS);
+            if (mTriggerFailureDurationMs <= 0) {
+                mTriggerFailureDurationMs = DEFAULT_TRIGGER_FAILURE_DURATION_MS;
+            }
+
+            setExplicitHealthCheckEnabled(DeviceConfig.getBoolean(
+                    DeviceConfig.NAMESPACE_ROLLBACK,
+                    PROPERTY_WATCHDOG_EXPLICIT_HEALTH_CHECK_ENABLED,
+                    DEFAULT_EXPLICIT_HEALTH_CHECK_ENABLED));
+        }
+    }
+
+    /**
+     * Persists mAllObservers to file. Threshold information is ignored.
+     */
+    private boolean saveToFile() {
+        Slog.i(TAG, "Saving observer state to file");
+        synchronized (mLock) {
+            FileOutputStream stream;
+            try {
+                stream = mPolicyFile.startWrite();
+            } catch (IOException e) {
+                Slog.w(TAG, "Cannot update monitored packages", e);
+                return false;
+            }
+
+            try {
+                TypedXmlSerializer out = Xml.resolveSerializer(stream);
+                out.startDocument(null, true);
+                out.startTag(null, TAG_PACKAGE_WATCHDOG);
+                out.attributeInt(null, ATTR_VERSION, DB_VERSION);
+                for (int oIndex = 0; oIndex < mAllObservers.size(); oIndex++) {
+                    mAllObservers.valueAt(oIndex).writeLocked(out);
+                }
+                out.endTag(null, TAG_PACKAGE_WATCHDOG);
+                out.endDocument();
+                mPolicyFile.finishWrite(stream);
+                return true;
+            } catch (IOException e) {
+                Slog.w(TAG, "Failed to save monitored packages, restoring backup", e);
+                mPolicyFile.failWrite(stream);
+                return false;
+            } finally {
+                IoUtils.closeQuietly(stream);
+            }
+        }
+    }
+
+    private void saveToFileAsync() {
+        if (!mLongTaskHandler.hasCallbacks(mSaveToFile)) {
+            mLongTaskHandler.post(mSaveToFile);
+        }
+    }
+
+    /** @hide Convert a {@code LongArrayQueue} to a String of comma-separated values. */
+    public static String longArrayQueueToString(LongArrayQueue queue) {
+        if (queue.size() > 0) {
+            StringBuilder sb = new StringBuilder();
+            sb.append(queue.get(0));
+            for (int i = 1; i < queue.size(); i++) {
+                sb.append(",");
+                sb.append(queue.get(i));
+            }
+            return sb.toString();
+        }
+        return "";
+    }
+
+    /** @hide Parse a comma-separated String of longs into a LongArrayQueue. */
+    public static LongArrayQueue parseLongArrayQueue(String commaSeparatedValues) {
+        LongArrayQueue result = new LongArrayQueue();
+        if (!TextUtils.isEmpty(commaSeparatedValues)) {
+            String[] values = commaSeparatedValues.split(",");
+            for (String value : values) {
+                result.addLast(Long.parseLong(value));
+            }
+        }
+        return result;
+    }
+
+
+    /** Dump status of every observer in mAllObservers. */
+    public void dump(@NonNull PrintWriter pw) {
+        if (Flags.synchronousRebootInRescueParty() && RescueParty.isRecoveryTriggeredReboot()) {
+            dumpInternal(pw);
+        } else {
+            synchronized (mLock) {
+                dumpInternal(pw);
+            }
+        }
+    }
+
+    private void dumpInternal(@NonNull PrintWriter pw) {
+        IndentingPrintWriter ipw = new IndentingPrintWriter(pw, "  ");
+        ipw.println("Package Watchdog status");
+        ipw.increaseIndent();
+        synchronized (mLock) {
+            for (String observerName : mAllObservers.keySet()) {
+                ipw.println("Observer name: " + observerName);
+                ipw.increaseIndent();
+                ObserverInternal observerInternal = mAllObservers.get(observerName);
+                observerInternal.dump(ipw);
+                ipw.decreaseIndent();
+            }
+        }
+        ipw.decreaseIndent();
+        dumpCrashRecoveryEvents(ipw);
+    }
+
+    @VisibleForTesting
+    @GuardedBy("mLock")
+    void registerObserverInternal(ObserverInternal observerInternal) {
+        mAllObservers.put(observerInternal.name, observerInternal);
+    }
+
+    /**
+     * Represents an observer monitoring a set of packages along with the failure thresholds for
+     * each package.
+     *
+     * <p> Note, the PackageWatchdog#mLock must always be held when reading or writing
+     * instances of this class.
+     */
+    static class ObserverInternal {
+        public final String name;
+        @GuardedBy("mLock")
+        private final ArrayMap<String, MonitoredPackage> mPackages = new ArrayMap<>();
+        @Nullable
+        @GuardedBy("mLock")
+        public PackageHealthObserver registeredObserver;
+        private int mMitigationCount;
+
+        ObserverInternal(String name, List<MonitoredPackage> packages) {
+            this(name, packages, /*mitigationCount=*/ 0);
+        }
+
+        ObserverInternal(String name, List<MonitoredPackage> packages, int mitigationCount) {
+            this.name = name;
+            updatePackagesLocked(packages);
+            this.mMitigationCount = mitigationCount;
+        }
+
+        /**
+         * Writes important {@link MonitoredPackage} details for this observer to file.
+         * Does not persist any package failure thresholds.
+         */
+        @GuardedBy("mLock")
+        public boolean writeLocked(TypedXmlSerializer out) {
+            try {
+                out.startTag(null, TAG_OBSERVER);
+                out.attribute(null, ATTR_NAME, name);
+                if (Flags.recoverabilityDetection()) {
+                    out.attributeInt(null, ATTR_MITIGATION_COUNT, mMitigationCount);
+                }
+                for (int i = 0; i < mPackages.size(); i++) {
+                    MonitoredPackage p = mPackages.valueAt(i);
+                    p.writeLocked(out);
+                }
+                out.endTag(null, TAG_OBSERVER);
+                return true;
+            } catch (IOException e) {
+                Slog.w(TAG, "Cannot save observer", e);
+                return false;
+            }
+        }
+
+        public int getBootMitigationCount() {
+            return mMitigationCount;
+        }
+
+        public void setBootMitigationCount(int mitigationCount) {
+            mMitigationCount = mitigationCount;
+        }
+
+        @GuardedBy("mLock")
+        public void updatePackagesLocked(List<MonitoredPackage> packages) {
+            for (int pIndex = 0; pIndex < packages.size(); pIndex++) {
+                MonitoredPackage p = packages.get(pIndex);
+                MonitoredPackage existingPackage = getMonitoredPackage(p.getName());
+                if (existingPackage != null) {
+                    existingPackage.updateHealthCheckDuration(p.mDurationMs);
+                } else {
+                    putMonitoredPackage(p);
+                }
+            }
+        }
+
+        /**
+         * Reduces the monitoring durations of all packages observed by this observer by
+         * {@code elapsedMs}. If any duration is less than 0, the package is removed from
+         * observation. If any health check duration is less than 0, the health check result
+         * is evaluated.
+         *
+         * @return a {@link Set} of packages that were removed from the observer without explicit
+         * health check passing, or an empty list if no package expired for which an explicit health
+         * check was still pending
+         */
+        @GuardedBy("mLock")
+        private Set<MonitoredPackage> prunePackagesLocked(long elapsedMs) {
+            Set<MonitoredPackage> failedPackages = new ArraySet<>();
+            Iterator<MonitoredPackage> it = mPackages.values().iterator();
+            while (it.hasNext()) {
+                MonitoredPackage p = it.next();
+                int oldState = p.getHealthCheckStateLocked();
+                int newState = p.handleElapsedTimeLocked(elapsedMs);
+                if (oldState != HealthCheckState.FAILED
+                        && newState == HealthCheckState.FAILED) {
+                    Slog.i(TAG, "Package " + p.getName() + " failed health check");
+                    failedPackages.add(p);
+                }
+                if (p.isExpiredLocked()) {
+                    it.remove();
+                }
+            }
+            return failedPackages;
+        }
+
+        /**
+         * Increments failure counts of {@code packageName}.
+         * @returns {@code true} if failure threshold is exceeded, {@code false} otherwise
+         * @hide
+         */
+        @GuardedBy("mLock")
+        public boolean onPackageFailureLocked(String packageName) {
+            if (getMonitoredPackage(packageName) == null && registeredObserver.isPersistent()
+                    && registeredObserver.mayObservePackage(packageName)) {
+                putMonitoredPackage(sPackageWatchdog.newMonitoredPackage(
+                        packageName, DEFAULT_OBSERVING_DURATION_MS, false));
+            }
+            MonitoredPackage p = getMonitoredPackage(packageName);
+            if (p != null) {
+                return p.onFailureLocked();
+            }
+            return false;
+        }
+
+        /**
+         * Returns the map of packages monitored by this observer.
+         *
+         * @return a mapping of package names to {@link MonitoredPackage} objects.
+         */
+        @GuardedBy("mLock")
+        public ArrayMap<String, MonitoredPackage> getMonitoredPackages() {
+            return mPackages;
+        }
+
+        /**
+         * Returns the {@link MonitoredPackage} associated with a given package name if the
+         * package is being monitored by this observer.
+         *
+         * @param packageName: the name of the package.
+         * @return the {@link MonitoredPackage} object associated with the package name if one
+         *         exists, {@code null} otherwise.
+         */
+        @GuardedBy("mLock")
+        @Nullable
+        public MonitoredPackage getMonitoredPackage(String packageName) {
+            return mPackages.get(packageName);
+        }
+
+        /**
+         * Associates a {@link MonitoredPackage} with the observer.
+         *
+         * @param p: the {@link MonitoredPackage} to store.
+         */
+        @GuardedBy("mLock")
+        public void putMonitoredPackage(MonitoredPackage p) {
+            mPackages.put(p.getName(), p);
+        }
+
+        /**
+         * Returns one ObserverInternal from the {@code parser} and advances its state.
+         *
+         * <p>Note that this method is <b>not</b> thread safe. It should only be called from
+         * #loadFromFile which in turn is only called on construction of the
+         * singleton PackageWatchdog.
+         **/
+        public static ObserverInternal read(TypedXmlPullParser parser, PackageWatchdog watchdog) {
+            String observerName = null;
+            int observerMitigationCount = 0;
+            if (TAG_OBSERVER.equals(parser.getName())) {
+                observerName = parser.getAttributeValue(null, ATTR_NAME);
+                if (TextUtils.isEmpty(observerName)) {
+                    Slog.wtf(TAG, "Unable to read observer name");
+                    return null;
+                }
+            }
+            List<MonitoredPackage> packages = new ArrayList<>();
+            int innerDepth = parser.getDepth();
+            try {
+                if (Flags.recoverabilityDetection()) {
+                    try {
+                        observerMitigationCount =
+                                parser.getAttributeInt(null, ATTR_MITIGATION_COUNT);
+                    } catch (XmlPullParserException e) {
+                        Slog.i(
+                            TAG,
+                            "ObserverInternal mitigation count was not present.");
+                    }
+                }
+                while (XmlUtils.nextElementWithin(parser, innerDepth)) {
+                    if (TAG_PACKAGE.equals(parser.getName())) {
+                        try {
+                            MonitoredPackage pkg = watchdog.parseMonitoredPackage(parser);
+                            if (pkg != null) {
+                                packages.add(pkg);
+                            }
+                        } catch (NumberFormatException e) {
+                            Slog.wtf(TAG, "Skipping package for observer " + observerName, e);
+                            continue;
+                        }
+                    }
+                }
+            } catch (XmlPullParserException | IOException e) {
+                Slog.wtf(TAG, "Unable to read observer " + observerName, e);
+                return null;
+            }
+            if (packages.isEmpty()) {
+                return null;
+            }
+            return new ObserverInternal(observerName, packages, observerMitigationCount);
+        }
+
+        /** Dumps information about this observer and the packages it watches. */
+        public void dump(IndentingPrintWriter pw) {
+            boolean isPersistent = registeredObserver != null && registeredObserver.isPersistent();
+            pw.println("Persistent: " + isPersistent);
+            for (String packageName : mPackages.keySet()) {
+                MonitoredPackage p = getMonitoredPackage(packageName);
+                pw.println(packageName +  ": ");
+                pw.increaseIndent();
+                pw.println("# Failures: " + p.mFailureHistory.size());
+                pw.println("Monitoring duration remaining: " + p.mDurationMs + "ms");
+                pw.println("Explicit health check duration: " + p.mHealthCheckDurationMs + "ms");
+                pw.println("Health check state: " + p.toString(p.mHealthCheckState));
+                pw.decreaseIndent();
+            }
+        }
+    }
+
+    /** @hide */
+    @Retention(SOURCE)
+    @IntDef(value = {
+            HealthCheckState.ACTIVE,
+            HealthCheckState.INACTIVE,
+            HealthCheckState.PASSED,
+            HealthCheckState.FAILED})
+    public @interface HealthCheckState {
+        // The package has not passed health check but has requested a health check
+        int ACTIVE = 0;
+        // The package has not passed health check and has not requested a health check
+        int INACTIVE = 1;
+        // The package has passed health check
+        int PASSED = 2;
+        // The package has failed health check
+        int FAILED = 3;
+    }
+
+    MonitoredPackage newMonitoredPackage(
+            String name, long durationMs, boolean hasPassedHealthCheck) {
+        return newMonitoredPackage(name, durationMs, Long.MAX_VALUE, hasPassedHealthCheck,
+                new LongArrayQueue());
+    }
+
+    MonitoredPackage newMonitoredPackage(String name, long durationMs, long healthCheckDurationMs,
+            boolean hasPassedHealthCheck, LongArrayQueue mitigationCalls) {
+        return new MonitoredPackage(name, durationMs, healthCheckDurationMs,
+                hasPassedHealthCheck, mitigationCalls);
+    }
+
+    MonitoredPackage parseMonitoredPackage(TypedXmlPullParser parser)
+            throws XmlPullParserException {
+        String packageName = parser.getAttributeValue(null, ATTR_NAME);
+        long duration = parser.getAttributeLong(null, ATTR_DURATION);
+        long healthCheckDuration = parser.getAttributeLong(null,
+                        ATTR_EXPLICIT_HEALTH_CHECK_DURATION);
+        boolean hasPassedHealthCheck = parser.getAttributeBoolean(null, ATTR_PASSED_HEALTH_CHECK);
+        LongArrayQueue mitigationCalls = parseLongArrayQueue(
+                parser.getAttributeValue(null, ATTR_MITIGATION_CALLS));
+        return newMonitoredPackage(packageName,
+                duration, healthCheckDuration, hasPassedHealthCheck, mitigationCalls);
+    }
+
+    /**
+     * Represents a package and its health check state along with the time
+     * it should be monitored for.
+     *
+     * <p> Note, the PackageWatchdog#mLock must always be held when reading or writing
+     * instances of this class.
+     */
+    class MonitoredPackage {
+        private final String mPackageName;
+        // Times when package failures happen sorted in ascending order
+        @GuardedBy("mLock")
+        private final LongArrayQueue mFailureHistory = new LongArrayQueue();
+        // Times when an observer was called to mitigate this package's failure. Sorted in
+        // ascending order.
+        @GuardedBy("mLock")
+        private final LongArrayQueue mMitigationCalls;
+        // One of STATE_[ACTIVE|INACTIVE|PASSED|FAILED]. Updated on construction and after
+        // methods that could change the health check state: handleElapsedTimeLocked and
+        // tryPassHealthCheckLocked
+        private int mHealthCheckState = HealthCheckState.INACTIVE;
+        // Whether an explicit health check has passed.
+        // This value in addition with mHealthCheckDurationMs determines the health check state
+        // of the package, see #getHealthCheckStateLocked
+        @GuardedBy("mLock")
+        private boolean mHasPassedHealthCheck;
+        // System uptime duration to monitor package.
+        @GuardedBy("mLock")
+        private long mDurationMs;
+        // System uptime duration to check the result of an explicit health check
+        // Initially, MAX_VALUE until we get a value from the health check service
+        // and request health checks.
+        // This value in addition with mHasPassedHealthCheck determines the health check state
+        // of the package, see #getHealthCheckStateLocked
+        @GuardedBy("mLock")
+        private long mHealthCheckDurationMs = Long.MAX_VALUE;
+
+        MonitoredPackage(String packageName, long durationMs,
+                long healthCheckDurationMs, boolean hasPassedHealthCheck,
+                LongArrayQueue mitigationCalls) {
+            mPackageName = packageName;
+            mDurationMs = durationMs;
+            mHealthCheckDurationMs = healthCheckDurationMs;
+            mHasPassedHealthCheck = hasPassedHealthCheck;
+            mMitigationCalls = mitigationCalls;
+            updateHealthCheckStateLocked();
+        }
+
+        /** Writes the salient fields to disk using {@code out}.
+         * @hide
+         */
+        @GuardedBy("mLock")
+        public void writeLocked(TypedXmlSerializer out) throws IOException {
+            out.startTag(null, TAG_PACKAGE);
+            out.attribute(null, ATTR_NAME, getName());
+            out.attributeLong(null, ATTR_DURATION, mDurationMs);
+            out.attributeLong(null, ATTR_EXPLICIT_HEALTH_CHECK_DURATION, mHealthCheckDurationMs);
+            out.attributeBoolean(null, ATTR_PASSED_HEALTH_CHECK, mHasPassedHealthCheck);
+            LongArrayQueue normalizedCalls = normalizeMitigationCalls();
+            out.attribute(null, ATTR_MITIGATION_CALLS, longArrayQueueToString(normalizedCalls));
+            out.endTag(null, TAG_PACKAGE);
+        }
+
+        /**
+         * Increment package failures or resets failure count depending on the last package failure.
+         *
+         * @return {@code true} if failure count exceeds a threshold, {@code false} otherwise
+         */
+        @GuardedBy("mLock")
+        public boolean onFailureLocked() {
+            // Sliding window algorithm: find out if there exists a window containing failures >=
+            // mTriggerFailureCount.
+            final long now = mSystemClock.uptimeMillis();
+            mFailureHistory.addLast(now);
+            while (now - mFailureHistory.peekFirst() > mTriggerFailureDurationMs) {
+                // Prune values falling out of the window
+                mFailureHistory.removeFirst();
+            }
+            boolean failed = mFailureHistory.size() >= mTriggerFailureCount;
+            if (failed) {
+                mFailureHistory.clear();
+            }
+            return failed;
+        }
+
+        /**
+         * Notes the timestamp of a mitigation call into the observer.
+         */
+        @GuardedBy("mLock")
+        public void noteMitigationCallLocked() {
+            mMitigationCalls.addLast(mSystemClock.uptimeMillis());
+        }
+
+        /**
+         * Prunes any mitigation calls outside of the de-escalation window, and returns the
+         * number of calls that are in the window afterwards.
+         *
+         * @return the number of mitigation calls made in the de-escalation window.
+         */
+        @GuardedBy("mLock")
+        public int getMitigationCountLocked() {
+            try {
+                final long now = mSystemClock.uptimeMillis();
+                while (now - mMitigationCalls.peekFirst() > DEFAULT_DEESCALATION_WINDOW_MS) {
+                    mMitigationCalls.removeFirst();
+                }
+            } catch (NoSuchElementException ignore) {
+            }
+
+            return mMitigationCalls.size();
+        }
+
+        /**
+         * Before writing to disk, make the mitigation call timestamps relative to the current
+         * system uptime. This is because they need to be relative to the uptime which will reset
+         * at the next boot.
+         *
+         * @return a LongArrayQueue of the mitigation calls relative to the current system uptime.
+         */
+        @GuardedBy("mLock")
+        public LongArrayQueue normalizeMitigationCalls() {
+            LongArrayQueue normalized = new LongArrayQueue();
+            final long now = mSystemClock.uptimeMillis();
+            for (int i = 0; i < mMitigationCalls.size(); i++) {
+                normalized.addLast(mMitigationCalls.get(i) - now);
+            }
+            return normalized;
+        }
+
+        /**
+         * Sets the initial health check duration.
+         *
+         * @return the new health check state
+         */
+        @GuardedBy("mLock")
+        public int setHealthCheckActiveLocked(long initialHealthCheckDurationMs) {
+            if (initialHealthCheckDurationMs <= 0) {
+                Slog.wtf(TAG, "Cannot set non-positive health check duration "
+                        + initialHealthCheckDurationMs + "ms for package " + getName()
+                        + ". Using total duration " + mDurationMs + "ms instead");
+                initialHealthCheckDurationMs = mDurationMs;
+            }
+            if (mHealthCheckState == HealthCheckState.INACTIVE) {
+                // Transitions to ACTIVE
+                mHealthCheckDurationMs = initialHealthCheckDurationMs;
+            }
+            return updateHealthCheckStateLocked();
+        }
+
+        /**
+         * Updates the monitoring durations of the package.
+         *
+         * @return the new health check state
+         */
+        @GuardedBy("mLock")
+        public int handleElapsedTimeLocked(long elapsedMs) {
+            if (elapsedMs <= 0) {
+                Slog.w(TAG, "Cannot handle non-positive elapsed time for package " + getName());
+                return mHealthCheckState;
+            }
+            // Transitions to FAILED if now <= 0 and health check not passed
+            mDurationMs -= elapsedMs;
+            if (mHealthCheckState == HealthCheckState.ACTIVE) {
+                // We only update health check durations if we have #setHealthCheckActiveLocked
+                // This ensures we don't leave the INACTIVE state for an unexpected elapsed time
+                // Transitions to FAILED if now <= 0 and health check not passed
+                mHealthCheckDurationMs -= elapsedMs;
+            }
+            return updateHealthCheckStateLocked();
+        }
+
+        /** Explicitly update the monitoring duration of the package. */
+        @GuardedBy("mLock")
+        public void updateHealthCheckDuration(long newDurationMs) {
+            mDurationMs = newDurationMs;
+        }
+
+        /**
+         * Marks the health check as passed and transitions to {@link HealthCheckState.PASSED}
+         * if not yet {@link HealthCheckState.FAILED}.
+         *
+         * @return the new {@link HealthCheckState health check state}
+         */
+        @GuardedBy("mLock")
+        @HealthCheckState
+        public int tryPassHealthCheckLocked() {
+            if (mHealthCheckState != HealthCheckState.FAILED) {
+                // FAILED is a final state so only pass if we haven't failed
+                // Transition to PASSED
+                mHasPassedHealthCheck = true;
+            }
+            return updateHealthCheckStateLocked();
+        }
+
+        /** Returns the monitored package name. */
+        private String getName() {
+            return mPackageName;
+        }
+
+        /**
+         * Returns the current {@link HealthCheckState health check state}.
+         */
+        @GuardedBy("mLock")
+        @HealthCheckState
+        public int getHealthCheckStateLocked() {
+            return mHealthCheckState;
+        }
+
+        /**
+         * Returns the shortest duration before the package should be scheduled for a prune.
+         *
+         * @return the duration or {@link Long#MAX_VALUE} if the package should not be scheduled
+         */
+        @GuardedBy("mLock")
+        public long getShortestScheduleDurationMsLocked() {
+            // Consider health check duration only if #isPendingHealthChecksLocked is true
+            return Math.min(toPositive(mDurationMs),
+                    isPendingHealthChecksLocked()
+                    ? toPositive(mHealthCheckDurationMs) : Long.MAX_VALUE);
+        }
+
+        /**
+         * Returns {@code true} if the total duration left to monitor the package is less than or
+         * equal to 0 {@code false} otherwise.
+         */
+        @GuardedBy("mLock")
+        public boolean isExpiredLocked() {
+            return mDurationMs <= 0;
+        }
+
+        /**
+         * Returns {@code true} if the package, {@link #getName} is expecting health check results
+         * {@code false} otherwise.
+         */
+        @GuardedBy("mLock")
+        public boolean isPendingHealthChecksLocked() {
+            return mHealthCheckState == HealthCheckState.ACTIVE
+                    || mHealthCheckState == HealthCheckState.INACTIVE;
+        }
+
+        /**
+         * Updates the health check state based on {@link #mHasPassedHealthCheck}
+         * and {@link #mHealthCheckDurationMs}.
+         *
+         * @return the new {@link HealthCheckState health check state}
+         */
+        @GuardedBy("mLock")
+        @HealthCheckState
+        private int updateHealthCheckStateLocked() {
+            int oldState = mHealthCheckState;
+            if (mHasPassedHealthCheck) {
+                // Set final state first to avoid ambiguity
+                mHealthCheckState = HealthCheckState.PASSED;
+            } else if (mHealthCheckDurationMs <= 0 || mDurationMs <= 0) {
+                // Set final state first to avoid ambiguity
+                mHealthCheckState = HealthCheckState.FAILED;
+            } else if (mHealthCheckDurationMs == Long.MAX_VALUE) {
+                mHealthCheckState = HealthCheckState.INACTIVE;
+            } else {
+                mHealthCheckState = HealthCheckState.ACTIVE;
+            }
+
+            if (oldState != mHealthCheckState) {
+                Slog.i(TAG, "Updated health check state for package " + getName() + ": "
+                        + toString(oldState) + " -> " + toString(mHealthCheckState));
+            }
+            return mHealthCheckState;
+        }
+
+        /** Returns a {@link String} representation of the current health check state. */
+        private String toString(@HealthCheckState int state) {
+            switch (state) {
+                case HealthCheckState.ACTIVE:
+                    return "ACTIVE";
+                case HealthCheckState.INACTIVE:
+                    return "INACTIVE";
+                case HealthCheckState.PASSED:
+                    return "PASSED";
+                case HealthCheckState.FAILED:
+                    return "FAILED";
+                default:
+                    return "UNKNOWN";
+            }
+        }
+
+        /** Returns {@code value} if it is greater than 0 or {@link Long#MAX_VALUE} otherwise. */
+        private long toPositive(long value) {
+            return value > 0 ? value : Long.MAX_VALUE;
+        }
+
+        /** Compares the equality of this object with another {@link MonitoredPackage}. */
+        @VisibleForTesting
+        boolean isEqualTo(MonitoredPackage pkg) {
+            return (getName().equals(pkg.getName()))
+                    && mDurationMs == pkg.mDurationMs
+                    && mHasPassedHealthCheck == pkg.mHasPassedHealthCheck
+                    && mHealthCheckDurationMs == pkg.mHealthCheckDurationMs
+                    && (mMitigationCalls.toString()).equals(pkg.mMitigationCalls.toString());
+        }
+    }
+
+    @GuardedBy("mLock")
+    @SuppressWarnings("GuardedBy")
+    void saveAllObserversBootMitigationCountToMetadata(String filePath) {
+        HashMap<String, Integer> bootMitigationCounts = new HashMap<>();
+        for (int i = 0; i < mAllObservers.size(); i++) {
+            final ObserverInternal observer = mAllObservers.valueAt(i);
+            bootMitigationCounts.put(observer.name, observer.getBootMitigationCount());
+        }
+
+        try {
+            FileOutputStream fileStream = new FileOutputStream(new File(filePath));
+            ObjectOutputStream objectStream = new ObjectOutputStream(fileStream);
+            objectStream.writeObject(bootMitigationCounts);
+            objectStream.flush();
+            objectStream.close();
+            fileStream.close();
+        } catch (Exception e) {
+            Slog.i(TAG, "Could not save observers metadata to file: " + e);
+        }
+    }
+
+    /**
+     * Handles the thresholding logic for system server boots.
+     */
+    class BootThreshold {
+
+        private final int mBootTriggerCount;
+        private final long mTriggerWindow;
+
+        BootThreshold(int bootTriggerCount, long triggerWindow) {
+            this.mBootTriggerCount = bootTriggerCount;
+            this.mTriggerWindow = triggerWindow;
+        }
+
+        public void reset() {
+            setStart(0);
+            setCount(0);
+        }
+
+        protected int getCount() {
+            return CrashRecoveryProperties.rescueBootCount().orElse(0);
+        }
+
+        protected void setCount(int count) {
+            CrashRecoveryProperties.rescueBootCount(count);
+        }
+
+        public long getStart() {
+            return CrashRecoveryProperties.rescueBootStart().orElse(0L);
+        }
+
+        public int getMitigationCount() {
+            return CrashRecoveryProperties.bootMitigationCount().orElse(0);
+        }
+
+        public void setStart(long start) {
+            CrashRecoveryProperties.rescueBootStart(getStartTime(start));
+        }
+
+        public void setMitigationStart(long start) {
+            CrashRecoveryProperties.bootMitigationStart(getStartTime(start));
+        }
+
+        public long getMitigationStart() {
+            return CrashRecoveryProperties.bootMitigationStart().orElse(0L);
+        }
+
+        public void setMitigationCount(int count) {
+            CrashRecoveryProperties.bootMitigationCount(count);
+        }
+
+        private static long constrain(long amount, long low, long high) {
+            return amount < low ? low : (amount > high ? high : amount);
+        }
+
+        public long getStartTime(long start) {
+            final long now = mSystemClock.uptimeMillis();
+            return constrain(start, 0, now);
+        }
+
+        public void saveMitigationCountToMetadata() {
+            try (BufferedWriter writer = new BufferedWriter(new FileWriter(METADATA_FILE))) {
+                writer.write(String.valueOf(getMitigationCount()));
+            } catch (Exception e) {
+                Slog.e(TAG, "Could not save metadata to file: " + e);
+            }
+        }
+
+        public void readMitigationCountFromMetadataIfNecessary() {
+            File bootPropsFile = new File(METADATA_FILE);
+            if (bootPropsFile.exists()) {
+                try (BufferedReader reader = new BufferedReader(new FileReader(METADATA_FILE))) {
+                    String mitigationCount = reader.readLine();
+                    setMitigationCount(Integer.parseInt(mitigationCount));
+                    bootPropsFile.delete();
+                } catch (Exception e) {
+                    Slog.i(TAG, "Could not read metadata file: " + e);
+                }
+            }
+        }
+
+
+        /** Increments the boot counter, and returns whether the device is bootlooping. */
+        @GuardedBy("mLock")
+        public boolean incrementAndTest() {
+            if (Flags.recoverabilityDetection()) {
+                readAllObserversBootMitigationCountIfNecessary(METADATA_FILE);
+            } else {
+                readMitigationCountFromMetadataIfNecessary();
+            }
+
+            final long now = mSystemClock.uptimeMillis();
+            if (now - getStart() < 0) {
+                Slog.e(TAG, "Window was less than zero. Resetting start to current time.");
+                setStart(now);
+                setMitigationStart(now);
+            }
+            if (now - getMitigationStart() > DEFAULT_DEESCALATION_WINDOW_MS) {
+                setMitigationStart(now);
+                if (Flags.recoverabilityDetection()) {
+                    resetAllObserversBootMitigationCount();
+                } else {
+                    setMitigationCount(0);
+                }
+            }
+            final long window = now - getStart();
+            if (window >= mTriggerWindow) {
+                setCount(1);
+                setStart(now);
+                return false;
+            } else {
+                int count = getCount() + 1;
+                setCount(count);
+                EventLog.writeEvent(LOG_TAG_RESCUE_NOTE, Process.ROOT_UID, count, window);
+                if (Flags.recoverabilityDetection()) {
+                    // After a reboot (e.g. by WARM_REBOOT or mainline rollback) we apply
+                    // mitigations without waiting for DEFAULT_BOOT_LOOP_TRIGGER_COUNT.
+                    return (count >= mBootTriggerCount)
+                            || (performedMitigationsDuringWindow() && count > 1);
+                }
+                return count >= mBootTriggerCount;
+            }
+        }
+
+        @GuardedBy("mLock")
+        private boolean performedMitigationsDuringWindow() {
+            for (ObserverInternal observerInternal: mAllObservers.values()) {
+                if (observerInternal.getBootMitigationCount() > 0) {
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        @GuardedBy("mLock")
+        private void resetAllObserversBootMitigationCount() {
+            for (int i = 0; i < mAllObservers.size(); i++) {
+                final ObserverInternal observer = mAllObservers.valueAt(i);
+                observer.setBootMitigationCount(0);
+            }
+            saveAllObserversBootMitigationCountToMetadata(METADATA_FILE);
+        }
+
+        @GuardedBy("mLock")
+        @SuppressWarnings("GuardedBy")
+        void readAllObserversBootMitigationCountIfNecessary(String filePath) {
+            File metadataFile = new File(filePath);
+            if (metadataFile.exists()) {
+                try {
+                    FileInputStream fileStream = new FileInputStream(metadataFile);
+                    ObjectInputStream objectStream = new ObjectInputStream(fileStream);
+                    HashMap<String, Integer> bootMitigationCounts =
+                            (HashMap<String, Integer>) objectStream.readObject();
+                    objectStream.close();
+                    fileStream.close();
+
+                    for (int i = 0; i < mAllObservers.size(); i++) {
+                        final ObserverInternal observer = mAllObservers.valueAt(i);
+                        if (bootMitigationCounts.containsKey(observer.name)) {
+                            observer.setBootMitigationCount(
+                                    bootMitigationCounts.get(observer.name));
+                        }
+                    }
+                } catch (Exception e) {
+                    Slog.i(TAG, "Could not read observer metadata file: " + e);
+                }
+            }
+        }
+    }
+
+    /**
+     * Register broadcast receiver for shutdown.
+     * We would save the observer state to persist across boots.
+     *
+     * @hide
+     */
+    public void registerShutdownBroadcastReceiver() {
+        BroadcastReceiver shutdownEventReceiver = new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                // Only write if intent is relevant to device reboot or shutdown.
+                String intentAction = intent.getAction();
+                if (ACTION_REBOOT.equals(intentAction)
+                        || ACTION_SHUTDOWN.equals(intentAction)) {
+                    writeNow();
+                }
+            }
+        };
+
+        // Setup receiver for device reboots or shutdowns.
+        IntentFilter filter = new IntentFilter(ACTION_REBOOT);
+        filter.addAction(ACTION_SHUTDOWN);
+        mContext.registerReceiverForAllUsers(shutdownEventReceiver, filter, null,
+                /* run on main thread */ null);
+    }
+}
diff --git a/packages/CrashRecovery/services/module/java/com/android/server/RescueParty.java b/packages/CrashRecovery/services/module/java/com/android/server/RescueParty.java
new file mode 100644
index 0000000..f1b2f6b
--- /dev/null
+++ b/packages/CrashRecovery/services/module/java/com/android/server/RescueParty.java
@@ -0,0 +1,990 @@
+/*
+ * 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.server;
+
+import static com.android.server.crashrecovery.CrashRecoveryUtils.logCrashRecoveryEvent;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.VersionedPackage;
+import android.crashrecovery.flags.Flags;
+import android.os.Build;
+import android.os.Environment;
+import android.os.PowerManager;
+import android.os.RecoverySystem;
+import android.os.SystemClock;
+import android.os.SystemProperties;
+import android.os.UserHandle;
+import android.provider.DeviceConfig;
+import android.provider.Settings;
+import android.sysprop.CrashRecoveryProperties;
+import android.text.TextUtils;
+import android.util.ArraySet;
+import android.util.ArrayUtils;
+import android.util.EventLog;
+import android.util.FileUtils;
+import android.util.Log;
+import android.util.Slog;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.PackageWatchdog.FailureReasons;
+import com.android.server.PackageWatchdog.PackageHealthObserver;
+import com.android.server.PackageWatchdog.PackageHealthObserverImpact;
+import com.android.server.crashrecovery.proto.CrashRecoveryStatsLog;
+
+import java.io.File;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Utilities to help rescue the system from crash loops. Callers are expected to
+ * report boot events and persistent app crashes, and if they happen frequently
+ * enough this class will slowly escalate through several rescue operations
+ * before finally rebooting and prompting the user if they want to wipe data as
+ * a last resort.
+ *
+ * @hide
+ */
+public class RescueParty {
+    @VisibleForTesting
+    static final String PROP_ENABLE_RESCUE = "persist.sys.enable_rescue";
+    @VisibleForTesting
+    static final int LEVEL_NONE = 0;
+    @VisibleForTesting
+    static final int LEVEL_RESET_SETTINGS_UNTRUSTED_DEFAULTS = 1;
+    @VisibleForTesting
+    static final int LEVEL_RESET_SETTINGS_UNTRUSTED_CHANGES = 2;
+    @VisibleForTesting
+    static final int LEVEL_RESET_SETTINGS_TRUSTED_DEFAULTS = 3;
+    @VisibleForTesting
+    static final int LEVEL_WARM_REBOOT = 4;
+    @VisibleForTesting
+    static final int LEVEL_FACTORY_RESET = 5;
+    @VisibleForTesting
+    static final int RESCUE_LEVEL_NONE = 0;
+    @VisibleForTesting
+    static final int RESCUE_LEVEL_SCOPED_DEVICE_CONFIG_RESET = 1;
+    @VisibleForTesting
+    static final int RESCUE_LEVEL_ALL_DEVICE_CONFIG_RESET = 2;
+    @VisibleForTesting
+    static final int RESCUE_LEVEL_WARM_REBOOT = 3;
+    @VisibleForTesting
+    static final int RESCUE_LEVEL_RESET_SETTINGS_UNTRUSTED_DEFAULTS = 4;
+    @VisibleForTesting
+    static final int RESCUE_LEVEL_RESET_SETTINGS_UNTRUSTED_CHANGES = 5;
+    @VisibleForTesting
+    static final int RESCUE_LEVEL_RESET_SETTINGS_TRUSTED_DEFAULTS = 6;
+    @VisibleForTesting
+    static final int RESCUE_LEVEL_FACTORY_RESET = 7;
+
+    @IntDef(prefix = { "RESCUE_LEVEL_" }, value = {
+        RESCUE_LEVEL_NONE,
+        RESCUE_LEVEL_SCOPED_DEVICE_CONFIG_RESET,
+        RESCUE_LEVEL_ALL_DEVICE_CONFIG_RESET,
+        RESCUE_LEVEL_WARM_REBOOT,
+        RESCUE_LEVEL_RESET_SETTINGS_UNTRUSTED_DEFAULTS,
+        RESCUE_LEVEL_RESET_SETTINGS_UNTRUSTED_CHANGES,
+        RESCUE_LEVEL_RESET_SETTINGS_TRUSTED_DEFAULTS,
+        RESCUE_LEVEL_FACTORY_RESET
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    @interface RescueLevels {}
+
+    @VisibleForTesting
+    static final String RESCUE_NON_REBOOT_LEVEL_LIMIT = "persist.sys.rescue_non_reboot_level_limit";
+    @VisibleForTesting
+    static final int DEFAULT_RESCUE_NON_REBOOT_LEVEL_LIMIT = RESCUE_LEVEL_WARM_REBOOT - 1;
+    @VisibleForTesting
+    static final String TAG = "RescueParty";
+    @VisibleForTesting
+    static final long DEFAULT_OBSERVING_DURATION_MS = TimeUnit.DAYS.toMillis(2);
+    @VisibleForTesting
+    static final int DEVICE_CONFIG_RESET_MODE = Settings.RESET_MODE_TRUSTED_DEFAULTS;
+    // The DeviceConfig namespace containing all RescueParty switches.
+    @VisibleForTesting
+    static final String NAMESPACE_CONFIGURATION = "configuration";
+    @VisibleForTesting
+    static final String NAMESPACE_TO_PACKAGE_MAPPING_FLAG =
+            "namespace_to_package_mapping";
+    @VisibleForTesting
+    static final long DEFAULT_FACTORY_RESET_THROTTLE_DURATION_MIN = 1440;
+
+    private static final String NAME = "rescue-party-observer";
+
+    private static final String PROP_DISABLE_RESCUE = "persist.sys.disable_rescue";
+    private static final String PROP_VIRTUAL_DEVICE = "ro.hardware.virtual_device";
+    private static final String PROP_DEVICE_CONFIG_DISABLE_FLAG =
+            "persist.device_config.configuration.disable_rescue_party";
+    private static final String PROP_DISABLE_FACTORY_RESET_FLAG =
+            "persist.device_config.configuration.disable_rescue_party_factory_reset";
+    private static final String PROP_THROTTLE_DURATION_MIN_FLAG =
+            "persist.device_config.configuration.rescue_party_throttle_duration_min";
+
+    private static final int PERSISTENT_MASK = ApplicationInfo.FLAG_PERSISTENT
+            | ApplicationInfo.FLAG_SYSTEM;
+
+    /**
+     * EventLog tags used when logging into the event log. Note the values must be sync with
+     * frameworks/base/services/core/java/com/android/server/EventLogTags.logtags to get correct
+     * name translation.
+     */
+    private static final int LOG_TAG_RESCUE_SUCCESS = 2902;
+    private static final int LOG_TAG_RESCUE_FAILURE = 2903;
+
+    /** Register the Rescue Party observer as a Package Watchdog health observer */
+    public static void registerHealthObserver(Context context) {
+        PackageWatchdog.getInstance(context).registerHealthObserver(
+                RescuePartyObserver.getInstance(context));
+    }
+
+    private static boolean isDisabled() {
+        // Check if we're explicitly enabled for testing
+        if (SystemProperties.getBoolean(PROP_ENABLE_RESCUE, false)) {
+            return false;
+        }
+
+        // We're disabled if the DeviceConfig disable flag is set to true.
+        // This is in case that an emergency rollback of the feature is needed.
+        if (SystemProperties.getBoolean(PROP_DEVICE_CONFIG_DISABLE_FLAG, false)) {
+            Slog.v(TAG, "Disabled because of DeviceConfig flag");
+            return true;
+        }
+
+        // We're disabled on all engineering devices
+        if (Build.TYPE.equals("eng")) {
+            Slog.v(TAG, "Disabled because of eng build");
+            return true;
+        }
+
+        // We're disabled on userdebug devices connected over USB, since that's
+        // a decent signal that someone is actively trying to debug the device,
+        // or that it's in a lab environment.
+        if (Build.TYPE.equals("userdebug") && isUsbActive()) {
+            Slog.v(TAG, "Disabled because of active USB connection");
+            return true;
+        }
+
+        // One last-ditch check
+        if (SystemProperties.getBoolean(PROP_DISABLE_RESCUE, false)) {
+            Slog.v(TAG, "Disabled because of manual property");
+            return true;
+        }
+
+        return false;
+    }
+
+    /**
+     * Check if we're currently attempting to reboot for a factory reset. This method must
+     * return true if RescueParty tries to reboot early during a boot loop, since the device
+     * will not be fully booted at this time.
+     */
+    public static boolean isRecoveryTriggeredReboot() {
+        return isFactoryResetPropertySet() || isRebootPropertySet();
+    }
+
+    static boolean isFactoryResetPropertySet() {
+        return CrashRecoveryProperties.attemptingFactoryReset().orElse(false);
+    }
+
+    static boolean isRebootPropertySet() {
+        return CrashRecoveryProperties.attemptingReboot().orElse(false);
+    }
+
+    protected static long getLastFactoryResetTimeMs() {
+        return CrashRecoveryProperties.lastFactoryResetTimeMs().orElse(0L);
+    }
+
+    protected static int getMaxRescueLevelAttempted() {
+        return CrashRecoveryProperties.maxRescueLevelAttempted().orElse(LEVEL_NONE);
+    }
+
+    protected static void setFactoryResetProperty(boolean value) {
+        CrashRecoveryProperties.attemptingFactoryReset(value);
+    }
+    protected static void setRebootProperty(boolean value) {
+        CrashRecoveryProperties.attemptingReboot(value);
+    }
+
+    protected static void setLastFactoryResetTimeMs(long value) {
+        CrashRecoveryProperties.lastFactoryResetTimeMs(value);
+    }
+
+    protected static void setMaxRescueLevelAttempted(int level) {
+        CrashRecoveryProperties.maxRescueLevelAttempted(level);
+    }
+
+    private static Set<String> getPresetNamespacesForPackages(List<String> packageNames) {
+        Set<String> resultSet = new ArraySet<String>();
+        if (!Flags.deprecateFlagsAndSettingsResets()) {
+            try {
+                String flagVal = DeviceConfig.getString(NAMESPACE_CONFIGURATION,
+                        NAMESPACE_TO_PACKAGE_MAPPING_FLAG, "");
+                String[] mappingEntries = flagVal.split(",");
+                for (int i = 0; i < mappingEntries.length; i++) {
+                    if (TextUtils.isEmpty(mappingEntries[i])) {
+                        continue;
+                    }
+                    String[] splitEntry = mappingEntries[i].split(":");
+                    if (splitEntry.length != 2) {
+                        throw new RuntimeException("Invalid mapping entry: " + mappingEntries[i]);
+                    }
+                    String namespace = splitEntry[0];
+                    String packageName = splitEntry[1];
+
+                    if (packageNames.contains(packageName)) {
+                        resultSet.add(namespace);
+                    }
+                }
+            } catch (Exception e) {
+                resultSet.clear();
+                Slog.e(TAG, "Failed to read preset package to namespaces mapping.", e);
+            } finally {
+                return resultSet;
+            }
+        } else {
+            return resultSet;
+        }
+    }
+
+    @VisibleForTesting
+    static long getElapsedRealtime() {
+        return SystemClock.elapsedRealtime();
+    }
+
+    private static class RescuePartyMonitorCallback implements DeviceConfig.MonitorCallback {
+        Context mContext;
+
+        RescuePartyMonitorCallback(Context context) {
+            this.mContext = context;
+        }
+
+        public void onNamespaceUpdate(@NonNull String updatedNamespace) {
+            if (!Flags.deprecateFlagsAndSettingsResets()) {
+                startObservingPackages(mContext, updatedNamespace);
+            }
+        }
+
+        public void onDeviceConfigAccess(@NonNull String callingPackage,
+                @NonNull String namespace) {
+
+            if (!Flags.deprecateFlagsAndSettingsResets()) {
+                RescuePartyObserver.getInstance(mContext).recordDeviceConfigAccess(
+                        callingPackage,
+                        namespace);
+            }
+        }
+    }
+
+    private static void startObservingPackages(Context context, @NonNull String updatedNamespace) {
+        if (!Flags.deprecateFlagsAndSettingsResets()) {
+            RescuePartyObserver rescuePartyObserver = RescuePartyObserver.getInstance(context);
+            Set<String> callingPackages = rescuePartyObserver.getCallingPackagesSet(
+                    updatedNamespace);
+            if (callingPackages == null) {
+                return;
+            }
+            List<String> callingPackageList = new ArrayList<>();
+            callingPackageList.addAll(callingPackages);
+            Slog.i(TAG, "Starting to observe: " + callingPackageList + ", updated namespace: "
+                    + updatedNamespace);
+            PackageWatchdog.getInstance(context).startObservingHealth(
+                    rescuePartyObserver,
+                    callingPackageList,
+                    DEFAULT_OBSERVING_DURATION_MS);
+        }
+    }
+
+    private static int getMaxRescueLevel(boolean mayPerformReboot) {
+        if (Flags.recoverabilityDetection()) {
+            if (!mayPerformReboot
+                    || SystemProperties.getBoolean(PROP_DISABLE_FACTORY_RESET_FLAG, false)) {
+                return SystemProperties.getInt(RESCUE_NON_REBOOT_LEVEL_LIMIT,
+                        DEFAULT_RESCUE_NON_REBOOT_LEVEL_LIMIT);
+            }
+            return RESCUE_LEVEL_FACTORY_RESET;
+        } else {
+            if (!mayPerformReboot
+                    || SystemProperties.getBoolean(PROP_DISABLE_FACTORY_RESET_FLAG, false)) {
+                return LEVEL_RESET_SETTINGS_TRUSTED_DEFAULTS;
+            }
+            return LEVEL_FACTORY_RESET;
+        }
+    }
+
+    private static int getMaxRescueLevel() {
+        if (!SystemProperties.getBoolean(PROP_DISABLE_FACTORY_RESET_FLAG, false)) {
+            return Level.factoryReset();
+        }
+        return Level.reboot();
+    }
+
+    /**
+     * Get the rescue level to perform if this is the n-th attempt at mitigating failure.
+     *
+     * @param mitigationCount: the mitigation attempt number (1 = first attempt etc.)
+     * @param mayPerformReboot: whether or not a reboot and factory reset may be performed
+     *                          for the given failure.
+     * @return the rescue level for the n-th mitigation attempt.
+     */
+    private static int getRescueLevel(int mitigationCount, boolean mayPerformReboot) {
+        if (!Flags.deprecateFlagsAndSettingsResets()) {
+            if (mitigationCount == 1) {
+                return LEVEL_RESET_SETTINGS_UNTRUSTED_DEFAULTS;
+            } else if (mitigationCount == 2) {
+                return LEVEL_RESET_SETTINGS_UNTRUSTED_CHANGES;
+            } else if (mitigationCount == 3) {
+                return LEVEL_RESET_SETTINGS_TRUSTED_DEFAULTS;
+            } else if (mitigationCount == 4) {
+                return Math.min(getMaxRescueLevel(mayPerformReboot), LEVEL_WARM_REBOOT);
+            } else if (mitigationCount >= 5) {
+                return Math.min(getMaxRescueLevel(mayPerformReboot), LEVEL_FACTORY_RESET);
+            } else {
+                Slog.w(TAG, "Expected positive mitigation count, was " + mitigationCount);
+                return LEVEL_NONE;
+            }
+        } else {
+            if (mitigationCount == 1) {
+                return Level.reboot();
+            } else if (mitigationCount >= 2) {
+                return Math.min(getMaxRescueLevel(), Level.factoryReset());
+            } else {
+                Slog.w(TAG, "Expected positive mitigation count, was " + mitigationCount);
+                return LEVEL_NONE;
+            }
+        }
+    }
+
+    /**
+     * Get the rescue level to perform if this is the n-th attempt at mitigating failure.
+     * When failedPackage is null then 1st and 2nd mitigation counts are redundant (scoped and
+     * all device config reset). Behaves as if one mitigation attempt was already done.
+     *
+     * @param mitigationCount the mitigation attempt number (1 = first attempt etc.).
+     * @param mayPerformReboot whether or not a reboot and factory reset may be performed
+     * for the given failure.
+     * @param failedPackage in case of bootloop this is null.
+     * @return the rescue level for the n-th mitigation attempt.
+     */
+    private static @RescueLevels int getRescueLevel(int mitigationCount, boolean mayPerformReboot,
+            @Nullable VersionedPackage failedPackage) {
+        // Skipping RESCUE_LEVEL_SCOPED_DEVICE_CONFIG_RESET since it's not defined without a failed
+        // package.
+        if (failedPackage == null && mitigationCount > 0) {
+            mitigationCount += 1;
+        }
+        if (mitigationCount == 1) {
+            return RESCUE_LEVEL_SCOPED_DEVICE_CONFIG_RESET;
+        } else if (mitigationCount == 2) {
+            return RESCUE_LEVEL_ALL_DEVICE_CONFIG_RESET;
+        } else if (mitigationCount == 3) {
+            return Math.min(getMaxRescueLevel(mayPerformReboot), RESCUE_LEVEL_WARM_REBOOT);
+        } else if (mitigationCount == 4) {
+            return Math.min(getMaxRescueLevel(mayPerformReboot),
+                    RESCUE_LEVEL_RESET_SETTINGS_UNTRUSTED_DEFAULTS);
+        } else if (mitigationCount == 5) {
+            return Math.min(getMaxRescueLevel(mayPerformReboot),
+                    RESCUE_LEVEL_RESET_SETTINGS_UNTRUSTED_CHANGES);
+        } else if (mitigationCount == 6) {
+            return Math.min(getMaxRescueLevel(mayPerformReboot),
+                    RESCUE_LEVEL_RESET_SETTINGS_TRUSTED_DEFAULTS);
+        } else if (mitigationCount >= 7) {
+            return Math.min(getMaxRescueLevel(mayPerformReboot), RESCUE_LEVEL_FACTORY_RESET);
+        } else {
+            return RESCUE_LEVEL_NONE;
+        }
+    }
+
+    /**
+     * Get the rescue level to perform if this is the n-th attempt at mitigating failure.
+     *
+     * @param mitigationCount the mitigation attempt number (1 = first attempt etc.).
+     * @return the rescue level for the n-th mitigation attempt.
+     */
+    private static @RescueLevels int getRescueLevel(int mitigationCount) {
+        if (mitigationCount == 1) {
+            return Level.reboot();
+        } else if (mitigationCount >= 2) {
+            return Math.min(getMaxRescueLevel(), Level.factoryReset());
+        } else {
+            return Level.none();
+        }
+    }
+
+    private static void executeRescueLevel(Context context, @Nullable String failedPackage,
+            int level) {
+        Slog.w(TAG, "Attempting rescue level " + levelToString(level));
+        try {
+            executeRescueLevelInternal(context, level, failedPackage);
+            EventLog.writeEvent(LOG_TAG_RESCUE_SUCCESS, level);
+            String successMsg = "Finished rescue level " + levelToString(level);
+            if (!TextUtils.isEmpty(failedPackage)) {
+                successMsg += " for package " + failedPackage;
+            }
+            logCrashRecoveryEvent(Log.DEBUG, successMsg);
+        } catch (Throwable t) {
+            logRescueException(level, failedPackage, t);
+        }
+    }
+
+    private static void executeRescueLevelInternal(Context context, int level, @Nullable
+            String failedPackage) throws Exception {
+        if (Flags.recoverabilityDetection()) {
+            executeRescueLevelInternalNew(context, level, failedPackage);
+        } else {
+            executeRescueLevelInternalOld(context, level, failedPackage);
+        }
+    }
+
+    private static void executeRescueLevelInternalOld(Context context, int level, @Nullable
+            String failedPackage) throws Exception {
+        CrashRecoveryStatsLog.write(CrashRecoveryStatsLog.RESCUE_PARTY_RESET_REPORTED,
+                level, levelToString(level));
+        // Try our best to reset all settings possible, and once finished
+        // rethrow any exception that we encountered
+        Exception res = null;
+        switch (level) {
+            case LEVEL_RESET_SETTINGS_UNTRUSTED_DEFAULTS:
+                break;
+            case LEVEL_RESET_SETTINGS_UNTRUSTED_CHANGES:
+                break;
+            case LEVEL_RESET_SETTINGS_TRUSTED_DEFAULTS:
+                break;
+            case LEVEL_WARM_REBOOT:
+                executeWarmReboot(context, level, failedPackage);
+                break;
+            case LEVEL_FACTORY_RESET:
+                // Before the completion of Reboot, if any crash happens then PackageWatchdog
+                // escalates to next level i.e. factory reset, as they happen in separate threads.
+                // Adding a check to prevent factory reset to execute before above reboot completes.
+                // Note: this reboot property is not persistent resets after reboot is completed.
+                if (isRebootPropertySet()) {
+                    return;
+                }
+                executeFactoryReset(context, level, failedPackage);
+                break;
+        }
+
+        if (res != null) {
+            throw res;
+        }
+    }
+
+    private static void executeRescueLevelInternalNew(Context context, @RescueLevels int level,
+            @Nullable String failedPackage) throws Exception {
+        CrashRecoveryStatsLog.write(CrashRecoveryStatsLog.RESCUE_PARTY_RESET_REPORTED,
+                level, levelToString(level));
+        switch (level) {
+            case RESCUE_LEVEL_SCOPED_DEVICE_CONFIG_RESET:
+                break;
+            case RESCUE_LEVEL_ALL_DEVICE_CONFIG_RESET:
+                break;
+            case RESCUE_LEVEL_WARM_REBOOT:
+                executeWarmReboot(context, level, failedPackage);
+                break;
+            case RESCUE_LEVEL_RESET_SETTINGS_UNTRUSTED_DEFAULTS:
+                // do nothing
+                break;
+            case RESCUE_LEVEL_RESET_SETTINGS_UNTRUSTED_CHANGES:
+                // do nothing
+                break;
+            case RESCUE_LEVEL_RESET_SETTINGS_TRUSTED_DEFAULTS:
+                // do nothing
+                break;
+            case RESCUE_LEVEL_FACTORY_RESET:
+                // Before the completion of Reboot, if any crash happens then PackageWatchdog
+                // escalates to next level i.e. factory reset, as they happen in separate threads.
+                // Adding a check to prevent factory reset to execute before above reboot completes.
+                // Note: this reboot property is not persistent resets after reboot is completed.
+                if (isRebootPropertySet()) {
+                    return;
+                }
+                executeFactoryReset(context, level, failedPackage);
+                break;
+        }
+    }
+
+    private static void executeWarmReboot(Context context, int level,
+            @Nullable String failedPackage) {
+        if (Flags.deprecateFlagsAndSettingsResets()) {
+            if (shouldThrottleReboot()) {
+                return;
+            }
+        }
+
+        // Request the reboot from a separate thread to avoid deadlock on PackageWatchdog
+        // when device shutting down.
+        setRebootProperty(true);
+
+        if (Flags.synchronousRebootInRescueParty()) {
+            try {
+                PowerManager pm = context.getSystemService(PowerManager.class);
+                if (pm != null) {
+                    pm.reboot(TAG);
+                }
+            } catch (Throwable t) {
+                logRescueException(level, failedPackage, t);
+            }
+        } else {
+            Runnable runnable = () -> {
+                try {
+                    PowerManager pm = context.getSystemService(PowerManager.class);
+                    if (pm != null) {
+                        pm.reboot(TAG);
+                    }
+                } catch (Throwable t) {
+                    logRescueException(level, failedPackage, t);
+                }
+            };
+            Thread thread = new Thread(runnable);
+            thread.start();
+        }
+    }
+
+    private static void executeFactoryReset(Context context, int level,
+            @Nullable String failedPackage) {
+        if (Flags.deprecateFlagsAndSettingsResets()) {
+            if (shouldThrottleReboot()) {
+                return;
+            }
+        }
+        setFactoryResetProperty(true);
+        long now = System.currentTimeMillis();
+        setLastFactoryResetTimeMs(now);
+
+        if (Flags.synchronousRebootInRescueParty()) {
+            try {
+                RecoverySystem.rebootPromptAndWipeUserData(context, TAG + "," + failedPackage);
+            } catch (Throwable t) {
+                logRescueException(level, failedPackage, t);
+            }
+        } else {
+            Runnable runnable = new Runnable() {
+                @Override
+                public void run() {
+                    try {
+                        RecoverySystem.rebootPromptAndWipeUserData(context,
+                            TAG + "," + failedPackage);
+                    } catch (Throwable t) {
+                        logRescueException(level, failedPackage, t);
+                    }
+                }
+            };
+            Thread thread = new Thread(runnable);
+            thread.start();
+        }
+    }
+
+
+    private static String getCompleteMessage(Throwable t) {
+        final StringBuilder builder = new StringBuilder();
+        builder.append(t.getMessage());
+        while ((t = t.getCause()) != null) {
+            builder.append(": ").append(t.getMessage());
+        }
+        return builder.toString();
+    }
+
+    private static void logRescueException(int level, @Nullable String failedPackageName,
+            Throwable t) {
+        final String msg = getCompleteMessage(t);
+        EventLog.writeEvent(LOG_TAG_RESCUE_FAILURE, level, msg);
+        String failureMsg = "Failed rescue level " + levelToString(level);
+        if (!TextUtils.isEmpty(failedPackageName)) {
+            failureMsg += " for package " + failedPackageName;
+        }
+        logCrashRecoveryEvent(Log.ERROR, failureMsg + ": " + msg);
+    }
+
+    private static int mapRescueLevelToUserImpact(int rescueLevel) {
+        if (Flags.recoverabilityDetection()) {
+            switch (rescueLevel) {
+                case RESCUE_LEVEL_SCOPED_DEVICE_CONFIG_RESET:
+                    return PackageHealthObserverImpact.USER_IMPACT_LEVEL_10;
+                case RESCUE_LEVEL_ALL_DEVICE_CONFIG_RESET:
+                    return PackageHealthObserverImpact.USER_IMPACT_LEVEL_40;
+                case RESCUE_LEVEL_WARM_REBOOT:
+                    return PackageHealthObserverImpact.USER_IMPACT_LEVEL_50;
+                case RESCUE_LEVEL_RESET_SETTINGS_UNTRUSTED_DEFAULTS:
+                    return PackageHealthObserverImpact.USER_IMPACT_LEVEL_71;
+                case RESCUE_LEVEL_RESET_SETTINGS_UNTRUSTED_CHANGES:
+                    return PackageHealthObserverImpact.USER_IMPACT_LEVEL_75;
+                case RESCUE_LEVEL_RESET_SETTINGS_TRUSTED_DEFAULTS:
+                    return PackageHealthObserverImpact.USER_IMPACT_LEVEL_80;
+                case RESCUE_LEVEL_FACTORY_RESET:
+                    return PackageHealthObserverImpact.USER_IMPACT_LEVEL_100;
+                default:
+                    return PackageHealthObserverImpact.USER_IMPACT_LEVEL_0;
+            }
+        } else {
+            switch (rescueLevel) {
+                case LEVEL_RESET_SETTINGS_UNTRUSTED_DEFAULTS:
+                case LEVEL_RESET_SETTINGS_UNTRUSTED_CHANGES:
+                    return PackageHealthObserverImpact.USER_IMPACT_LEVEL_10;
+                case LEVEL_RESET_SETTINGS_TRUSTED_DEFAULTS:
+                case LEVEL_WARM_REBOOT:
+                    return PackageHealthObserverImpact.USER_IMPACT_LEVEL_50;
+                case LEVEL_FACTORY_RESET:
+                    return PackageHealthObserverImpact.USER_IMPACT_LEVEL_100;
+                default:
+                    return PackageHealthObserverImpact.USER_IMPACT_LEVEL_0;
+            }
+        }
+    }
+
+    /**
+     * Handle mitigation action for package failures. This observer will be register to Package
+     * Watchdog and will receive calls about package failures. This observer is persistent so it
+     * may choose to mitigate failures for packages it has not explicitly asked to observe.
+     */
+    public static class RescuePartyObserver implements PackageHealthObserver {
+
+        private final Context mContext;
+        private final Map<String, Set<String>> mCallingPackageNamespaceSetMap = new HashMap<>();
+        private final Map<String, Set<String>> mNamespaceCallingPackageSetMap = new HashMap<>();
+
+        @GuardedBy("RescuePartyObserver.class")
+        static RescuePartyObserver sRescuePartyObserver;
+
+        private RescuePartyObserver(Context context) {
+            mContext = context;
+        }
+
+        /** Creates or gets singleton instance of RescueParty. */
+        public static RescuePartyObserver getInstance(Context context) {
+            synchronized (RescuePartyObserver.class) {
+                if (sRescuePartyObserver == null) {
+                    sRescuePartyObserver = new RescuePartyObserver(context);
+                }
+                return sRescuePartyObserver;
+            }
+        }
+
+        /** Gets singleton instance. It returns null if the instance is not created yet.*/
+        @Nullable
+        public static RescuePartyObserver getInstanceIfCreated() {
+            synchronized (RescuePartyObserver.class) {
+                return sRescuePartyObserver;
+            }
+        }
+
+        @VisibleForTesting
+        static void reset() {
+            synchronized (RescuePartyObserver.class) {
+                sRescuePartyObserver = null;
+            }
+        }
+
+        @Override
+        public int onHealthCheckFailed(@Nullable VersionedPackage failedPackage,
+                @FailureReasons int failureReason, int mitigationCount) {
+            int impact = PackageHealthObserverImpact.USER_IMPACT_LEVEL_0;
+            if (!isDisabled() && (failureReason == PackageWatchdog.FAILURE_REASON_APP_CRASH
+                    || failureReason == PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING)) {
+                if (Flags.recoverabilityDetection()) {
+                    if (!Flags.deprecateFlagsAndSettingsResets()) {
+                        impact =  mapRescueLevelToUserImpact(getRescueLevel(mitigationCount,
+                                mayPerformReboot(failedPackage), failedPackage));
+                    } else {
+                        impact =  mapRescueLevelToUserImpact(getRescueLevel(mitigationCount));
+                    }
+                } else {
+                    impact =  mapRescueLevelToUserImpact(getRescueLevel(mitigationCount,
+                            mayPerformReboot(failedPackage)));
+                }
+            }
+
+            Slog.i(TAG, "Checking available remediations for health check failure."
+                    + " failedPackage: "
+                    + (failedPackage == null ? null : failedPackage.getPackageName())
+                    + " failureReason: " + failureReason
+                    + " available impact: " + impact);
+            return impact;
+        }
+
+        @Override
+        public boolean execute(@Nullable VersionedPackage failedPackage,
+                @FailureReasons int failureReason, int mitigationCount) {
+            if (isDisabled()) {
+                return false;
+            }
+            Slog.i(TAG, "Executing remediation."
+                    + " failedPackage: "
+                    + (failedPackage == null ? null : failedPackage.getPackageName())
+                    + " failureReason: " + failureReason
+                    + " mitigationCount: " + mitigationCount);
+            if (failureReason == PackageWatchdog.FAILURE_REASON_APP_CRASH
+                    || failureReason == PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING) {
+                final int level;
+                if (Flags.recoverabilityDetection()) {
+                    if (!Flags.deprecateFlagsAndSettingsResets()) {
+                        level = getRescueLevel(mitigationCount, mayPerformReboot(failedPackage),
+                                failedPackage);
+                    } else {
+                        level = getRescueLevel(mitigationCount);
+                    }
+                } else {
+                    level = getRescueLevel(mitigationCount, mayPerformReboot(failedPackage));
+                }
+                executeRescueLevel(mContext,
+                        failedPackage == null ? null : failedPackage.getPackageName(), level);
+                return true;
+            } else {
+                return false;
+            }
+        }
+
+        @Override
+        public boolean isPersistent() {
+            return true;
+        }
+
+        @Override
+        public boolean mayObservePackage(String packageName) {
+            PackageManager pm = mContext.getPackageManager();
+            try {
+                // A package is a module if this is non-null
+                if (pm.getModuleInfo(packageName, 0) != null) {
+                    return true;
+                }
+            } catch (PackageManager.NameNotFoundException | IllegalStateException ignore) {
+            }
+
+            return isPersistentSystemApp(packageName);
+        }
+
+        @Override
+        public int onBootLoop(int mitigationCount) {
+            if (isDisabled()) {
+                return PackageHealthObserverImpact.USER_IMPACT_LEVEL_0;
+            }
+            if (Flags.recoverabilityDetection()) {
+                if (!Flags.deprecateFlagsAndSettingsResets()) {
+                    return mapRescueLevelToUserImpact(getRescueLevel(mitigationCount,
+                            true, /*failedPackage=*/ null));
+                } else {
+                    return mapRescueLevelToUserImpact(getRescueLevel(mitigationCount));
+                }
+            } else {
+                return mapRescueLevelToUserImpact(getRescueLevel(mitigationCount, true));
+            }
+        }
+
+        @Override
+        public boolean executeBootLoopMitigation(int mitigationCount) {
+            if (isDisabled()) {
+                return false;
+            }
+            boolean mayPerformReboot = !shouldThrottleReboot();
+            final int level;
+            if (Flags.recoverabilityDetection()) {
+                if (!Flags.deprecateFlagsAndSettingsResets()) {
+                    level = getRescueLevel(mitigationCount, mayPerformReboot,
+                            /*failedPackage=*/ null);
+                } else {
+                    level = getRescueLevel(mitigationCount);
+                }
+            } else {
+                level = getRescueLevel(mitigationCount, mayPerformReboot);
+            }
+            executeRescueLevel(mContext, /*failedPackage=*/ null, level);
+            return true;
+        }
+
+        @Override
+        public String getUniqueIdentifier() {
+            return NAME;
+        }
+
+        /**
+         * Returns {@code true} if the failing package is non-null and performing a reboot or
+         * prompting a factory reset is an acceptable mitigation strategy for the package's
+         * failure, {@code false} otherwise.
+         */
+        private boolean mayPerformReboot(@Nullable VersionedPackage failingPackage) {
+            if (failingPackage == null) {
+                return false;
+            }
+            if (shouldThrottleReboot())  {
+                return false;
+            }
+
+            return isPersistentSystemApp(failingPackage.getPackageName());
+        }
+
+        private boolean isPersistentSystemApp(@NonNull String packageName) {
+            PackageManager pm = mContext.getPackageManager();
+            try {
+                ApplicationInfo info = pm.getApplicationInfo(packageName, 0);
+                return (info.flags & PERSISTENT_MASK) == PERSISTENT_MASK;
+            } catch (PackageManager.NameNotFoundException e) {
+                return false;
+            }
+        }
+
+        private synchronized void recordDeviceConfigAccess(@NonNull String callingPackage,
+                @NonNull String namespace) {
+            if (!Flags.deprecateFlagsAndSettingsResets()) {
+                // Record it in calling packages to namespace map
+                Set<String> namespaceSet = mCallingPackageNamespaceSetMap.get(callingPackage);
+                if (namespaceSet == null) {
+                    namespaceSet = new ArraySet<>();
+                    mCallingPackageNamespaceSetMap.put(callingPackage, namespaceSet);
+                }
+                namespaceSet.add(namespace);
+                // Record it in namespace to calling packages map
+                Set<String> callingPackageSet = mNamespaceCallingPackageSetMap.get(namespace);
+                if (callingPackageSet == null) {
+                    callingPackageSet = new ArraySet<>();
+                }
+                callingPackageSet.add(callingPackage);
+                mNamespaceCallingPackageSetMap.put(namespace, callingPackageSet);
+            }
+        }
+
+        private synchronized Set<String> getAffectedNamespaceSet(String failedPackage) {
+            return mCallingPackageNamespaceSetMap.get(failedPackage);
+        }
+
+        private synchronized Set<String> getAllAffectedNamespaceSet() {
+            return new HashSet<String>(mNamespaceCallingPackageSetMap.keySet());
+        }
+
+        private synchronized Set<String> getCallingPackagesSet(String namespace) {
+            return mNamespaceCallingPackageSetMap.get(namespace);
+        }
+    }
+
+    /**
+     * Returns {@code true} if Rescue Party is allowed to attempt a reboot or factory reset.
+     * Will return {@code false} if a factory reset was already offered recently.
+     */
+    private static boolean shouldThrottleReboot() {
+        Long lastResetTime = getLastFactoryResetTimeMs();
+        long now = System.currentTimeMillis();
+        long throttleDurationMin = SystemProperties.getLong(PROP_THROTTLE_DURATION_MIN_FLAG,
+                DEFAULT_FACTORY_RESET_THROTTLE_DURATION_MIN);
+        return now < lastResetTime + TimeUnit.MINUTES.toMillis(throttleDurationMin);
+    }
+
+    private static int[] getAllUserIds() {
+        int systemUserId = UserHandle.SYSTEM.getIdentifier();
+        int[] userIds = { systemUserId };
+        try {
+            for (File file : FileUtils.listFilesOrEmpty(Environment.getDataSystemDeDirectory())) {
+                try {
+                    final int userId = Integer.parseInt(file.getName());
+                    if (userId != systemUserId) {
+                        userIds = ArrayUtils.appendInt(userIds, userId);
+                    }
+                } catch (NumberFormatException ignored) {
+                }
+            }
+        } catch (Throwable t) {
+            Slog.w(TAG, "Trouble discovering users", t);
+        }
+        return userIds;
+    }
+
+    /**
+     * Hacky test to check if the device has an active USB connection, which is
+     * a good proxy for someone doing local development work.
+     */
+    private static boolean isUsbActive() {
+        if (SystemProperties.getBoolean(PROP_VIRTUAL_DEVICE, false)) {
+            Slog.v(TAG, "Assuming virtual device is connected over USB");
+            return true;
+        }
+        try {
+            final String state = FileUtils
+                    .readTextFile(new File("/sys/class/android_usb/android0/state"), 128, "");
+            return "CONFIGURED".equals(state.trim());
+        } catch (Throwable t) {
+            Slog.w(TAG, "Failed to determine if device was on USB", t);
+            return false;
+        }
+    }
+
+    private static class Level {
+        static int none() {
+            return Flags.recoverabilityDetection() ? RESCUE_LEVEL_NONE : LEVEL_NONE;
+        }
+
+        static int reboot() {
+            return Flags.recoverabilityDetection() ? RESCUE_LEVEL_WARM_REBOOT : LEVEL_WARM_REBOOT;
+        }
+
+        static int factoryReset() {
+            return Flags.recoverabilityDetection()
+                    ? RESCUE_LEVEL_FACTORY_RESET
+                    : LEVEL_FACTORY_RESET;
+        }
+    }
+
+    private static String levelToString(int level) {
+        if (Flags.recoverabilityDetection()) {
+            switch (level) {
+                case RESCUE_LEVEL_NONE:
+                    return "NONE";
+                case RESCUE_LEVEL_SCOPED_DEVICE_CONFIG_RESET:
+                    return "SCOPED_DEVICE_CONFIG_RESET";
+                case RESCUE_LEVEL_ALL_DEVICE_CONFIG_RESET:
+                    return "ALL_DEVICE_CONFIG_RESET";
+                case RESCUE_LEVEL_WARM_REBOOT:
+                    return "WARM_REBOOT";
+                case RESCUE_LEVEL_RESET_SETTINGS_UNTRUSTED_DEFAULTS:
+                    return "RESET_SETTINGS_UNTRUSTED_DEFAULTS";
+                case RESCUE_LEVEL_RESET_SETTINGS_UNTRUSTED_CHANGES:
+                    return "RESET_SETTINGS_UNTRUSTED_CHANGES";
+                case RESCUE_LEVEL_RESET_SETTINGS_TRUSTED_DEFAULTS:
+                    return "RESET_SETTINGS_TRUSTED_DEFAULTS";
+                case RESCUE_LEVEL_FACTORY_RESET:
+                    return "FACTORY_RESET";
+                default:
+                    return Integer.toString(level);
+            }
+        } else {
+            switch (level) {
+                case LEVEL_NONE:
+                    return "NONE";
+                case LEVEL_RESET_SETTINGS_UNTRUSTED_DEFAULTS:
+                    return "RESET_SETTINGS_UNTRUSTED_DEFAULTS";
+                case LEVEL_RESET_SETTINGS_UNTRUSTED_CHANGES:
+                    return "RESET_SETTINGS_UNTRUSTED_CHANGES";
+                case LEVEL_RESET_SETTINGS_TRUSTED_DEFAULTS:
+                    return "RESET_SETTINGS_TRUSTED_DEFAULTS";
+                case LEVEL_WARM_REBOOT:
+                    return "WARM_REBOOT";
+                case LEVEL_FACTORY_RESET:
+                    return "FACTORY_RESET";
+                default:
+                    return Integer.toString(level);
+            }
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/crashrecovery/CrashRecoveryModule.java b/packages/CrashRecovery/services/module/java/com/android/server/crashrecovery/CrashRecoveryModule.java
similarity index 100%
rename from services/core/java/com/android/server/crashrecovery/CrashRecoveryModule.java
rename to packages/CrashRecovery/services/module/java/com/android/server/crashrecovery/CrashRecoveryModule.java
diff --git a/services/core/java/com/android/server/crashrecovery/CrashRecoveryUtils.java b/packages/CrashRecovery/services/module/java/com/android/server/crashrecovery/CrashRecoveryUtils.java
similarity index 92%
rename from services/core/java/com/android/server/crashrecovery/CrashRecoveryUtils.java
rename to packages/CrashRecovery/services/module/java/com/android/server/crashrecovery/CrashRecoveryUtils.java
index 3eb3380..2e2a937 100644
--- a/services/core/java/com/android/server/crashrecovery/CrashRecoveryUtils.java
+++ b/packages/CrashRecovery/services/module/java/com/android/server/crashrecovery/CrashRecoveryUtils.java
@@ -18,7 +18,7 @@
 
 import android.os.Environment;
 import android.util.IndentingPrintWriter;
-import android.util.Slog;
+import android.util.Log;
 
 import java.io.BufferedReader;
 import java.io.File;
@@ -41,7 +41,7 @@
 
     /** Persist recovery related events in crashrecovery events file.**/
     public static void logCrashRecoveryEvent(int priority, String msg) {
-        Slog.println(priority, TAG, msg);
+        Log.println(priority, TAG, msg);
         try {
             File fname = getCrashRecoveryEventsFile();
             synchronized (sFileLock) {
@@ -52,7 +52,7 @@
                 pw.close();
             }
         } catch (IOException e) {
-            Slog.e(TAG, "Unable to log CrashRecoveryEvents " + e.getMessage());
+            Log.e(TAG, "Unable to log CrashRecoveryEvents " + e.getMessage());
         }
     }
 
@@ -72,7 +72,7 @@
                     pw.println(line);
                 }
             } catch (IOException e) {
-                Slog.e(TAG, "Unable to dump CrashRecoveryEvents " + e.getMessage());
+                Log.e(TAG, "Unable to dump CrashRecoveryEvents " + e.getMessage());
             }
         }
         pw.decreaseIndent();
diff --git a/packages/CrashRecovery/services/module/java/com/android/server/rollback/RollbackPackageHealthObserver.java b/packages/CrashRecovery/services/module/java/com/android/server/rollback/RollbackPackageHealthObserver.java
new file mode 100644
index 0000000..2931652
--- /dev/null
+++ b/packages/CrashRecovery/services/module/java/com/android/server/rollback/RollbackPackageHealthObserver.java
@@ -0,0 +1,786 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.rollback;
+
+import static com.android.server.crashrecovery.CrashRecoveryUtils.logCrashRecoveryEvent;
+
+import android.annotation.AnyThread;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.WorkerThread;
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.VersionedPackage;
+import android.content.rollback.PackageRollbackInfo;
+import android.content.rollback.RollbackInfo;
+import android.content.rollback.RollbackManager;
+import android.crashrecovery.flags.Flags;
+import android.os.Environment;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.PowerManager;
+import android.os.SystemProperties;
+import android.sysprop.CrashRecoveryProperties;
+import android.util.ArraySet;
+import android.util.FileUtils;
+import android.util.Log;
+import android.util.Slog;
+import android.util.SparseArray;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.Preconditions;
+import com.android.server.PackageWatchdog;
+import com.android.server.PackageWatchdog.FailureReasons;
+import com.android.server.PackageWatchdog.PackageHealthObserver;
+import com.android.server.PackageWatchdog.PackageHealthObserverImpact;
+import com.android.server.crashrecovery.proto.CrashRecoveryStatsLog;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Set;
+import java.util.function.Consumer;
+
+/**
+ * {@link PackageHealthObserver} for {@link RollbackManagerService}.
+ * This class monitors crashes and triggers RollbackManager rollback accordingly.
+ * It also monitors native crashes for some short while after boot.
+ *
+ * @hide
+ */
+public final class RollbackPackageHealthObserver implements PackageHealthObserver {
+    private static final String TAG = "RollbackPackageHealthObserver";
+    private static final String NAME = "rollback-observer";
+    private static final String CLASS_NAME = RollbackPackageHealthObserver.class.getName();
+
+    private static final int PERSISTENT_MASK = ApplicationInfo.FLAG_PERSISTENT
+            | ApplicationInfo.FLAG_SYSTEM;
+
+    private static final String PROP_DISABLE_HIGH_IMPACT_ROLLBACK_FLAG =
+            "persist.device_config.configuration.disable_high_impact_rollback";
+
+    private final Context mContext;
+    private final Handler mHandler;
+    private final File mLastStagedRollbackIdsFile;
+    private final File mTwoPhaseRollbackEnabledFile;
+    // Staged rollback ids that have been committed but their session is not yet ready
+    private final Set<Integer> mPendingStagedRollbackIds = new ArraySet<>();
+    // True if needing to roll back only rebootless apexes when native crash happens
+    private boolean mTwoPhaseRollbackEnabled;
+
+    @VisibleForTesting
+    public RollbackPackageHealthObserver(@NonNull Context context) {
+        mContext = context;
+        HandlerThread handlerThread = new HandlerThread("RollbackPackageHealthObserver");
+        handlerThread.start();
+        mHandler = new Handler(handlerThread.getLooper());
+        File dataDir = new File(Environment.getDataDirectory(), "rollback-observer");
+        dataDir.mkdirs();
+        mLastStagedRollbackIdsFile = new File(dataDir, "last-staged-rollback-ids");
+        mTwoPhaseRollbackEnabledFile = new File(dataDir, "two-phase-rollback-enabled");
+        PackageWatchdog.getInstance(mContext).registerHealthObserver(this);
+
+        if (SystemProperties.getBoolean("sys.boot_completed", false)) {
+            // Load the value from the file if system server has crashed and restarted
+            mTwoPhaseRollbackEnabled = readBoolean(mTwoPhaseRollbackEnabledFile);
+        } else {
+            // Disable two-phase rollback for a normal reboot. We assume the rebootless apex
+            // installed before reboot is stable if native crash didn't happen.
+            mTwoPhaseRollbackEnabled = false;
+            writeBoolean(mTwoPhaseRollbackEnabledFile, false);
+        }
+    }
+
+    @Override
+    public int onHealthCheckFailed(@Nullable VersionedPackage failedPackage,
+            @FailureReasons int failureReason, int mitigationCount) {
+        int impact = PackageHealthObserverImpact.USER_IMPACT_LEVEL_0;
+        if (Flags.recoverabilityDetection()) {
+            List<RollbackInfo> availableRollbacks = getAvailableRollbacks();
+            List<RollbackInfo> lowImpactRollbacks = getRollbacksAvailableForImpactLevel(
+                    availableRollbacks, PackageManager.ROLLBACK_USER_IMPACT_LOW);
+            if (!lowImpactRollbacks.isEmpty()) {
+                if (failureReason == PackageWatchdog.FAILURE_REASON_NATIVE_CRASH) {
+                    // For native crashes, we will directly roll back any available rollbacks at low
+                    // impact level
+                    impact = PackageHealthObserverImpact.USER_IMPACT_LEVEL_30;
+                } else if (getRollbackForPackage(failedPackage, lowImpactRollbacks) != null) {
+                    // Rollback is available for crashing low impact package
+                    impact = PackageHealthObserverImpact.USER_IMPACT_LEVEL_30;
+                } else {
+                    impact = PackageHealthObserverImpact.USER_IMPACT_LEVEL_70;
+                }
+            }
+        } else {
+            boolean anyRollbackAvailable = !mContext.getSystemService(RollbackManager.class)
+                    .getAvailableRollbacks().isEmpty();
+
+            if (failureReason == PackageWatchdog.FAILURE_REASON_NATIVE_CRASH
+                    && anyRollbackAvailable) {
+                // For native crashes, we will directly roll back any available rollbacks
+                // Note: For non-native crashes the rollback-all step has higher impact
+                impact = PackageHealthObserverImpact.USER_IMPACT_LEVEL_30;
+            } else if (getAvailableRollback(failedPackage) != null) {
+                // Rollback is available, we may get a callback into #execute
+                impact = PackageHealthObserverImpact.USER_IMPACT_LEVEL_30;
+            } else if (anyRollbackAvailable) {
+                // If any rollbacks are available, we will commit them
+                impact = PackageHealthObserverImpact.USER_IMPACT_LEVEL_70;
+            }
+        }
+
+        Slog.i(TAG, "Checking available remediations for health check failure."
+                + " failedPackage: "
+                + (failedPackage == null ? null : failedPackage.getPackageName())
+                + " failureReason: " + failureReason
+                + " available impact: " + impact);
+        return impact;
+    }
+
+    @Override
+    public boolean execute(@Nullable VersionedPackage failedPackage,
+            @FailureReasons int rollbackReason, int mitigationCount) {
+        Slog.i(TAG, "Executing remediation."
+                + " failedPackage: "
+                + (failedPackage == null ? null : failedPackage.getPackageName())
+                + " rollbackReason: " + rollbackReason
+                + " mitigationCount: " + mitigationCount);
+        if (Flags.recoverabilityDetection()) {
+            List<RollbackInfo> availableRollbacks = getAvailableRollbacks();
+            if (rollbackReason == PackageWatchdog.FAILURE_REASON_NATIVE_CRASH) {
+                mHandler.post(() -> rollbackAllLowImpact(availableRollbacks, rollbackReason));
+                return true;
+            }
+
+            List<RollbackInfo> lowImpactRollbacks = getRollbacksAvailableForImpactLevel(
+                    availableRollbacks, PackageManager.ROLLBACK_USER_IMPACT_LOW);
+            RollbackInfo rollback = getRollbackForPackage(failedPackage, lowImpactRollbacks);
+            if (rollback != null) {
+                mHandler.post(() -> rollbackPackage(rollback, failedPackage, rollbackReason));
+            } else if (!lowImpactRollbacks.isEmpty()) {
+                // Apply all available low impact rollbacks.
+                mHandler.post(() -> rollbackAllLowImpact(availableRollbacks, rollbackReason));
+            }
+        } else {
+            if (rollbackReason == PackageWatchdog.FAILURE_REASON_NATIVE_CRASH) {
+                mHandler.post(() -> rollbackAll(rollbackReason));
+                return true;
+            }
+
+            RollbackInfo rollback = getAvailableRollback(failedPackage);
+            if (rollback != null) {
+                mHandler.post(() -> rollbackPackage(rollback, failedPackage, rollbackReason));
+            } else {
+                mHandler.post(() -> rollbackAll(rollbackReason));
+            }
+        }
+
+        // Assume rollbacks executed successfully
+        return true;
+    }
+
+    @Override
+    public int onBootLoop(int mitigationCount) {
+        int impact = PackageHealthObserverImpact.USER_IMPACT_LEVEL_0;
+        if (Flags.recoverabilityDetection()) {
+            List<RollbackInfo> availableRollbacks = getAvailableRollbacks();
+            if (!availableRollbacks.isEmpty()) {
+                impact = getUserImpactBasedOnRollbackImpactLevel(availableRollbacks);
+            }
+        }
+        return impact;
+    }
+
+    @Override
+    public boolean executeBootLoopMitigation(int mitigationCount) {
+        if (Flags.recoverabilityDetection()) {
+            List<RollbackInfo> availableRollbacks = getAvailableRollbacks();
+
+            triggerLeastImpactLevelRollback(availableRollbacks,
+                    PackageWatchdog.FAILURE_REASON_BOOT_LOOP);
+            return true;
+        }
+        return false;
+    }
+
+    @Override
+    @NonNull
+    public String getUniqueIdentifier() {
+        return NAME;
+    }
+
+    @Override
+    public boolean isPersistent() {
+        return true;
+    }
+
+    @Override
+    public boolean mayObservePackage(@NonNull String packageName) {
+        if (getAvailableRollbacks().isEmpty()) {
+            return false;
+        }
+        return isPersistentSystemApp(packageName);
+    }
+
+    private List<RollbackInfo> getAvailableRollbacks() {
+        return mContext.getSystemService(RollbackManager.class).getAvailableRollbacks();
+    }
+
+    private boolean isPersistentSystemApp(@NonNull String packageName) {
+        PackageManager pm = mContext.getPackageManager();
+        try {
+            ApplicationInfo info = pm.getApplicationInfo(packageName, 0);
+            return (info.flags & PERSISTENT_MASK) == PERSISTENT_MASK;
+        } catch (PackageManager.NameNotFoundException e) {
+            return false;
+        }
+    }
+
+    private void assertInWorkerThread() {
+        Preconditions.checkState(mHandler.getLooper().isCurrentThread());
+    }
+
+    /**
+     * Start observing health of {@code packages} for {@code durationMs}.
+     * This may cause {@code packages} to be rolled back if they crash too freqeuntly.
+     */
+    @AnyThread
+    @NonNull
+    public void startObservingHealth(@NonNull List<String> packages, @NonNull long durationMs) {
+        PackageWatchdog.getInstance(mContext).startObservingHealth(this, packages, durationMs);
+    }
+
+    @AnyThread
+    @NonNull
+    public void notifyRollbackAvailable(@NonNull RollbackInfo rollback) {
+        mHandler.post(() -> {
+            // Enable two-phase rollback when a rebootless apex rollback is made available.
+            // We assume the rebootless apex is stable and is less likely to be the cause
+            // if native crash doesn't happen before reboot. So we will clear the flag and disable
+            // two-phase rollback after reboot.
+            if (isRebootlessApex(rollback)) {
+                mTwoPhaseRollbackEnabled = true;
+                writeBoolean(mTwoPhaseRollbackEnabledFile, true);
+            }
+        });
+    }
+
+    private static boolean isRebootlessApex(RollbackInfo rollback) {
+        if (!rollback.isStaged()) {
+            for (PackageRollbackInfo info : rollback.getPackages()) {
+                if (info.isApex()) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    /** Verifies the rollback state after a reboot and schedules polling for sometime after reboot
+     * to check for native crashes and mitigate them if needed.
+     */
+    @AnyThread
+    public void onBootCompletedAsync() {
+        mHandler.post(()->onBootCompleted());
+    }
+
+    @WorkerThread
+    private void onBootCompleted() {
+        assertInWorkerThread();
+
+        RollbackManager rollbackManager = mContext.getSystemService(RollbackManager.class);
+        if (!rollbackManager.getAvailableRollbacks().isEmpty()) {
+            // TODO(gavincorkery): Call into Package Watchdog from outside the observer
+            PackageWatchdog.getInstance(mContext).scheduleCheckAndMitigateNativeCrashes();
+        }
+
+        SparseArray<String> rollbackIds = popLastStagedRollbackIds();
+        for (int i = 0; i < rollbackIds.size(); i++) {
+            WatchdogRollbackLogger.logRollbackStatusOnBoot(mContext,
+                    rollbackIds.keyAt(i), rollbackIds.valueAt(i),
+                    rollbackManager.getRecentlyCommittedRollbacks());
+        }
+    }
+
+    @AnyThread
+    private RollbackInfo getAvailableRollback(VersionedPackage failedPackage) {
+        RollbackManager rollbackManager = mContext.getSystemService(RollbackManager.class);
+        for (RollbackInfo rollback : rollbackManager.getAvailableRollbacks()) {
+            for (PackageRollbackInfo packageRollback : rollback.getPackages()) {
+                if (packageRollback.getVersionRolledBackFrom().equals(failedPackage)) {
+                    return rollback;
+                }
+                // TODO(b/147666157): Extract version number of apk-in-apex so that we don't have
+                //  to rely on complicated reasoning as below
+
+                // Due to b/147666157, for apk in apex, we do not know the version we are rolling
+                // back from. But if a package X is embedded in apex A exclusively (not embedded in
+                // any other apex), which is not guaranteed, then it is sufficient to check only
+                // package names here, as the version of failedPackage and the PackageRollbackInfo
+                // can't be different. If failedPackage has a higher version, then it must have
+                // been updated somehow. There are two ways: it was updated by an update of apex A
+                // or updated directly as apk. In both cases, this rollback would have gotten
+                // expired when onPackageReplaced() was called. Since the rollback exists, it has
+                // same version as failedPackage.
+                if (packageRollback.isApkInApex()
+                        && packageRollback.getVersionRolledBackFrom().getPackageName()
+                        .equals(failedPackage.getPackageName())) {
+                    return rollback;
+                }
+            }
+        }
+        return null;
+    }
+
+    @AnyThread
+    private RollbackInfo getRollbackForPackage(@Nullable VersionedPackage failedPackage,
+            List<RollbackInfo> availableRollbacks) {
+        if (failedPackage == null) {
+            return null;
+        }
+
+        for (RollbackInfo rollback : availableRollbacks) {
+            for (PackageRollbackInfo packageRollback : rollback.getPackages()) {
+                if (packageRollback.getVersionRolledBackFrom().equals(failedPackage)) {
+                    return rollback;
+                }
+                // TODO(b/147666157): Extract version number of apk-in-apex so that we don't have
+                //  to rely on complicated reasoning as below
+
+                // Due to b/147666157, for apk in apex, we do not know the version we are rolling
+                // back from. But if a package X is embedded in apex A exclusively (not embedded in
+                // any other apex), which is not guaranteed, then it is sufficient to check only
+                // package names here, as the version of failedPackage and the PackageRollbackInfo
+                // can't be different. If failedPackage has a higher version, then it must have
+                // been updated somehow. There are two ways: it was updated by an update of apex A
+                // or updated directly as apk. In both cases, this rollback would have gotten
+                // expired when onPackageReplaced() was called. Since the rollback exists, it has
+                // same version as failedPackage.
+                if (packageRollback.isApkInApex()
+                        && packageRollback.getVersionRolledBackFrom().getPackageName()
+                        .equals(failedPackage.getPackageName())) {
+                    return rollback;
+                }
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Returns {@code true} if staged session associated with {@code rollbackId} was marked
+     * as handled, {@code false} if already handled.
+     */
+    @WorkerThread
+    private boolean markStagedSessionHandled(int rollbackId) {
+        assertInWorkerThread();
+        return mPendingStagedRollbackIds.remove(rollbackId);
+    }
+
+    /**
+     * Returns {@code true} if all pending staged rollback sessions were marked as handled,
+     * {@code false} if there is any left.
+     */
+    @WorkerThread
+    private boolean isPendingStagedSessionsEmpty() {
+        assertInWorkerThread();
+        return mPendingStagedRollbackIds.isEmpty();
+    }
+
+    private static boolean readBoolean(File file) {
+        try (FileInputStream fis = new FileInputStream(file)) {
+            return fis.read() == 1;
+        } catch (IOException ignore) {
+            return false;
+        }
+    }
+
+    private static void writeBoolean(File file, boolean value) {
+        try (FileOutputStream fos = new FileOutputStream(file)) {
+            fos.write(value ? 1 : 0);
+            fos.flush();
+            FileUtils.sync(fos);
+        } catch (IOException ignore) {
+        }
+    }
+
+    @WorkerThread
+    private void saveStagedRollbackId(int stagedRollbackId, @Nullable VersionedPackage logPackage) {
+        assertInWorkerThread();
+        writeStagedRollbackId(mLastStagedRollbackIdsFile, stagedRollbackId, logPackage);
+    }
+
+    static void writeStagedRollbackId(File file, int stagedRollbackId,
+            @Nullable VersionedPackage logPackage) {
+        try {
+            FileOutputStream fos = new FileOutputStream(file, true);
+            PrintWriter pw = new PrintWriter(fos);
+            String logPackageName = logPackage != null ? logPackage.getPackageName() : "";
+            pw.append(String.valueOf(stagedRollbackId)).append(",").append(logPackageName);
+            pw.println();
+            pw.flush();
+            FileUtils.sync(fos);
+            pw.close();
+        } catch (IOException e) {
+            Slog.e(TAG, "Failed to save last staged rollback id", e);
+            file.delete();
+        }
+    }
+
+    @WorkerThread
+    private SparseArray<String> popLastStagedRollbackIds() {
+        assertInWorkerThread();
+        try {
+            return readStagedRollbackIds(mLastStagedRollbackIdsFile);
+        } finally {
+            mLastStagedRollbackIdsFile.delete();
+        }
+    }
+
+    static SparseArray<String> readStagedRollbackIds(File file) {
+        SparseArray<String> result = new SparseArray<>();
+        try {
+            String line;
+            BufferedReader reader = new BufferedReader(new FileReader(file));
+            while ((line = reader.readLine()) != null) {
+                // Each line is of the format: "id,logging_package"
+                String[] values = line.trim().split(",");
+                String rollbackId = values[0];
+                String logPackageName = "";
+                if (values.length > 1) {
+                    logPackageName = values[1];
+                }
+                result.put(Integer.parseInt(rollbackId), logPackageName);
+            }
+        } catch (Exception ignore) {
+            return new SparseArray<>();
+        }
+        return result;
+    }
+
+
+    /**
+     * Returns true if the package name is the name of a module.
+     */
+    @AnyThread
+    private boolean isModule(String packageName) {
+        // Check if the package is listed among the system modules or is an
+        // APK inside an updatable APEX.
+        try {
+            final PackageInfo pkg = mContext.getPackageManager()
+                    .getPackageInfo(packageName, 0 /* flags */);
+            String apexPackageName = pkg.getApexPackageName();
+            if (apexPackageName != null) {
+                packageName = apexPackageName;
+            }
+
+            return pm.getModuleInfo(packageName, 0 /* flags */) != null;
+        } catch (PackageManager.NameNotFoundException e) {
+            return false;
+        }
+    }
+
+    /**
+     * Rolls back the session that owns {@code failedPackage}
+     *
+     * @param rollback {@code rollbackInfo} of the {@code failedPackage}
+     * @param failedPackage the package that needs to be rolled back
+     */
+    @WorkerThread
+    private void rollbackPackage(RollbackInfo rollback, VersionedPackage failedPackage,
+            @FailureReasons int rollbackReason) {
+        assertInWorkerThread();
+        String failedPackageName = (failedPackage == null ? null : failedPackage.getPackageName());
+
+        Slog.i(TAG, "Rolling back package. RollbackId: " + rollback.getRollbackId()
+                + " failedPackage: " + failedPackageName
+                + " rollbackReason: " + rollbackReason);
+        logCrashRecoveryEvent(Log.DEBUG, String.format("Rolling back %s. Reason: %s",
+                failedPackageName, rollbackReason));
+        final RollbackManager rollbackManager = mContext.getSystemService(RollbackManager.class);
+        int reasonToLog = WatchdogRollbackLogger.mapFailureReasonToMetric(rollbackReason);
+        final String failedPackageToLog;
+        if (rollbackReason == PackageWatchdog.FAILURE_REASON_NATIVE_CRASH) {
+            failedPackageToLog = SystemProperties.get(
+                    "sys.init.updatable_crashing_process_name", "");
+        } else {
+            failedPackageToLog = failedPackage.getPackageName();
+        }
+        VersionedPackage logPackageTemp = null;
+        if (isModule(failedPackage.getPackageName())) {
+            logPackageTemp = WatchdogRollbackLogger.getLogPackage(mContext, failedPackage);
+        }
+
+        final VersionedPackage logPackage = logPackageTemp;
+        WatchdogRollbackLogger.logEvent(logPackage,
+                CrashRecoveryStatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_INITIATE,
+                reasonToLog, failedPackageToLog);
+
+        Consumer<Intent> onResult = result -> {
+            assertInWorkerThread();
+            int status = result.getIntExtra(RollbackManager.EXTRA_STATUS,
+                    RollbackManager.STATUS_FAILURE);
+            if (status == RollbackManager.STATUS_SUCCESS) {
+                if (rollback.isStaged()) {
+                    int rollbackId = rollback.getRollbackId();
+                    saveStagedRollbackId(rollbackId, logPackage);
+                    WatchdogRollbackLogger.logEvent(logPackage,
+                            CrashRecoveryStatsLog
+                            .WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_BOOT_TRIGGERED,
+                            reasonToLog, failedPackageToLog);
+
+                } else {
+                    WatchdogRollbackLogger.logEvent(logPackage,
+                            CrashRecoveryStatsLog
+                                    .WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_SUCCESS,
+                            reasonToLog, failedPackageToLog);
+                }
+            } else {
+                WatchdogRollbackLogger.logEvent(logPackage,
+                        CrashRecoveryStatsLog
+                                .WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_FAILURE,
+                        reasonToLog, failedPackageToLog);
+            }
+            if (rollback.isStaged()) {
+                markStagedSessionHandled(rollback.getRollbackId());
+                // Wait for all pending staged sessions to get handled before rebooting.
+                if (isPendingStagedSessionsEmpty()) {
+                    CrashRecoveryProperties.attemptingReboot(true);
+                    mContext.getSystemService(PowerManager.class).reboot("Rollback staged install");
+                }
+            }
+        };
+
+        // Define a BroadcastReceiver to handle the result
+        BroadcastReceiver rollbackReceiver = new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent result) {
+                mHandler.post(() -> onResult.accept(result));
+            }
+        };
+
+        String intentActionName = CLASS_NAME + rollback.getRollbackId();
+        // Register the BroadcastReceiver
+        mContext.registerReceiver(rollbackReceiver,
+                new IntentFilter(intentActionName),
+                Context.RECEIVER_NOT_EXPORTED);
+
+        Intent intentReceiver = new Intent(intentActionName);
+        intentReceiver.putExtra("rollbackId", rollback.getRollbackId());
+        intentReceiver.setPackage(mContext.getPackageName());
+        intentReceiver.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+
+        PendingIntent rollbackPendingIntent = PendingIntent.getBroadcast(mContext,
+                rollback.getRollbackId(),
+                intentReceiver,
+                PendingIntent.FLAG_MUTABLE);
+
+        rollbackManager.commitRollback(rollback.getRollbackId(),
+                Collections.singletonList(failedPackage),
+                rollbackPendingIntent.getIntentSender());
+    }
+
+    /**
+     * Two-phase rollback:
+     * 1. roll back rebootless apexes first
+     * 2. roll back all remaining rollbacks if native crash doesn't stop after (1) is done
+     *
+     * This approach gives us a better chance to correctly attribute native crash to rebootless
+     * apex update without rolling back Mainline updates which might contains critical security
+     * fixes.
+     */
+    @WorkerThread
+    private boolean useTwoPhaseRollback(List<RollbackInfo> rollbacks) {
+        assertInWorkerThread();
+        if (!mTwoPhaseRollbackEnabled) {
+            return false;
+        }
+
+        Slog.i(TAG, "Rolling back all rebootless APEX rollbacks");
+        boolean found = false;
+        for (RollbackInfo rollback : rollbacks) {
+            if (isRebootlessApex(rollback)) {
+                VersionedPackage firstRollback =
+                        rollback.getPackages().get(0).getVersionRolledBackFrom();
+                rollbackPackage(rollback, firstRollback,
+                        PackageWatchdog.FAILURE_REASON_NATIVE_CRASH);
+                found = true;
+            }
+        }
+        return found;
+    }
+
+    /**
+     * Rollback the package that has minimum rollback impact level.
+     * @param availableRollbacks all available rollbacks
+     * @param rollbackReason reason to rollback
+     */
+    private void triggerLeastImpactLevelRollback(List<RollbackInfo> availableRollbacks,
+            @FailureReasons int rollbackReason) {
+        int minRollbackImpactLevel = getMinRollbackImpactLevel(availableRollbacks);
+
+        if (minRollbackImpactLevel == PackageManager.ROLLBACK_USER_IMPACT_LOW) {
+            // Apply all available low impact rollbacks.
+            mHandler.post(() -> rollbackAllLowImpact(availableRollbacks, rollbackReason));
+        } else if (minRollbackImpactLevel == PackageManager.ROLLBACK_USER_IMPACT_HIGH) {
+            // Check disable_high_impact_rollback device config before performing rollback
+            if (SystemProperties.getBoolean(PROP_DISABLE_HIGH_IMPACT_ROLLBACK_FLAG, false)) {
+                return;
+            }
+            // Rollback one package at a time. If that doesn't resolve the issue, rollback
+            // next with same impact level.
+            mHandler.post(() -> rollbackHighImpact(availableRollbacks, rollbackReason));
+        }
+    }
+
+    /**
+     * sort the available high impact rollbacks by first package name to have a deterministic order.
+     * Apply the first available rollback.
+     * @param availableRollbacks all available rollbacks
+     * @param rollbackReason reason to rollback
+     */
+    @WorkerThread
+    private void rollbackHighImpact(List<RollbackInfo> availableRollbacks,
+            @FailureReasons int rollbackReason) {
+        assertInWorkerThread();
+        List<RollbackInfo> highImpactRollbacks =
+                getRollbacksAvailableForImpactLevel(
+                        availableRollbacks, PackageManager.ROLLBACK_USER_IMPACT_HIGH);
+
+        // sort rollbacks based on package name of the first package. This is to have a
+        // deterministic order of rollbacks.
+        List<RollbackInfo> sortedHighImpactRollbacks = highImpactRollbacks.stream().sorted(
+                Comparator.comparing(a -> a.getPackages().get(0).getPackageName())).toList();
+        VersionedPackage firstRollback =
+                sortedHighImpactRollbacks
+                        .get(0)
+                        .getPackages()
+                        .get(0)
+                        .getVersionRolledBackFrom();
+        Slog.i(TAG, "Rolling back high impact rollback for package: "
+                + firstRollback.getPackageName());
+        rollbackPackage(sortedHighImpactRollbacks.get(0), firstRollback, rollbackReason);
+    }
+
+    @WorkerThread
+    private void rollbackAll(@FailureReasons int rollbackReason) {
+        assertInWorkerThread();
+        RollbackManager rollbackManager = mContext.getSystemService(RollbackManager.class);
+        List<RollbackInfo> rollbacks = rollbackManager.getAvailableRollbacks();
+        if (useTwoPhaseRollback(rollbacks)) {
+            return;
+        }
+
+        Slog.i(TAG, "Rolling back all available rollbacks");
+        // Add all rollback ids to mPendingStagedRollbackIds, so that we do not reboot before all
+        // pending staged rollbacks are handled.
+        for (RollbackInfo rollback : rollbacks) {
+            if (rollback.isStaged()) {
+                mPendingStagedRollbackIds.add(rollback.getRollbackId());
+            }
+        }
+
+        for (RollbackInfo rollback : rollbacks) {
+            VersionedPackage firstRollback =
+                    rollback.getPackages().get(0).getVersionRolledBackFrom();
+            rollbackPackage(rollback, firstRollback, rollbackReason);
+        }
+    }
+
+    /**
+     * Rollback all available low impact rollbacks
+     * @param availableRollbacks all available rollbacks
+     * @param rollbackReason reason to rollbacks
+     */
+    @WorkerThread
+    private void rollbackAllLowImpact(
+            List<RollbackInfo> availableRollbacks, @FailureReasons int rollbackReason) {
+        assertInWorkerThread();
+
+        List<RollbackInfo> lowImpactRollbacks = getRollbacksAvailableForImpactLevel(
+                availableRollbacks,
+                PackageManager.ROLLBACK_USER_IMPACT_LOW);
+        if (useTwoPhaseRollback(lowImpactRollbacks)) {
+            return;
+        }
+
+        Slog.i(TAG, "Rolling back all available low impact rollbacks");
+        logCrashRecoveryEvent(Log.DEBUG, "Rolling back all available. Reason: " + rollbackReason);
+        // Add all rollback ids to mPendingStagedRollbackIds, so that we do not reboot before all
+        // pending staged rollbacks are handled.
+        for (RollbackInfo rollback : lowImpactRollbacks) {
+            if (rollback.isStaged()) {
+                mPendingStagedRollbackIds.add(rollback.getRollbackId());
+            }
+        }
+
+        for (RollbackInfo rollback : lowImpactRollbacks) {
+            VersionedPackage firstRollback =
+                    rollback.getPackages().get(0).getVersionRolledBackFrom();
+            rollbackPackage(rollback, firstRollback, rollbackReason);
+        }
+    }
+
+    private List<RollbackInfo> getRollbacksAvailableForImpactLevel(
+            List<RollbackInfo> availableRollbacks, int impactLevel) {
+        return availableRollbacks.stream()
+                .filter(rollbackInfo -> rollbackInfo.getRollbackImpactLevel() == impactLevel)
+                .toList();
+    }
+
+    private int getMinRollbackImpactLevel(List<RollbackInfo> availableRollbacks) {
+        return availableRollbacks.stream()
+                .mapToInt(RollbackInfo::getRollbackImpactLevel)
+                .min()
+                .orElse(-1);
+    }
+
+    private int getUserImpactBasedOnRollbackImpactLevel(List<RollbackInfo> availableRollbacks) {
+        int impact = PackageHealthObserverImpact.USER_IMPACT_LEVEL_0;
+        int minImpact = getMinRollbackImpactLevel(availableRollbacks);
+        switch (minImpact) {
+            case PackageManager.ROLLBACK_USER_IMPACT_LOW:
+                impact = PackageHealthObserverImpact.USER_IMPACT_LEVEL_70;
+                break;
+            case PackageManager.ROLLBACK_USER_IMPACT_HIGH:
+                if (!SystemProperties.getBoolean(PROP_DISABLE_HIGH_IMPACT_ROLLBACK_FLAG, false)) {
+                    impact = PackageHealthObserverImpact.USER_IMPACT_LEVEL_90;
+                }
+                break;
+            default:
+                impact = PackageHealthObserverImpact.USER_IMPACT_LEVEL_0;
+        }
+        return impact;
+    }
+
+    @VisibleForTesting
+    Handler getHandler() {
+        return mHandler;
+    }
+}
diff --git a/services/core/java/com/android/server/rollback/WatchdogRollbackLogger.java b/packages/CrashRecovery/services/module/java/com/android/server/rollback/WatchdogRollbackLogger.java
similarity index 100%
rename from services/core/java/com/android/server/rollback/WatchdogRollbackLogger.java
rename to packages/CrashRecovery/services/module/java/com/android/server/rollback/WatchdogRollbackLogger.java
diff --git a/packages/CrashRecovery/services/module/java/com/android/util/ArrayUtils.java b/packages/CrashRecovery/services/module/java/com/android/util/ArrayUtils.java
new file mode 100644
index 0000000..0b7b986
--- /dev/null
+++ b/packages/CrashRecovery/services/module/java/com/android/util/ArrayUtils.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.util;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+
+import java.io.File;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * Copied over from frameworks/base/core/java/com/android/internal/util/ArrayUtils.java
+ *
+ * @hide
+ */
+public class ArrayUtils {
+    private ArrayUtils() { /* cannot be instantiated */ }
+    public static final File[] EMPTY_FILE = new File[0];
+
+
+    /**
+     * Return first index of {@code value} in {@code array}, or {@code -1} if
+     * not found.
+     */
+    public static <T> int indexOf(@Nullable T[] array, T value) {
+        if (array == null) return -1;
+        for (int i = 0; i < array.length; i++) {
+            if (Objects.equals(array[i], value)) return i;
+        }
+        return -1;
+    }
+
+    /** @hide */
+    public static @NonNull File[] defeatNullable(@Nullable File[] val) {
+        return (val != null) ? val : EMPTY_FILE;
+    }
+
+    /**
+     * Checks if given array is null or has zero elements.
+     */
+    public static boolean isEmpty(@Nullable int[] array) {
+        return array == null || array.length == 0;
+    }
+
+    /**
+     * True if the byte array is null or has length 0.
+     */
+    public static boolean isEmpty(@Nullable byte[] array) {
+        return array == null || array.length == 0;
+    }
+
+    /**
+     * Converts from List of bytes to byte array
+     * @param list
+     * @return byte[]
+     */
+    public static byte[] toPrimitive(List<byte[]> list) {
+        if (list.size() == 0) {
+            return new byte[0];
+        }
+        int byteLen = list.get(0).length;
+        byte[] array = new byte[list.size() * byteLen];
+        for (int i = 0; i < list.size(); i++) {
+            for (int j = 0; j < list.get(i).length; j++) {
+                array[i * byteLen + j] = list.get(i)[j];
+            }
+        }
+        return array;
+    }
+
+    /**
+     * Adds value to given array if not already present, providing set-like
+     * behavior.
+     */
+    public static @NonNull int[] appendInt(@Nullable int[] cur, int val) {
+        return appendInt(cur, val, false);
+    }
+
+    /**
+     * Adds value to given array.
+     */
+    public static @NonNull int[] appendInt(@Nullable int[] cur, int val,
+            boolean allowDuplicates) {
+        if (cur == null) {
+            return new int[] { val };
+        }
+        final int n = cur.length;
+        if (!allowDuplicates) {
+            for (int i = 0; i < n; i++) {
+                if (cur[i] == val) {
+                    return cur;
+                }
+            }
+        }
+        int[] ret = new int[n + 1];
+        System.arraycopy(cur, 0, ret, 0, n);
+        ret[n] = val;
+        return ret;
+    }
+}
diff --git a/packages/CrashRecovery/services/module/java/com/android/util/FileUtils.java b/packages/CrashRecovery/services/module/java/com/android/util/FileUtils.java
new file mode 100644
index 0000000..9c73fee
--- /dev/null
+++ b/packages/CrashRecovery/services/module/java/com/android/util/FileUtils.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.util;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+
+import java.io.BufferedInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * Bits and pieces copied from hidden API of android.os.FileUtils.
+ *
+ * @hide
+ */
+public class FileUtils {
+    /**
+     * Read a text file into a String, optionally limiting the length.
+     *
+     * @param file     to read (will not seek, so things like /proc files are OK)
+     * @param max      length (positive for head, negative of tail, 0 for no limit)
+     * @param ellipsis to add of the file was truncated (can be null)
+     * @return the contents of the file, possibly truncated
+     * @throws IOException if something goes wrong reading the file
+     * @hide
+     */
+    public static @Nullable String readTextFile(@Nullable File file, @Nullable int max,
+            @Nullable String ellipsis) throws IOException {
+        InputStream input = new FileInputStream(file);
+        // wrapping a BufferedInputStream around it because when reading /proc with unbuffered
+        // input stream, bytes read not equal to buffer size is not necessarily the correct
+        // indication for EOF; but it is true for BufferedInputStream due to its implementation.
+        BufferedInputStream bis = new BufferedInputStream(input);
+        try {
+            long size = file.length();
+            if (max > 0 || (size > 0 && max == 0)) {  // "head" mode: read the first N bytes
+                if (size > 0 && (max == 0 || size < max)) max = (int) size;
+                byte[] data = new byte[max + 1];
+                int length = bis.read(data);
+                if (length <= 0) return "";
+                if (length <= max) return new String(data, 0, length);
+                if (ellipsis == null) return new String(data, 0, max);
+                return new String(data, 0, max) + ellipsis;
+            } else if (max < 0) {  // "tail" mode: keep the last N
+                int len;
+                boolean rolled = false;
+                byte[] last = null;
+                byte[] data = null;
+                do {
+                    if (last != null) rolled = true;
+                    byte[] tmp = last;
+                    last = data;
+                    data = tmp;
+                    if (data == null) data = new byte[-max];
+                    len = bis.read(data);
+                } while (len == data.length);
+
+                if (last == null && len <= 0) return "";
+                if (last == null) return new String(data, 0, len);
+                if (len > 0) {
+                    rolled = true;
+                    System.arraycopy(last, len, last, 0, last.length - len);
+                    System.arraycopy(data, 0, last, last.length - len, len);
+                }
+                if (ellipsis == null || !rolled) return new String(last);
+                return ellipsis + new String(last);
+            } else {  // "cat" mode: size unknown, read it all in streaming fashion
+                ByteArrayOutputStream contents = new ByteArrayOutputStream();
+                int len;
+                byte[] data = new byte[1024];
+                do {
+                    len = bis.read(data);
+                    if (len > 0) contents.write(data, 0, len);
+                } while (len == data.length);
+                return contents.toString();
+            }
+        } finally {
+            bis.close();
+            input.close();
+        }
+    }
+
+    /**
+     * Perform an fsync on the given FileOutputStream. The stream at this
+     * point must be flushed but not yet closed.
+     *
+     * @hide
+     */
+    public static boolean sync(FileOutputStream stream) {
+        try {
+            if (stream != null) {
+                stream.getFD().sync();
+            }
+            return true;
+        } catch (IOException e) {
+        }
+        return false;
+    }
+
+    /**
+     * List the files in the directory or return empty file.
+     *
+     * @hide
+     */
+    public static @NonNull File[] listFilesOrEmpty(@Nullable File dir) {
+        return (dir != null) ? ArrayUtils.defeatNullable(dir.listFiles())
+            : ArrayUtils.EMPTY_FILE;
+    }
+}
diff --git a/packages/CrashRecovery/services/module/java/com/android/util/LongArrayQueue.java b/packages/CrashRecovery/services/module/java/com/android/util/LongArrayQueue.java
new file mode 100644
index 0000000..9a24ada
--- /dev/null
+++ b/packages/CrashRecovery/services/module/java/com/android/util/LongArrayQueue.java
@@ -0,0 +1,188 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.util;
+
+import libcore.util.EmptyArray;
+
+import java.util.NoSuchElementException;
+
+/**
+ * Copied from frameworks/base/core/java/android/util/LongArrayQueue.java
+ *
+ * @hide
+ */
+public class LongArrayQueue {
+
+    private long[] mValues;
+    private int mSize;
+    private int mHead;
+    private int mTail;
+
+    private long[] newUnpaddedLongArray(int num) {
+        return new long[num];
+    }
+    /**
+     * Initializes a queue with the given starting capacity.
+     *
+     * @param initialCapacity the capacity.
+     */
+    public LongArrayQueue(int initialCapacity) {
+        if (initialCapacity == 0) {
+            mValues = EmptyArray.LONG;
+        } else {
+            mValues = newUnpaddedLongArray(initialCapacity);
+        }
+        mSize = 0;
+        mHead = mTail = 0;
+    }
+
+    /**
+     * Initializes a queue with default starting capacity.
+     */
+    public LongArrayQueue() {
+        this(16);
+    }
+
+    /** @hide */
+    public static int growSize(int currentSize) {
+        return currentSize <= 4 ? 8 : currentSize * 2;
+    }
+
+    private void grow() {
+        if (mSize < mValues.length) {
+            throw new IllegalStateException("Queue not full yet!");
+        }
+        final int newSize = growSize(mSize);
+        final long[] newArray = newUnpaddedLongArray(newSize);
+        final int r = mValues.length - mHead; // Number of elements on and to the right of head.
+        System.arraycopy(mValues, mHead, newArray, 0, r);
+        System.arraycopy(mValues, 0, newArray, r, mHead);
+        mValues = newArray;
+        mHead = 0;
+        mTail = mSize;
+    }
+
+    /**
+     * Returns the number of elements in the queue.
+     */
+    public int size() {
+        return mSize;
+    }
+
+    /**
+     * Removes all elements from this queue.
+     */
+    public void clear() {
+        mSize = 0;
+        mHead = mTail = 0;
+    }
+
+    /**
+     * Adds a value to the tail of the queue.
+     *
+     * @param value the value to be added.
+     */
+    public void addLast(long value) {
+        if (mSize == mValues.length) {
+            grow();
+        }
+        mValues[mTail] = value;
+        mTail = (mTail + 1) % mValues.length;
+        mSize++;
+    }
+
+    /**
+     * Removes an element from the head of the queue.
+     *
+     * @return the element at the head of the queue.
+     * @throws NoSuchElementException if the queue is empty.
+     */
+    public long removeFirst() {
+        if (mSize == 0) {
+            throw new NoSuchElementException("Queue is empty!");
+        }
+        final long ret = mValues[mHead];
+        mHead = (mHead + 1) % mValues.length;
+        mSize--;
+        return ret;
+    }
+
+    /**
+     * Returns the element at the given position from the head of the queue, where 0 represents the
+     * head of the queue.
+     *
+     * @param position the position from the head of the queue.
+     * @return the element found at the given position.
+     * @throws IndexOutOfBoundsException if {@code position} < {@code 0} or
+     *                                   {@code position} >= {@link #size()}
+     */
+    public long get(int position) {
+        if (position < 0 || position >= mSize) {
+            throw new IndexOutOfBoundsException("Index " + position
+                + " not valid for a queue of size " + mSize);
+        }
+        final int index = (mHead + position) % mValues.length;
+        return mValues[index];
+    }
+
+    /**
+     * Returns the element at the head of the queue, without removing it.
+     *
+     * @return the element at the head of the queue.
+     * @throws NoSuchElementException if the queue is empty
+     */
+    public long peekFirst() {
+        if (mSize == 0) {
+            throw new NoSuchElementException("Queue is empty!");
+        }
+        return mValues[mHead];
+    }
+
+    /**
+     * Returns the element at the tail of the queue.
+     *
+     * @return the element at the tail of the queue.
+     * @throws NoSuchElementException if the queue is empty.
+     */
+    public long peekLast() {
+        if (mSize == 0) {
+            throw new NoSuchElementException("Queue is empty!");
+        }
+        final int index = (mTail == 0) ? mValues.length - 1 : mTail - 1;
+        return mValues[index];
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public String toString() {
+        if (mSize <= 0) {
+            return "{}";
+        }
+
+        final StringBuilder buffer = new StringBuilder(mSize * 64);
+        buffer.append('{');
+        buffer.append(get(0));
+        for (int i = 1; i < mSize; i++) {
+            buffer.append(", ");
+            buffer.append(get(i));
+        }
+        buffer.append('}');
+        return buffer.toString();
+    }
+}
diff --git a/packages/CrashRecovery/services/module/java/com/android/util/XmlUtils.java b/packages/CrashRecovery/services/module/java/com/android/util/XmlUtils.java
new file mode 100644
index 0000000..50823f5
--- /dev/null
+++ b/packages/CrashRecovery/services/module/java/com/android/util/XmlUtils.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.util;
+
+import android.annotation.NonNull;
+import android.system.ErrnoException;
+import android.system.Os;
+
+import com.android.modules.utils.TypedXmlPullParser;
+
+import libcore.util.XmlObjectFactory;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.BufferedInputStream;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ *  Bits and pieces copied from hidden API of
+ *  frameworks/base/core/java/com/android/internal/util/XmlUtils.java
+ *
+ * @hide
+ */
+public class XmlUtils {
+
+    private static final String STRING_ARRAY_SEPARATOR = ":";
+
+    /** @hide */
+    public static final void beginDocument(XmlPullParser parser, String firstElementName)
+            throws XmlPullParserException, IOException {
+        int type;
+        while ((type = parser.next()) != parser.START_TAG
+            && type != parser.END_DOCUMENT) {
+            // Do nothing
+        }
+
+        if (type != parser.START_TAG) {
+            throw new XmlPullParserException("No start tag found");
+        }
+
+        if (!parser.getName().equals(firstElementName)) {
+            throw new XmlPullParserException("Unexpected start tag: found " + parser.getName()
+                + ", expected " + firstElementName);
+        }
+    }
+
+    /** @hide */
+    public static boolean nextElementWithin(XmlPullParser parser, int outerDepth)
+            throws IOException, XmlPullParserException {
+        for (;;) {
+            int type = parser.next();
+            if (type == XmlPullParser.END_DOCUMENT
+                    || (type == XmlPullParser.END_TAG && parser.getDepth() == outerDepth)) {
+                return false;
+            }
+            if (type == XmlPullParser.START_TAG
+                    && parser.getDepth() == outerDepth + 1) {
+                return true;
+            }
+        }
+    }
+
+    private static XmlPullParser newPullParser() {
+        try {
+            XmlPullParser parser = XmlObjectFactory.newXmlPullParser();
+            parser.setFeature(XmlPullParser.FEATURE_PROCESS_DOCDECL, true);
+            parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
+            return parser;
+        } catch (XmlPullParserException e) {
+            throw new AssertionError();
+        }
+    }
+
+    /** @hide */
+    public static @NonNull TypedXmlPullParser resolvePullParser(@NonNull InputStream in)
+            throws IOException {
+        final byte[] magic = new byte[4];
+        if (in instanceof FileInputStream) {
+            try {
+                Os.pread(((FileInputStream) in).getFD(), magic, 0, magic.length, 0);
+            } catch (ErrnoException e) {
+                throw e.rethrowAsIOException();
+            }
+        } else {
+            if (!in.markSupported()) {
+                in = new BufferedInputStream(in);
+            }
+            in.mark(8);
+            in.read(magic);
+            in.reset();
+        }
+
+        final TypedXmlPullParser xml;
+        xml = (TypedXmlPullParser) newPullParser();
+        try {
+            xml.setInput(in, "UTF_8");
+        } catch (XmlPullParserException e) {
+            throw new IOException(e);
+        }
+        return xml;
+    }
+}
diff --git a/services/core/java/com/android/server/ExplicitHealthCheckController.java b/packages/CrashRecovery/services/platform/java/com/android/server/ExplicitHealthCheckController.java
similarity index 100%
rename from services/core/java/com/android/server/ExplicitHealthCheckController.java
rename to packages/CrashRecovery/services/platform/java/com/android/server/ExplicitHealthCheckController.java
diff --git a/services/core/java/com/android/server/PackageWatchdog.java b/packages/CrashRecovery/services/platform/java/com/android/server/PackageWatchdog.java
similarity index 100%
rename from services/core/java/com/android/server/PackageWatchdog.java
rename to packages/CrashRecovery/services/platform/java/com/android/server/PackageWatchdog.java
diff --git a/services/core/java/com/android/server/RescueParty.java b/packages/CrashRecovery/services/platform/java/com/android/server/RescueParty.java
similarity index 100%
rename from services/core/java/com/android/server/RescueParty.java
rename to packages/CrashRecovery/services/platform/java/com/android/server/RescueParty.java
diff --git a/services/core/java/com/android/server/crashrecovery/CrashRecoveryModule.java b/packages/CrashRecovery/services/platform/java/com/android/server/crashrecovery/CrashRecoveryModule.java
similarity index 100%
copy from services/core/java/com/android/server/crashrecovery/CrashRecoveryModule.java
copy to packages/CrashRecovery/services/platform/java/com/android/server/crashrecovery/CrashRecoveryModule.java
diff --git a/services/core/java/com/android/server/crashrecovery/CrashRecoveryUtils.java b/packages/CrashRecovery/services/platform/java/com/android/server/crashrecovery/CrashRecoveryUtils.java
similarity index 92%
copy from services/core/java/com/android/server/crashrecovery/CrashRecoveryUtils.java
copy to packages/CrashRecovery/services/platform/java/com/android/server/crashrecovery/CrashRecoveryUtils.java
index 3eb3380..2e2a937 100644
--- a/services/core/java/com/android/server/crashrecovery/CrashRecoveryUtils.java
+++ b/packages/CrashRecovery/services/platform/java/com/android/server/crashrecovery/CrashRecoveryUtils.java
@@ -18,7 +18,7 @@
 
 import android.os.Environment;
 import android.util.IndentingPrintWriter;
-import android.util.Slog;
+import android.util.Log;
 
 import java.io.BufferedReader;
 import java.io.File;
@@ -41,7 +41,7 @@
 
     /** Persist recovery related events in crashrecovery events file.**/
     public static void logCrashRecoveryEvent(int priority, String msg) {
-        Slog.println(priority, TAG, msg);
+        Log.println(priority, TAG, msg);
         try {
             File fname = getCrashRecoveryEventsFile();
             synchronized (sFileLock) {
@@ -52,7 +52,7 @@
                 pw.close();
             }
         } catch (IOException e) {
-            Slog.e(TAG, "Unable to log CrashRecoveryEvents " + e.getMessage());
+            Log.e(TAG, "Unable to log CrashRecoveryEvents " + e.getMessage());
         }
     }
 
@@ -72,7 +72,7 @@
                     pw.println(line);
                 }
             } catch (IOException e) {
-                Slog.e(TAG, "Unable to dump CrashRecoveryEvents " + e.getMessage());
+                Log.e(TAG, "Unable to dump CrashRecoveryEvents " + e.getMessage());
             }
         }
         pw.decreaseIndent();
diff --git a/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java b/packages/CrashRecovery/services/platform/java/com/android/server/rollback/RollbackPackageHealthObserver.java
similarity index 100%
rename from services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java
rename to packages/CrashRecovery/services/platform/java/com/android/server/rollback/RollbackPackageHealthObserver.java
diff --git a/services/core/java/com/android/server/rollback/WatchdogRollbackLogger.java b/packages/CrashRecovery/services/platform/java/com/android/server/rollback/WatchdogRollbackLogger.java
similarity index 100%
copy from services/core/java/com/android/server/rollback/WatchdogRollbackLogger.java
copy to packages/CrashRecovery/services/platform/java/com/android/server/rollback/WatchdogRollbackLogger.java
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/common/ui/BottomSheet.kt b/packages/CredentialManager/src/com/android/credentialmanager/common/ui/BottomSheet.kt
index c48e7e4..8df8a07 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/common/ui/BottomSheet.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/common/ui/BottomSheet.kt
@@ -33,7 +33,6 @@
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.graphics.Color
 import com.android.compose.rememberSystemUiController
-import com.android.compose.theme.LocalAndroidColorScheme
 import androidx.compose.ui.unit.dp
 import com.android.credentialmanager.common.material.ModalBottomSheetLayout
 import com.android.credentialmanager.common.material.ModalBottomSheetValue
@@ -57,7 +56,7 @@
         )
         androidx.compose.material3.ModalBottomSheet(
                 onDismissRequest = onDismiss,
-                containerColor = LocalAndroidColorScheme.current.surfaceBright,
+                containerColor = MaterialTheme.colorScheme.surfaceBright,
                 sheetState = state,
                 content = {
                     Box(
@@ -91,7 +90,7 @@
             setBottomSheetSystemBarsColor(sysUiController)
         }
         ModalBottomSheetLayout(
-                sheetBackgroundColor = LocalAndroidColorScheme.current.surfaceBright,
+                sheetBackgroundColor = MaterialTheme.colorScheme.surfaceBright,
                 modifier = Modifier.background(Color.Transparent),
                 sheetState = state,
                 sheetContent = { sheetContent() },
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/common/ui/Cards.kt b/packages/CredentialManager/src/com/android/credentialmanager/common/ui/Cards.kt
index 006a2d9..426fec2 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/common/ui/Cards.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/common/ui/Cards.kt
@@ -29,12 +29,12 @@
 import androidx.compose.foundation.lazy.LazyListScope
 import androidx.compose.material3.Card
 import androidx.compose.material3.CardDefaults
+import androidx.compose.material3.MaterialTheme
 import androidx.compose.runtime.Composable
 import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.unit.dp
-import com.android.compose.theme.LocalAndroidColorScheme
 import com.android.credentialmanager.ui.theme.Shapes
 
 /**
@@ -54,7 +54,7 @@
         modifier = modifier.fillMaxWidth().wrapContentHeight(),
         border = null,
         colors = CardDefaults.cardColors(
-            containerColor = LocalAndroidColorScheme.current.surfaceBright,
+            containerColor = MaterialTheme.colorScheme.surfaceBright,
         ),
     ) {
         if (topAppBar != null) {
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/common/ui/Entry.kt b/packages/CredentialManager/src/com/android/credentialmanager/common/ui/Entry.kt
index 2c3c63b..84078c4 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/common/ui/Entry.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/common/ui/Entry.kt
@@ -31,6 +31,7 @@
 import androidx.compose.material.icons.outlined.Lock
 import androidx.compose.material3.Icon
 import androidx.compose.material3.IconButton
+import androidx.compose.material3.MaterialTheme
 import androidx.compose.material3.SuggestionChip
 import androidx.compose.material3.SuggestionChipDefaults
 import androidx.compose.runtime.Composable
@@ -52,7 +53,6 @@
 import androidx.compose.ui.unit.Dp
 import androidx.compose.ui.unit.LayoutDirection
 import androidx.compose.ui.unit.dp
-import com.android.compose.theme.LocalAndroidColorScheme
 import com.android.credentialmanager.ui.theme.EntryShape
 import com.android.credentialmanager.ui.theme.Shapes
 
@@ -172,7 +172,7 @@
                             // Decorative purpose only.
                             contentDescription = null,
                             modifier = Modifier.size(24.dp),
-                            tint = LocalAndroidColorScheme.current.onSurfaceVariant,
+                            tint = MaterialTheme.colorScheme.onSurfaceVariant,
                         )
                     }
                 }
@@ -186,7 +186,7 @@
                         Icon(
                             modifier = iconSize,
                             bitmap = iconImageBitmap,
-                            tint = LocalAndroidColorScheme.current.onSurfaceVariant,
+                            tint = MaterialTheme.colorScheme.onSurfaceVariant,
                             // Decorative purpose only.
                             contentDescription = null,
                         )
@@ -210,7 +210,7 @@
                     Icon(
                         modifier = iconSize,
                         imageVector = iconImageVector,
-                        tint = LocalAndroidColorScheme.current.onSurfaceVariant,
+                        tint = MaterialTheme.colorScheme.onSurfaceVariant,
                         // Decorative purpose only.
                         contentDescription = null,
                     )
@@ -222,7 +222,7 @@
                     Icon(
                         modifier = iconSize,
                         painter = iconPainter,
-                        tint = LocalAndroidColorScheme.current.onSurfaceVariant,
+                        tint = MaterialTheme.colorScheme.onSurfaceVariant,
                         // Decorative purpose only.
                         contentDescription = null,
                     )
@@ -233,9 +233,9 @@
         },
         border = null,
         colors = SuggestionChipDefaults.suggestionChipColors(
-            containerColor = LocalAndroidColorScheme.current.surfaceContainerHigh,
-            labelColor = LocalAndroidColorScheme.current.onSurfaceVariant,
-            iconContentColor = LocalAndroidColorScheme.current.onSurfaceVariant,
+            containerColor = MaterialTheme.colorScheme.surfaceContainerHigh,
+            labelColor = MaterialTheme.colorScheme.onSurfaceVariant,
+            iconContentColor = MaterialTheme.colorScheme.onSurfaceVariant,
         ),
     )
 }
@@ -338,7 +338,7 @@
                         imageVector = navigationIcon,
                         contentDescription = navigationIconContentDescription,
                         modifier = Modifier.size(24.dp).autoMirrored(),
-                        tint = LocalAndroidColorScheme.current.onSurfaceVariant,
+                        tint = MaterialTheme.colorScheme.onSurfaceVariant,
                 )
             }
         }
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/common/ui/SectionHeader.kt b/packages/CredentialManager/src/com/android/credentialmanager/common/ui/SectionHeader.kt
index 342af3b..37268ad 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/common/ui/SectionHeader.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/common/ui/SectionHeader.kt
@@ -21,23 +21,23 @@
 import androidx.compose.foundation.layout.padding
 import androidx.compose.foundation.layout.wrapContentHeight
 import androidx.compose.runtime.Composable
+import androidx.compose.material3.MaterialTheme
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.unit.dp
-import com.android.compose.theme.LocalAndroidColorScheme
 
 @Composable
 fun CredentialListSectionHeader(text: String, isFirstSection: Boolean) {
     InternalSectionHeader(
         text = text,
-        color = LocalAndroidColorScheme.current.onSurfaceVariant,
+        color = MaterialTheme.colorScheme.onSurfaceVariant,
         applyTopPadding = !isFirstSection
     )
 }
 
 @Composable
 fun MoreAboutPasskeySectionHeader(text: String) {
-    InternalSectionHeader(text, LocalAndroidColorScheme.current.onSurface)
+    InternalSectionHeader(text, MaterialTheme.colorScheme.onSurface)
 }
 
 @Composable
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/common/ui/SystemUiControllerUtils.kt b/packages/CredentialManager/src/com/android/credentialmanager/common/ui/SystemUiControllerUtils.kt
index b4075f1..d325ebb 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/common/ui/SystemUiControllerUtils.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/common/ui/SystemUiControllerUtils.kt
@@ -17,9 +17,9 @@
 package com.android.credentialmanager.common.ui
 
 import androidx.compose.runtime.Composable
+import androidx.compose.material3.MaterialTheme
 import androidx.compose.ui.graphics.Color
 import com.android.compose.SystemUiController
-import com.android.compose.theme.LocalAndroidColorScheme
 import com.android.credentialmanager.common.material.ModalBottomSheetDefaults
 
 @Composable
@@ -34,7 +34,7 @@
         darkIcons = false
     )
     sysUiController.setNavigationBarColor(
-        color = LocalAndroidColorScheme.current.surfaceBright,
+        color = MaterialTheme.colorScheme.surfaceBright,
         darkIcons = false
     )
 }
\ No newline at end of file
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/common/ui/Texts.kt b/packages/CredentialManager/src/com/android/credentialmanager/common/ui/Texts.kt
index 68c2244..3e999cb 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/common/ui/Texts.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/common/ui/Texts.kt
@@ -26,7 +26,6 @@
 import androidx.compose.ui.text.style.Hyphens
 import androidx.compose.ui.text.style.TextAlign
 import androidx.compose.ui.text.style.TextOverflow
-import com.android.compose.theme.LocalAndroidColorScheme
 
 /**
  * The headline for a screen. E.g. "Create a passkey for X", "Choose a saved sign-in for X".
@@ -38,7 +37,7 @@
     Text(
         modifier = modifier.wrapContentSize(),
         text = text,
-        color = LocalAndroidColorScheme.current.onSurface,
+        color = MaterialTheme.colorScheme.onSurface,
         textAlign = TextAlign.Center,
         style = MaterialTheme.typography.headlineSmall.copy(hyphens = Hyphens.Auto),
     )
@@ -52,7 +51,7 @@
     Text(
         modifier = modifier.wrapContentSize(),
         text = text,
-        color = LocalAndroidColorScheme.current.onSurfaceVariant,
+        color = MaterialTheme.colorScheme.onSurfaceVariant,
         style = MaterialTheme.typography.bodyMedium.copy(hyphens = Hyphens.Auto),
     )
 }
@@ -70,7 +69,7 @@
     Text(
         modifier = modifier.wrapContentSize(),
         text = text,
-        color = LocalAndroidColorScheme.current.onSurfaceVariant,
+        color = MaterialTheme.colorScheme.onSurfaceVariant,
         style = MaterialTheme.typography.bodySmall.copy(hyphens = Hyphens.Auto),
         overflow = TextOverflow.Ellipsis,
         maxLines = if (enforceOneLine) 1 else Int.MAX_VALUE,
@@ -86,7 +85,7 @@
     Text(
         modifier = modifier.wrapContentSize(),
         text = text,
-        color = LocalAndroidColorScheme.current.onSurface,
+        color = MaterialTheme.colorScheme.onSurface,
         style = MaterialTheme.typography.titleLarge.copy(hyphens = Hyphens.Auto),
     )
 }
@@ -104,7 +103,7 @@
     Text(
         modifier = modifier.wrapContentSize(),
         text = text,
-        color = LocalAndroidColorScheme.current.onSurface,
+        color = MaterialTheme.colorScheme.onSurface,
         style = MaterialTheme.typography.titleSmall.copy(hyphens = Hyphens.Auto),
         overflow = TextOverflow.Ellipsis,
         maxLines = if (enforceOneLine) 1 else Int.MAX_VALUE,
@@ -160,7 +159,7 @@
         modifier = modifier.wrapContentSize(),
         text = text,
         textAlign = TextAlign.Center,
-        color = LocalAndroidColorScheme.current.onSurfaceVariant,
+        color = MaterialTheme.colorScheme.onSurfaceVariant,
         style = MaterialTheme.typography.labelLarge.copy(hyphens = Hyphens.Auto),
     )
 }
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialComponents.kt b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialComponents.kt
index 4993a1f..d788891 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialComponents.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialComponents.kt
@@ -30,6 +30,7 @@
 import androidx.compose.foundation.layout.padding
 import androidx.compose.foundation.layout.wrapContentHeight
 import androidx.compose.material3.Divider
+import androidx.compose.material3.MaterialTheme
 import androidx.compose.material.icons.Icons
 import androidx.compose.material.icons.outlined.NewReleases
 import androidx.compose.material.icons.filled.Add
@@ -46,7 +47,6 @@
 import androidx.compose.ui.unit.Dp
 import androidx.compose.ui.unit.dp
 import androidx.core.graphics.drawable.toBitmap
-import com.android.compose.theme.LocalAndroidColorScheme
 import com.android.credentialmanager.CredentialSelectorViewModel
 import com.android.credentialmanager.R
 import com.android.credentialmanager.common.BiometricError
@@ -448,7 +448,7 @@
                 item {
                     Divider(
                         thickness = 1.dp,
-                        color = LocalAndroidColorScheme.current.outlineVariant,
+                        color = MaterialTheme.colorScheme.outlineVariant,
                         modifier = Modifier.padding(vertical = 16.dp)
                     )
                 }
diff --git a/packages/SettingsLib/ActionButtonsPreference/res/drawable/half_rounded_left_bk.xml b/packages/SettingsLib/ActionButtonsPreference/res/drawable/half_rounded_left_bk.xml
index 0d4ef3c..8d6f0da4 100644
--- a/packages/SettingsLib/ActionButtonsPreference/res/drawable/half_rounded_left_bk.xml
+++ b/packages/SettingsLib/ActionButtonsPreference/res/drawable/half_rounded_left_bk.xml
@@ -1,18 +1,18 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-  ~ Copyright (C) 2021 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
+    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.
   -->
 
 <shape xmlns:android="http://schemas.android.com/apk/res/android"
diff --git a/packages/SettingsLib/ActionButtonsPreference/res/drawable/left_rounded_ripple.xml b/packages/SettingsLib/ActionButtonsPreference/res/drawable/left_rounded_ripple.xml
index 1584b45..f82388c 100644
--- a/packages/SettingsLib/ActionButtonsPreference/res/drawable/left_rounded_ripple.xml
+++ b/packages/SettingsLib/ActionButtonsPreference/res/drawable/left_rounded_ripple.xml
@@ -1,18 +1,18 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-  ~ Copyright (C) 2021 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
+    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.
   -->
 
 <ripple xmlns:android="http://schemas.android.com/apk/res/android"
diff --git a/packages/SettingsLib/ActionButtonsPreference/res/drawable/right_rounded_ripple.xml b/packages/SettingsLib/ActionButtonsPreference/res/drawable/right_rounded_ripple.xml
index 15f2b5c..3b0cca0 100644
--- a/packages/SettingsLib/ActionButtonsPreference/res/drawable/right_rounded_ripple.xml
+++ b/packages/SettingsLib/ActionButtonsPreference/res/drawable/right_rounded_ripple.xml
@@ -1,18 +1,18 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-  ~ Copyright (C) 2021 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
+    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.
   -->
 
 <ripple xmlns:android="http://schemas.android.com/apk/res/android"
diff --git a/packages/SettingsLib/ActionButtonsPreference/res/drawable/rounded_ripple.xml b/packages/SettingsLib/ActionButtonsPreference/res/drawable/rounded_ripple.xml
index 90eefbe..bdf9114 100644
--- a/packages/SettingsLib/ActionButtonsPreference/res/drawable/rounded_ripple.xml
+++ b/packages/SettingsLib/ActionButtonsPreference/res/drawable/rounded_ripple.xml
@@ -1,18 +1,18 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-  ~ Copyright (C) 2021 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
+    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.
   -->
 
 <ripple xmlns:android="http://schemas.android.com/apk/res/android"
diff --git a/packages/SettingsLib/ActionButtonsPreference/res/drawable/square_bk.xml b/packages/SettingsLib/ActionButtonsPreference/res/drawable/square_bk.xml
index f0da7b4..d56c843 100644
--- a/packages/SettingsLib/ActionButtonsPreference/res/drawable/square_bk.xml
+++ b/packages/SettingsLib/ActionButtonsPreference/res/drawable/square_bk.xml
@@ -1,18 +1,18 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-  ~ Copyright (C) 2021 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
+    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.
   -->
 
 <shape xmlns:android="http://schemas.android.com/apk/res/android"
diff --git a/packages/SettingsLib/ActionButtonsPreference/res/drawable/square_ripple.xml b/packages/SettingsLib/ActionButtonsPreference/res/drawable/square_ripple.xml
index 06be00d..9270cbe 100644
--- a/packages/SettingsLib/ActionButtonsPreference/res/drawable/square_ripple.xml
+++ b/packages/SettingsLib/ActionButtonsPreference/res/drawable/square_ripple.xml
@@ -1,18 +1,18 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-  ~ Copyright (C) 2021 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
+    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.
   -->
 
 <ripple xmlns:android="http://schemas.android.com/apk/res/android"
diff --git a/packages/SettingsLib/ActionButtonsPreference/res/values/arrays.xml b/packages/SettingsLib/ActionButtonsPreference/res/values/arrays.xml
index fe88845..180564d 100644
--- a/packages/SettingsLib/ActionButtonsPreference/res/values/arrays.xml
+++ b/packages/SettingsLib/ActionButtonsPreference/res/values/arrays.xml
@@ -1,18 +1,18 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-  ~ Copyright (C) 2021 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
+    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.
   -->
 
 <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
diff --git a/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/KeyValueStore.kt b/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/KeyValueStore.kt
index 3d41337..5f1f8df 100644
--- a/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/KeyValueStore.kt
+++ b/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/KeyValueStore.kt
@@ -25,6 +25,7 @@
     fun contains(key: String): Boolean
 
     /** Gets default value of given key. */
+    @Suppress("UNCHECKED_CAST")
     fun <T : Any> getDefaultValue(key: String, valueType: Class<T>): T? =
         when (valueType) {
             Boolean::class.javaObjectType -> false
@@ -56,6 +57,7 @@
 
     override fun contains(key: String): Boolean = sharedPreferences.contains(key)
 
+    @Suppress("IMPLICIT_CAST_TO_ANY", "UNCHECKED_CAST")
     override fun <T : Any> getValue(key: String, valueType: Class<T>): T? =
         when (valueType) {
             Boolean::class.javaObjectType -> sharedPreferences.getBoolean(key, false)
@@ -68,6 +70,7 @@
         }
             as T?
 
+    @Suppress("UNCHECKED_CAST")
     override fun <T : Any> setValue(key: String, valueType: Class<T>, value: T?) {
         if (value == null) {
             sharedPreferences.edit().remove(key).apply()
diff --git a/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/SettingsGlobalStore.kt b/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/SettingsGlobalStore.kt
index 4aef0fc..fb93559 100644
--- a/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/SettingsGlobalStore.kt
+++ b/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/SettingsGlobalStore.kt
@@ -34,6 +34,7 @@
 
     override fun contains(key: String): Boolean = Global.getString(contentResolver, key) != null
 
+    @Suppress("UNCHECKED_CAST")
     override fun <T : Any> getValue(key: String, valueType: Class<T>): T? =
         try {
             when (valueType) {
diff --git a/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/SettingsSecureStore.kt b/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/SettingsSecureStore.kt
index 9f41ecb..bc37571 100644
--- a/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/SettingsSecureStore.kt
+++ b/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/SettingsSecureStore.kt
@@ -34,6 +34,7 @@
 
     override fun contains(key: String): Boolean = Secure.getString(contentResolver, key) != null
 
+    @Suppress("UNCHECKED_CAST")
     override fun <T : Any> getValue(key: String, valueType: Class<T>): T? =
         try {
             when (valueType) {
diff --git a/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/SettingsStore.kt b/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/SettingsStore.kt
index 5981688..fdefa39 100644
--- a/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/SettingsStore.kt
+++ b/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/SettingsStore.kt
@@ -27,7 +27,7 @@
 import java.util.concurrent.atomic.AtomicInteger
 
 /** Base class of the Settings provider data stores. */
-open abstract class SettingsStore(protected val contentResolver: ContentResolver) :
+abstract class SettingsStore(protected val contentResolver: ContentResolver) :
     KeyedDataObservable<String>(), KeyValueStore {
 
     /**
diff --git a/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/SettingsSystemStore.kt b/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/SettingsSystemStore.kt
index 6cca7ed..1c75c7c 100644
--- a/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/SettingsSystemStore.kt
+++ b/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/SettingsSystemStore.kt
@@ -34,6 +34,7 @@
 
     override fun contains(key: String): Boolean = System.getString(contentResolver, key) != null
 
+    @Suppress("UNCHECKED_CAST")
     override fun <T : Any> getValue(key: String, valueType: Class<T>): T? =
         try {
             when (valueType) {
diff --git a/packages/SettingsLib/IntroPreference/res/layout/settingslib_expressive_preference_intro.xml b/packages/SettingsLib/IntroPreference/res/layout/settingslib_expressive_preference_intro.xml
index 203a395..2edc001 100644
--- a/packages/SettingsLib/IntroPreference/res/layout/settingslib_expressive_preference_intro.xml
+++ b/packages/SettingsLib/IntroPreference/res/layout/settingslib_expressive_preference_intro.xml
@@ -31,7 +31,6 @@
 
         <TextView
             android:id="@android:id/title"
-            android:text="Title"
             style="@style/SettingsLibEntityHeaderTitle"/>
 
         <com.android.settingslib.widget.CollapsableTextView
diff --git a/packages/SettingsLib/Preference/Android.bp b/packages/SettingsLib/Preference/Android.bp
index e83e17c..bff95ce 100644
--- a/packages/SettingsLib/Preference/Android.bp
+++ b/packages/SettingsLib/Preference/Android.bp
@@ -1,3 +1,19 @@
+//
+// Copyright (C) 2024 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES 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_license"],
 }
@@ -22,16 +38,3 @@
     ],
     kotlincflags: ["-Xjvm-default=all"],
 }
-
-android_library {
-    name: "SettingsLibPreference-testutils",
-    srcs: ["testutils/**/*.kt"],
-    static_libs: [
-        "SettingsLibPreference",
-        "androidx.fragment_fragment-testing",
-        "androidx.test.core",
-        "androidx.test.ext.junit",
-        "flag-junit",
-        "truth",
-    ],
-}
diff --git a/packages/SettingsLib/Preference/src/com/android/settingslib/preference/PreferenceDataStoreAdapter.kt b/packages/SettingsLib/Preference/src/com/android/settingslib/preference/PreferenceDataStoreAdapter.kt
index 02acfca..c2728b4 100644
--- a/packages/SettingsLib/Preference/src/com/android/settingslib/preference/PreferenceDataStoreAdapter.kt
+++ b/packages/SettingsLib/Preference/src/com/android/settingslib/preference/PreferenceDataStoreAdapter.kt
@@ -37,6 +37,7 @@
     override fun getString(key: String, defValue: String?): String? =
         keyValueStore.getValue(key, String::class.javaObjectType) ?: defValue
 
+    @Suppress("UNCHECKED_CAST")
     override fun getStringSet(key: String, defValues: Set<String>?): Set<String>? =
         (keyValueStore.getValue(key, Set::class.javaObjectType) as Set<String>?) ?: defValues
 
diff --git a/packages/SettingsLib/Preference/src/com/android/settingslib/preference/PreferenceFragment.kt b/packages/SettingsLib/Preference/src/com/android/settingslib/preference/PreferenceFragment.kt
index a270681..debaf3e 100644
--- a/packages/SettingsLib/Preference/src/com/android/settingslib/preference/PreferenceFragment.kt
+++ b/packages/SettingsLib/Preference/src/com/android/settingslib/preference/PreferenceFragment.kt
@@ -18,6 +18,7 @@
 
 import android.content.Context
 import android.os.Bundle
+import android.util.Log
 import androidx.annotation.XmlRes
 import androidx.preference.PreferenceFragmentCompat
 import androidx.preference.PreferenceScreen
@@ -42,7 +43,9 @@
     override fun createPreferenceScreen(factory: PreferenceScreenFactory): PreferenceScreen? {
         val context = factory.context
         fun createPreferenceScreenFromResource() =
-            factory.inflate(getPreferenceScreenResId(context))
+            factory.inflate(getPreferenceScreenResId(context))?.also {
+                Log.i(TAG, "Load screen " + it.key + " from resource")
+            }
 
         val screenCreator =
             getPreferenceScreenCreator(context) ?: return createPreferenceScreenFromResource()
@@ -50,10 +53,12 @@
         val preferenceHierarchy = screenCreator.getPreferenceHierarchy(context)
         val preferenceScreen =
             if (screenCreator.hasCompleteHierarchy()) {
+                Log.i(TAG, "Load screen " + screenCreator.key + " from hierarchy")
                 factory.getOrCreatePreferenceScreen().apply {
                     inflatePreferenceHierarchy(preferenceBindingFactory, preferenceHierarchy)
                 }
             } else {
+                Log.i(TAG, "Screen " + screenCreator.key + " is hybrid")
                 createPreferenceScreenFromResource()?.also {
                     bindRecursively(it, preferenceBindingFactory, preferenceHierarchy)
                 } ?: return null
@@ -83,4 +88,8 @@
         preferenceScreenBindingHelper?.close()
         super.onDestroy()
     }
+
+    companion object {
+        private const val TAG = "PreferenceFragment"
+    }
 }
diff --git a/packages/SettingsLib/Preference/testutils/Android.bp b/packages/SettingsLib/Preference/testutils/Android.bp
new file mode 100644
index 0000000..5287d6c
--- /dev/null
+++ b/packages/SettingsLib/Preference/testutils/Android.bp
@@ -0,0 +1,32 @@
+//
+// Copyright (C) 2024 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES 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_license"],
+}
+
+android_library {
+    name: "SettingsLibPreference-testutils",
+    srcs: ["**/*.kt"],
+    static_libs: [
+        "SettingsLibPreference",
+        "androidx.fragment_fragment-testing",
+        "androidx.test.core",
+        "androidx.test.ext.junit",
+        "flag-junit",
+        "truth",
+    ],
+}
diff --git a/packages/SettingsLib/Preference/testutils/AndroidManifest.xml b/packages/SettingsLib/Preference/testutils/AndroidManifest.xml
new file mode 100644
index 0000000..4e807a6
--- /dev/null
+++ b/packages/SettingsLib/Preference/testutils/AndroidManifest.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Copyright (C) 2024 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.settingslib.preference.testutils">
+
+  <uses-sdk android:minSdkVersion="21" />
+</manifest>
diff --git a/packages/SettingsLib/SelectorWithWidgetPreference/res/values/attrs.xml b/packages/SettingsLib/SelectorWithWidgetPreference/res/values/attrs.xml
index 7ffde25..b90de6b 100644
--- a/packages/SettingsLib/SelectorWithWidgetPreference/res/values/attrs.xml
+++ b/packages/SettingsLib/SelectorWithWidgetPreference/res/values/attrs.xml
@@ -1,17 +1,18 @@
-<?xml version="1.0" encoding="utf-8"?><!--
-  ~ Copyright (C) 2024 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+    Copyright (C) 2024 The Android Open Source Project
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
   -->
 
 <resources>
diff --git a/packages/SettingsLib/SelectorWithWidgetPreference/src/com/android/settingslib/widget/SelectorWithWidgetPreference.java b/packages/SettingsLib/SelectorWithWidgetPreference/src/com/android/settingslib/widget/SelectorWithWidgetPreference.java
index e6726dc..03a2101 100644
--- a/packages/SettingsLib/SelectorWithWidgetPreference/src/com/android/settingslib/widget/SelectorWithWidgetPreference.java
+++ b/packages/SettingsLib/SelectorWithWidgetPreference/src/com/android/settingslib/widget/SelectorWithWidgetPreference.java
@@ -255,4 +255,9 @@
             a.recycle();
         }
     }
+
+    @VisibleForTesting(otherwise = VisibleForTesting.NONE)
+    public View getExtraWidget() {
+        return mExtraWidget;
+    }
 }
diff --git a/packages/SettingsLib/SettingsTheme/res/drawable-v31/settingslib_list_divider.xml b/packages/SettingsLib/SettingsTheme/res/drawable-v31/settingslib_list_divider.xml
new file mode 100644
index 0000000..eb588d9
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/drawable-v31/settingslib_list_divider.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2024 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+    <solid android:color="@color/settingslib_list_divider_color" />
+    <size
+        android:height="1dp"
+        android:width="1dp" />
+</shape>
\ No newline at end of file
diff --git a/packages/SettingsLib/SettingsTheme/res/drawable-v35/settingslib_expressive_icon_chevron.xml b/packages/SettingsLib/SettingsTheme/res/drawable-v35/settingslib_expressive_icon_chevron.xml
index 16ca18a..9447653 100644
--- a/packages/SettingsLib/SettingsTheme/res/drawable-v35/settingslib_expressive_icon_chevron.xml
+++ b/packages/SettingsLib/SettingsTheme/res/drawable-v35/settingslib_expressive_icon_chevron.xml
@@ -1,18 +1,18 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-  ~ Copyright (C) 2024 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
+    Copyright (C) 2024 The Android Open Source Project
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT 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"
diff --git a/packages/SettingsLib/SettingsTheme/res/drawable-v35/settingslib_list_divider.xml b/packages/SettingsLib/SettingsTheme/res/drawable-v35/settingslib_list_divider.xml
new file mode 100644
index 0000000..c17f7ee
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/drawable-v35/settingslib_list_divider.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2024 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+    <solid android:color="@color/settingslib_materialColorOutline" />
+    <size
+        android:height="1dp"
+        android:width="1dp" />
+</shape>
\ No newline at end of file
diff --git a/packages/SettingsLib/SettingsTheme/res/layout-v31/settingslib_preference_frame.xml b/packages/SettingsLib/SettingsTheme/res/layout-v31/settingslib_preference_frame.xml
index 433d264..128f7a1 100644
--- a/packages/SettingsLib/SettingsTheme/res/layout-v31/settingslib_preference_frame.xml
+++ b/packages/SettingsLib/SettingsTheme/res/layout-v31/settingslib_preference_frame.xml
@@ -29,7 +29,6 @@
         android:layout_height="wrap_content"
         android:layout_gravity="start"
         android:textAlignment="viewStart"
-        android:text="Title"
         android:maxLines="2"
         android:textAppearance="?android:attr/textAppearanceListItem"
         android:ellipsize="marquee"/>
@@ -41,7 +40,6 @@
         android:layout_below="@android:id/title"
         android:layout_alignLeft="@android:id/title"
         android:layout_alignStart="@android:id/title"
-        android:text="Summary summary summary"
         android:layout_gravity="start"
         android:textAlignment="viewStart"
         android:textColor="?android:attr/textColorSecondary"
diff --git a/packages/SettingsLib/SettingsTheme/res/layout-v33/settingslib_preference.xml b/packages/SettingsLib/SettingsTheme/res/layout-v33/settingslib_preference.xml
index 4e23b65..952562e 100644
--- a/packages/SettingsLib/SettingsTheme/res/layout-v33/settingslib_preference.xml
+++ b/packages/SettingsLib/SettingsTheme/res/layout-v33/settingslib_preference.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-    Copyright (C) 2022 The Android Open Source Project
+    Copyright (C) 2021 The Android Open Source Project
 
     Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
diff --git a/packages/SettingsLib/SettingsTheme/res/layout-v33/settingslib_preference_frame.xml b/packages/SettingsLib/SettingsTheme/res/layout-v33/settingslib_preference_frame.xml
index f93e1b9..599e817 100644
--- a/packages/SettingsLib/SettingsTheme/res/layout-v33/settingslib_preference_frame.xml
+++ b/packages/SettingsLib/SettingsTheme/res/layout-v33/settingslib_preference_frame.xml
@@ -29,7 +29,6 @@
         android:layout_height="wrap_content"
         android:layout_gravity="start"
         android:textAlignment="viewStart"
-        android:text="Title"
         android:maxLines="2"
         android:hyphenationFrequency="normalFast"
         android:lineBreakWordStyle="phrase"
@@ -47,7 +46,6 @@
         android:textAlignment="viewStart"
         android:textColor="?android:attr/textColorSecondary"
         android:maxLines="10"
-        android:text="Summary summary summary"
         android:hyphenationFrequency="normalFast"
         android:lineBreakWordStyle="phrase"
         style="@style/PreferenceSummaryTextStyle"/>
diff --git a/packages/SettingsLib/SettingsTheme/res/layout-v35/settingslib_expressive_collapsable_textview.xml b/packages/SettingsLib/SettingsTheme/res/layout-v35/settingslib_expressive_collapsable_textview.xml
index 4cc3c89..ea7baa4 100644
--- a/packages/SettingsLib/SettingsTheme/res/layout-v35/settingslib_expressive_collapsable_textview.xml
+++ b/packages/SettingsLib/SettingsTheme/res/layout-v35/settingslib_expressive_collapsable_textview.xml
@@ -25,6 +25,7 @@
     android:orientation="vertical"
     android:animateLayoutChanges="true"
     android:background="?android:attr/selectableItemBackground"
+    android:filterTouchesWhenObscured="false"
     android:clipToPadding="false">
 
     <TextView
diff --git a/packages/SettingsLib/SettingsTheme/res/layout-v35/settingslib_expressive_preference.xml b/packages/SettingsLib/SettingsTheme/res/layout-v35/settingslib_expressive_preference.xml
index 2475dfd..511e2bb 100644
--- a/packages/SettingsLib/SettingsTheme/res/layout-v35/settingslib_expressive_preference.xml
+++ b/packages/SettingsLib/SettingsTheme/res/layout-v35/settingslib_expressive_preference.xml
@@ -25,7 +25,8 @@
     android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
     android:background="?android:attr/selectableItemBackground"
     android:clipToPadding="false"
-    android:baselineAligned="false">
+    android:baselineAligned="false"
+    android:filterTouchesWhenObscured="false">
 
     <include layout="@layout/settingslib_expressive_preference_icon_frame"/>
 
diff --git a/packages/SettingsLib/SettingsTheme/res/layout-v35/settingslib_expressive_preference_icon_frame.xml b/packages/SettingsLib/SettingsTheme/res/layout-v35/settingslib_expressive_preference_icon_frame.xml
index f5017a5..ccdf37d 100644
--- a/packages/SettingsLib/SettingsTheme/res/layout-v35/settingslib_expressive_preference_icon_frame.xml
+++ b/packages/SettingsLib/SettingsTheme/res/layout-v35/settingslib_expressive_preference_icon_frame.xml
@@ -22,7 +22,8 @@
     android:minWidth="@dimen/settingslib_expressive_space_medium3"
     android:minHeight="@dimen/settingslib_expressive_space_medium3"
     android:gravity="center"
-    android:layout_marginEnd="-8dp">
+    android:layout_marginEnd="-8dp"
+    android:filterTouchesWhenObscured="false">
 
     <androidx.preference.internal.PreferenceImageView
         android:id="@android:id/icon"
diff --git a/packages/SettingsLib/SettingsTheme/res/layout-v35/settingslib_expressive_preference_switch.xml b/packages/SettingsLib/SettingsTheme/res/layout-v35/settingslib_expressive_preference_switch.xml
index 4cbdfd5..4abcd22 100644
--- a/packages/SettingsLib/SettingsTheme/res/layout-v35/settingslib_expressive_preference_switch.xml
+++ b/packages/SettingsLib/SettingsTheme/res/layout-v35/settingslib_expressive_preference_switch.xml
@@ -19,4 +19,5 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:theme="@style/Theme.Material3.DynamicColors.DayNight"
     android:id="@+id/switchWidget"
+    android:filterTouchesWhenObscured="false"
     style="@style/SettingslibSwitchStyle.Expressive"/>
\ No newline at end of file
diff --git a/packages/SettingsLib/SettingsTheme/res/layout-v35/settingslib_expressive_preference_text_frame.xml b/packages/SettingsLib/SettingsTheme/res/layout-v35/settingslib_expressive_preference_text_frame.xml
index e3e689b..cc42dab 100644
--- a/packages/SettingsLib/SettingsTheme/res/layout-v35/settingslib_expressive_preference_text_frame.xml
+++ b/packages/SettingsLib/SettingsTheme/res/layout-v35/settingslib_expressive_preference_text_frame.xml
@@ -20,7 +20,8 @@
     android:layout_width="@dimen/settingslib_expressive_space_none"
     android:layout_height="wrap_content"
     android:layout_weight="1"
-    android:padding="@dimen/settingslib_expressive_space_small1">
+    android:paddingVertical="@dimen/settingslib_expressive_space_small1"
+    android:filterTouchesWhenObscured="false">
 
     <TextView
         android:id="@android:id/title"
@@ -28,8 +29,10 @@
         android:layout_height="wrap_content"
         android:layout_gravity="start"
         android:textAlignment="viewStart"
-        android:textAppearance="?android:attr/textAppearanceListItem"
         android:maxLines="2"
+        android:hyphenationFrequency="normalFast"
+        android:lineBreakWordStyle="phrase"
+        android:textAppearance="?android:attr/textAppearanceListItem"
         android:ellipsize="marquee"/>
 
     <TextView
@@ -43,5 +46,7 @@
         android:textAlignment="viewStart"
         android:textAppearance="?android:attr/textAppearanceListItemSecondary"
         android:textColor="?android:attr/textColorSecondary"
-        android:maxLines="10"/>
-</RelativeLayout>
+        android:maxLines="10"
+        android:hyphenationFrequency="normalFast"
+        android:lineBreakWordStyle="phrase"/>
+</RelativeLayout>
\ No newline at end of file
diff --git a/packages/SettingsLib/SettingsTheme/res/layout-v35/settingslib_expressive_two_target_divider.xml b/packages/SettingsLib/SettingsTheme/res/layout-v35/settingslib_expressive_two_target_divider.xml
index 3f75181..9be9ec3 100644
--- a/packages/SettingsLib/SettingsTheme/res/layout-v35/settingslib_expressive_two_target_divider.xml
+++ b/packages/SettingsLib/SettingsTheme/res/layout-v35/settingslib_expressive_two_target_divider.xml
@@ -1,18 +1,18 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-  ~ Copyright (C) 2024 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
+    Copyright (C) 2024 The Android Open Source Project
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
   -->
 
 <LinearLayout
@@ -24,7 +24,8 @@
     android:orientation="horizontal"
     android:paddingStart="?android:attr/listPreferredItemPaddingEnd"
     android:paddingLeft="?android:attr/listPreferredItemPaddingEnd"
-    android:paddingVertical="@dimen/settingslib_expressive_space_extrasmall7">
+    android:paddingVertical="@dimen/settingslib_expressive_space_extrasmall7"
+    android:filterTouchesWhenObscured="false">
 
     <ImageView
         android:layout_width="wrap_content"
diff --git a/packages/SettingsLib/SettingsTheme/res/layout-v35/settingslib_preference_category_no_title.xml b/packages/SettingsLib/SettingsTheme/res/layout-v35/settingslib_preference_category_no_title.xml
index 7f466f6..f69fcd2 100644
--- a/packages/SettingsLib/SettingsTheme/res/layout-v35/settingslib_preference_category_no_title.xml
+++ b/packages/SettingsLib/SettingsTheme/res/layout-v35/settingslib_preference_category_no_title.xml
@@ -18,5 +18,6 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
-    android:baselineAligned="false">
+    android:baselineAligned="false"
+    android:filterTouchesWhenObscured="false">
 </LinearLayout>
diff --git a/packages/SettingsLib/SettingsTheme/res/values-night-v31/colors.xml b/packages/SettingsLib/SettingsTheme/res/values-night-v31/colors.xml
index 0a36a4f..313748d 100644
--- a/packages/SettingsLib/SettingsTheme/res/values-night-v31/colors.xml
+++ b/packages/SettingsLib/SettingsTheme/res/values-night-v31/colors.xml
@@ -56,4 +56,6 @@
 
     <!--Deprecated. After sdk 35, don't use it-->
     <color name="settingslib_colorSurface">@color/settingslib_surface_dark</color>
+
+    <color name="settingslib_list_divider_color">@android:color/system_neutral1_700</color>
 </resources>
\ No newline at end of file
diff --git a/packages/SettingsLib/SettingsTheme/res/values-v31/colors.xml b/packages/SettingsLib/SettingsTheme/res/values-v31/colors.xml
index 7706e0e..b99ee51 100644
--- a/packages/SettingsLib/SettingsTheme/res/values-v31/colors.xml
+++ b/packages/SettingsLib/SettingsTheme/res/values-v31/colors.xml
@@ -90,4 +90,6 @@
 
     <color name="settingslib_spinner_title_color">@android:color/system_neutral1_900</color>
     <color name="settingslib_spinner_dropdown_color">@android:color/system_neutral2_700</color>
+
+    <color name="settingslib_list_divider_color">@android:color/system_neutral1_200</color>
 </resources>
diff --git a/packages/SettingsLib/SettingsTheme/res/values-v31/themes.xml b/packages/SettingsLib/SettingsTheme/res/values-v31/themes.xml
index 698f21d..3ccbbc0 100644
--- a/packages/SettingsLib/SettingsTheme/res/values-v31/themes.xml
+++ b/packages/SettingsLib/SettingsTheme/res/values-v31/themes.xml
@@ -27,6 +27,7 @@
         <item name="android:switchStyle">@style/Switch.SettingsLib</item>
         <item name="switchStyle">@style/SwitchCompat.SettingsLib</item>
         <item name="android:progressBarStyleHorizontal">@style/HorizontalProgressBar.SettingsLib</item>
+        <item name="android:listDivider">@drawable/settingslib_list_divider</item>
     </style>
 
     <style name="Theme.SettingsBase" parent="Theme.SettingsBase_v31" />
diff --git a/packages/SettingsLib/SettingsTheme/res/values-v35/strings.xml b/packages/SettingsLib/SettingsTheme/res/values/strings.xml
similarity index 94%
rename from packages/SettingsLib/SettingsTheme/res/values-v35/strings.xml
rename to packages/SettingsLib/SettingsTheme/res/values/strings.xml
index 2273406..c36dcb8 100644
--- a/packages/SettingsLib/SettingsTheme/res/values-v35/strings.xml
+++ b/packages/SettingsLib/SettingsTheme/res/values/strings.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-  Copyright (C) 2021 The Android Open Source Project
+  Copyright (C) 2024 The Android Open Source Project
 
   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
diff --git a/packages/SettingsLib/SettingsTheme/src/com/android/settingslib/widget/CollapsableTextView.kt b/packages/SettingsLib/SettingsTheme/src/com/android/settingslib/widget/CollapsableTextView.kt
index f1cc4e95..7eb9840 100644
--- a/packages/SettingsLib/SettingsTheme/src/com/android/settingslib/widget/CollapsableTextView.kt
+++ b/packages/SettingsLib/SettingsTheme/src/com/android/settingslib/widget/CollapsableTextView.kt
@@ -248,8 +248,6 @@
     val url: String = "",
     val clickListener: View.OnClickListener) : URLSpan(url) {
     override fun onClick(widget: View) {
-        if (clickListener != null) {
-            clickListener.onClick(widget)
-        }
+        clickListener.onClick(widget)
     }
 }
diff --git a/packages/SettingsLib/SettingsTheme/src/com/android/settingslib/widget/SettingsThemeHelper.kt b/packages/SettingsLib/SettingsTheme/src/com/android/settingslib/widget/SettingsThemeHelper.kt
index 10e5267..74f5441 100644
--- a/packages/SettingsLib/SettingsTheme/src/com/android/settingslib/widget/SettingsThemeHelper.kt
+++ b/packages/SettingsLib/SettingsTheme/src/com/android/settingslib/widget/SettingsThemeHelper.kt
@@ -18,7 +18,6 @@
 
 import android.content.Context
 import android.os.Build
-import android.os.SystemProperties
 
 object SettingsThemeHelper {
     private const val IS_EXPRESSIVE_DESIGN_ENABLED = "is_expressive_design_enabled"
@@ -50,8 +49,7 @@
         expressiveThemeState =
             if (
                 (Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM) &&
-                    (SystemProperties.getBoolean(IS_EXPRESSIVE_DESIGN_ENABLED, false) ||
-                        getPropBoolean(context, IS_EXPRESSIVE_DESIGN_ENABLED, false))
+                        getPropBoolean(context, IS_EXPRESSIVE_DESIGN_ENABLED, false)
             ) {
                 ExpressiveThemeState.ENABLED
             } else {
diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/GallerySpaEnvironment.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/GallerySpaEnvironment.kt
index 2a251a5..dfd296f 100644
--- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/GallerySpaEnvironment.kt
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/GallerySpaEnvironment.kt
@@ -39,6 +39,7 @@
 import com.android.settingslib.spa.gallery.page.ProgressBarPageProvider
 import com.android.settingslib.spa.gallery.scaffold.NonScrollablePagerPageProvider
 import com.android.settingslib.spa.gallery.page.SliderPageProvider
+import com.android.settingslib.spa.gallery.preference.CheckBoxPreferencePageProvider
 import com.android.settingslib.spa.gallery.preference.IntroPreferencePageProvider
 import com.android.settingslib.spa.gallery.preference.ListPreferencePageProvider
 import com.android.settingslib.spa.gallery.preference.MainSwitchPreferencePageProvider
@@ -46,6 +47,7 @@
 import com.android.settingslib.spa.gallery.preference.PreferencePageProvider
 import com.android.settingslib.spa.gallery.preference.SwitchPreferencePageProvider
 import com.android.settingslib.spa.gallery.preference.TopIntroPreferencePageProvider
+import com.android.settingslib.spa.gallery.preference.TwoTargetButtonPreferencePageProvider
 import com.android.settingslib.spa.gallery.preference.TwoTargetSwitchPreferencePageProvider
 import com.android.settingslib.spa.gallery.preference.ZeroStatePreferencePageProvider
 import com.android.settingslib.spa.gallery.scaffold.PagerMainPageProvider
@@ -105,6 +107,8 @@
                 CopyablePageProvider,
                 IntroPreferencePageProvider,
                 TopIntroPreferencePageProvider,
+                CheckBoxPreferencePageProvider,
+                TwoTargetButtonPreferencePageProvider,
             ),
             rootPages = listOf(
                 HomePageProvider.createSettingsPage(),
diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/dialog/DialogMainPageProvider.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/dialog/DialogMainPageProvider.kt
index c9c81aa..cb05504 100644
--- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/dialog/DialogMainPageProvider.kt
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/dialog/DialogMainPageProvider.kt
@@ -19,50 +19,93 @@
 import android.os.Bundle
 import androidx.compose.material3.Text
 import androidx.compose.runtime.Composable
-import com.android.settingslib.spa.framework.common.SettingsEntry
-import com.android.settingslib.spa.framework.common.SettingsEntryBuilder
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.saveable.rememberSaveable
+import androidx.compose.runtime.setValue
 import com.android.settingslib.spa.framework.common.SettingsPageProvider
-import com.android.settingslib.spa.framework.common.createSettingsPage
 import com.android.settingslib.spa.framework.compose.navigator
 import com.android.settingslib.spa.widget.dialog.AlertDialogButton
+import com.android.settingslib.spa.widget.dialog.SettingsAlertDialogWithIcon
 import com.android.settingslib.spa.widget.dialog.rememberAlertDialogPresenter
 import com.android.settingslib.spa.widget.preference.Preference
 import com.android.settingslib.spa.widget.preference.PreferenceModel
+import com.android.settingslib.spa.widget.scaffold.RegularScaffold
+import com.android.settingslib.spa.widget.ui.Category
 
 private const val TITLE = "Category: Dialog"
 
 object DialogMainPageProvider : SettingsPageProvider {
     override val name = "DialogMain"
-    private val owner = createSettingsPage()
 
-    override fun buildEntry(arguments: Bundle?): List<SettingsEntry> = listOf(
-        SettingsEntryBuilder.create("AlertDialog", owner).setUiLayoutFn {
-            val alertDialogPresenter = rememberAlertDialogPresenter(
-                confirmButton = AlertDialogButton("Ok"),
-                dismissButton = AlertDialogButton("Cancel"),
-                title = "Title",
-                text = { Text("Text") },
-            )
-            Preference(object : PreferenceModel {
-                override val title = "Show AlertDialog"
-                override val onClick = alertDialogPresenter::open
-            })
-        }.build(),
-        SettingsEntryBuilder.create("NavDialog", owner).setUiLayoutFn {
-            Preference(object : PreferenceModel {
-                override val title = "Navigate to Dialog"
-                override val onClick = navigator(route = NavDialogProvider.name)
-            })
-        }.build(),
-    )
+    @Composable
+    override fun Page(arguments: Bundle?) {
+        RegularScaffold(TITLE) {
+            Category {
+                AlertDialog()
+                AlertDialogWithIcon()
+                NavDialog()
+            }
+        }
+    }
 
     @Composable
     fun Entry() {
-        Preference(object : PreferenceModel {
-            override val title = TITLE
-            override val onClick = navigator(name)
-        })
+        Preference(
+            object : PreferenceModel {
+                override val title = TITLE
+                override val onClick = navigator(name)
+            }
+        )
     }
 
     override fun getTitle(arguments: Bundle?) = TITLE
 }
+
+@Composable
+private fun AlertDialog() {
+    val alertDialogPresenter =
+        rememberAlertDialogPresenter(
+            confirmButton = AlertDialogButton("Ok"),
+            dismissButton = AlertDialogButton("Cancel"),
+            title = "Title",
+            text = { Text("Text") },
+        )
+    Preference(
+        object : PreferenceModel {
+            override val title = "Show AlertDialog"
+            override val onClick = alertDialogPresenter::open
+        }
+    )
+}
+
+@Composable
+private fun AlertDialogWithIcon() {
+    var openDialog by rememberSaveable { mutableStateOf(false) }
+    val close = { openDialog = false }
+    val open = { openDialog = true }
+    if (openDialog) {
+        SettingsAlertDialogWithIcon(
+            title = "Title",
+            onDismissRequest = close,
+            confirmButton = AlertDialogButton("OK", onClick = close),
+            dismissButton = AlertDialogButton("Dismiss", onClick = close),
+        ) {}
+    }
+    Preference(
+        object : PreferenceModel {
+            override val title = "Show AlertDialogWithIcon"
+            override val onClick = open
+        }
+    )
+}
+
+@Composable
+private fun NavDialog() {
+    Preference(
+        object : PreferenceModel {
+            override val title = "Navigate to Dialog"
+            override val onClick = navigator(route = NavDialogProvider.name)
+        }
+    )
+}
diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/CheckBoxPreferencePageProvider.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/CheckBoxPreferencePageProvider.kt
new file mode 100644
index 0000000..c2b67cb
--- /dev/null
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/CheckBoxPreferencePageProvider.kt
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.spa.gallery.preference
+
+import android.os.Bundle
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.outlined.AirplanemodeActive
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.saveable.rememberSaveable
+import androidx.compose.runtime.setValue
+import com.android.settingslib.spa.framework.common.SettingsPageProvider
+import com.android.settingslib.spa.framework.compose.navigator
+import com.android.settingslib.spa.widget.preference.CheckboxPreference
+import com.android.settingslib.spa.widget.preference.CheckboxPreferenceModel
+import com.android.settingslib.spa.widget.preference.Preference
+import com.android.settingslib.spa.widget.preference.PreferenceModel
+import com.android.settingslib.spa.widget.scaffold.RegularScaffold
+import com.android.settingslib.spa.widget.ui.Category
+import com.android.settingslib.spa.widget.ui.SettingsIcon
+
+private const val TITLE = "Sample CheckBoxPreference"
+
+object CheckBoxPreferencePageProvider : SettingsPageProvider {
+    override val name = "CheckBoxPreference"
+
+    @Composable
+    override fun Page(arguments: Bundle?) {
+        RegularScaffold(TITLE) {
+            Category {
+                var checked1 by rememberSaveable { mutableStateOf(true) }
+                CheckboxPreference(
+                    object : CheckboxPreferenceModel {
+                        override val title = "Use Dark theme"
+                        override val checked = { checked1 }
+                        override val onCheckedChange = { newChecked: Boolean ->
+                            checked1 = newChecked
+                        }
+                    }
+                )
+                var checked2 by rememberSaveable { mutableStateOf(false) }
+                CheckboxPreference(
+                    object : CheckboxPreferenceModel {
+                        override val title = "Use Dark theme"
+                        override val summary = { "Summary" }
+                        override val checked = { checked2 }
+                        override val onCheckedChange = { newChecked: Boolean ->
+                            checked2 = newChecked
+                        }
+                    }
+                )
+                var checked3 by rememberSaveable { mutableStateOf(true) }
+                CheckboxPreference(
+                    object : CheckboxPreferenceModel {
+                        override val title = "Use Dark theme"
+                        override val summary = { "Summary" }
+                        override val checked = { checked3 }
+                        override val onCheckedChange = { newChecked: Boolean ->
+                            checked3 = newChecked
+                        }
+                        override val icon =
+                            @Composable {
+                                SettingsIcon(imageVector = Icons.Outlined.AirplanemodeActive)
+                            }
+                    }
+                )
+            }
+        }
+    }
+
+    @Composable
+    fun Entry() {
+        Preference(
+            object : PreferenceModel {
+                override val title = TITLE
+                override val onClick = navigator(name)
+            }
+        )
+    }
+
+    override fun getTitle(arguments: Bundle?): String {
+        return TITLE
+    }
+}
diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/PreferenceMainPageProvider.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/PreferenceMainPageProvider.kt
index 831b439..3cfb536 100644
--- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/PreferenceMainPageProvider.kt
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/PreferenceMainPageProvider.kt
@@ -36,11 +36,13 @@
             Category {
                 PreferencePageProvider.Entry()
                 ListPreferencePageProvider.Entry()
+                CheckBoxPreferencePageProvider.Entry()
             }
             Category {
                 SwitchPreferencePageProvider.Entry()
                 MainSwitchPreferencePageProvider.Entry()
                 TwoTargetSwitchPreferencePageProvider.Entry()
+                TwoTargetButtonPreferencePageProvider.Entry()
             }
             Category {
                 ZeroStatePreferencePageProvider.Entry()
diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/TwoTargetButtonPreferencePageProvider.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/TwoTargetButtonPreferencePageProvider.kt
new file mode 100644
index 0000000..c6e834a
--- /dev/null
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/TwoTargetButtonPreferencePageProvider.kt
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.spa.gallery.preference
+
+import android.os.Bundle
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.outlined.Add
+import androidx.compose.material.icons.outlined.Info
+import androidx.compose.runtime.Composable
+import com.android.settingslib.spa.framework.common.SettingsPageProvider
+import com.android.settingslib.spa.framework.compose.navigator
+import com.android.settingslib.spa.widget.preference.Preference
+import com.android.settingslib.spa.widget.preference.PreferenceModel
+import com.android.settingslib.spa.widget.preference.TwoTargetButtonPreference
+import com.android.settingslib.spa.widget.scaffold.RegularScaffold
+import com.android.settingslib.spa.widget.ui.Category
+
+private const val TITLE = "Sample TwoTargetButtonPreference"
+
+object TwoTargetButtonPreferencePageProvider : SettingsPageProvider {
+    override val name = "TwoTargetButtonPreference"
+
+    @Composable
+    override fun Page(arguments: Bundle?) {
+        RegularScaffold(TITLE) {
+            Category {
+                SampleTwoTargetButtonPreference()
+                SampleTwoTargetButtonPreferenceWithSummary()
+            }
+        }
+    }
+
+    @Composable
+    fun Entry() {
+        Preference(
+            object : PreferenceModel {
+                override val title = TITLE
+                override val onClick = navigator(name)
+            }
+        )
+    }
+}
+
+@Composable
+private fun SampleTwoTargetButtonPreference() {
+    TwoTargetButtonPreference(
+        title = "TwoTargetButton",
+        summary = { "" },
+        buttonIcon = Icons.Outlined.Info,
+        buttonIconDescription = "info",
+        onClick = {},
+        onButtonClick = {},
+    )
+}
+
+@Composable
+private fun SampleTwoTargetButtonPreferenceWithSummary() {
+    TwoTargetButtonPreference(
+        title = "TwoTargetButton",
+        summary = { "summary" },
+        buttonIcon = Icons.Outlined.Add,
+        buttonIconDescription = "info",
+        onClick = {},
+        onButtonClick = {},
+    )
+}
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsDimension.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsDimension.kt
index ab95162..3957483 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsDimension.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsDimension.kt
@@ -22,6 +22,7 @@
 object SettingsDimension {
     val paddingTiny = 2.dp
     val paddingExtraSmall = 4.dp
+    val paddingExtraSmall1 = 6.dp
     val paddingSmall = if (isSpaExpressiveEnabled) 8.dp else 4.dp
     val paddingExtraSmall5 = 10.dp
     val paddingExtraSmall6 = 12.dp
@@ -85,4 +86,9 @@
     val illustrationMaxHeight = 300.dp
     val illustrationPadding = paddingLarge
     val illustrationCornerRadius = 28.dp
+
+    val preferenceMinHeight = 72.dp
+
+    val spinnerOptionMinHeight = 48.dp
+    val spinnerIconSize = 20.dp
 }
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsShape.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsShape.kt
index c787715..86ba686 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsShape.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsShape.kt
@@ -24,7 +24,9 @@
 
     val CornerMedium = RoundedCornerShape(12.dp)
 
-    val categoryCorner = RoundedCornerShape(20.dp)
+    val CornerMedium2 = RoundedCornerShape(20.dp)
+
+    val CornerLarge = RoundedCornerShape(24.dp)
 
     val CornerExtraLarge = RoundedCornerShape(28.dp)
 }
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/dialog/SettingsAlertDialogWithIcon.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/dialog/SettingsAlertDialogWithIcon.kt
index 58a83fa..4cf270d 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/dialog/SettingsAlertDialogWithIcon.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/dialog/SettingsAlertDialogWithIcon.kt
@@ -17,7 +17,6 @@
 package com.android.settingslib.spa.widget.dialog
 
 import androidx.compose.foundation.layout.Column
-import androidx.compose.foundation.layout.fillMaxWidth
 import androidx.compose.foundation.layout.width
 import androidx.compose.foundation.rememberScrollState
 import androidx.compose.foundation.verticalScroll
@@ -26,12 +25,13 @@
 import androidx.compose.material3.AlertDialog
 import androidx.compose.material3.Button
 import androidx.compose.material3.Icon
+import androidx.compose.material3.MaterialTheme
 import androidx.compose.material3.OutlinedButton
 import androidx.compose.material3.Text
 import androidx.compose.runtime.Composable
 import androidx.compose.ui.Modifier
-import androidx.compose.ui.text.style.TextAlign
 import androidx.compose.ui.window.DialogProperties
+import com.android.settingslib.spa.framework.theme.isSpaExpressiveEnabled
 
 @Composable
 fun SettingsAlertDialogWithIcon(
@@ -57,7 +57,9 @@
             title?.let {
                 {
                     CenterRow {
-                        Text(it, modifier = Modifier.fillMaxWidth(), textAlign = TextAlign.Center)
+                        if (isSpaExpressiveEnabled)
+                            Text(it, style = MaterialTheme.typography.bodyLarge)
+                        else Text(it)
                     }
                 }
             },
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/BaseLayout.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/BaseLayout.kt
index c68ec78..acb96be 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/BaseLayout.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/BaseLayout.kt
@@ -22,6 +22,7 @@
 import androidx.compose.foundation.layout.Row
 import androidx.compose.foundation.layout.Spacer
 import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.heightIn
 import androidx.compose.foundation.layout.padding
 import androidx.compose.foundation.layout.size
 import androidx.compose.foundation.layout.width
@@ -35,6 +36,7 @@
 import androidx.compose.ui.tooling.preview.Preview
 import androidx.compose.ui.unit.Dp
 import androidx.compose.ui.unit.dp
+import androidx.compose.ui.unit.min
 import com.android.settingslib.spa.framework.theme.SettingsDimension
 import com.android.settingslib.spa.framework.theme.SettingsOpacity.alphaForEnabled
 import com.android.settingslib.spa.framework.theme.SettingsShape
@@ -62,7 +64,8 @@
                 .semantics(mergeDescendants = true) {}
                 .then(
                     if (isSpaExpressiveEnabled)
-                        Modifier.clip(SettingsShape.CornerExtraSmall)
+                        Modifier.heightIn(min = SettingsDimension.preferenceMinHeight)
+                            .clip(SettingsShape.CornerExtraSmall)
                             .background(MaterialTheme.colorScheme.surfaceBright)
                     else Modifier
                 )
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/MainSwitchPreference.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/MainSwitchPreference.kt
index b28e88e..e6a2366 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/MainSwitchPreference.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/MainSwitchPreference.kt
@@ -17,6 +17,7 @@
 package com.android.settingslib.spa.widget.preference
 
 import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.heightIn
 import androidx.compose.foundation.layout.padding
 import androidx.compose.foundation.shape.CircleShape
 import androidx.compose.material3.MaterialTheme
@@ -25,6 +26,7 @@
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.tooling.preview.Preview
 import androidx.compose.ui.unit.dp
+import androidx.compose.ui.unit.min
 import com.android.settingslib.spa.framework.theme.SettingsDimension
 import com.android.settingslib.spa.framework.theme.SettingsShape
 import com.android.settingslib.spa.framework.theme.SettingsTheme
@@ -35,13 +37,19 @@
 fun MainSwitchPreference(model: SwitchPreferenceModel) {
     EntryHighlight {
         Surface(
-            modifier = Modifier.padding(SettingsDimension.itemPaddingEnd),
-            color = when (model.checked()) {
-                true -> MaterialTheme.colorScheme.primaryContainer
-                else -> MaterialTheme.colorScheme.secondaryContainer
-            },
-            shape = if (isSpaExpressiveEnabled) CircleShape
-            else SettingsShape.CornerExtraLarge,
+            modifier =
+                Modifier.padding(SettingsDimension.itemPaddingEnd)
+                    .then(
+                        if (isSpaExpressiveEnabled)
+                            Modifier.heightIn(min = SettingsDimension.preferenceMinHeight)
+                        else Modifier
+                    ),
+            color =
+                when (model.checked()) {
+                    true -> MaterialTheme.colorScheme.primaryContainer
+                    else -> MaterialTheme.colorScheme.secondaryContainer
+                },
+            shape = if (isSpaExpressiveEnabled) CircleShape else SettingsShape.CornerExtraLarge,
         ) {
             InternalSwitchPreference(
                 title = model.title,
@@ -61,16 +69,20 @@
 private fun MainSwitchPreferencePreview() {
     SettingsTheme {
         Column {
-            MainSwitchPreference(object : SwitchPreferenceModel {
-                override val title = "Use Dark theme"
-                override val checked = { true }
-                override val onCheckedChange: (Boolean) -> Unit = {}
-            })
-            MainSwitchPreference(object : SwitchPreferenceModel {
-                override val title = "Use Dark theme"
-                override val checked = { false }
-                override val onCheckedChange: (Boolean) -> Unit = {}
-            })
+            MainSwitchPreference(
+                object : SwitchPreferenceModel {
+                    override val title = "Use Dark theme"
+                    override val checked = { true }
+                    override val onCheckedChange: (Boolean) -> Unit = {}
+                }
+            )
+            MainSwitchPreference(
+                object : SwitchPreferenceModel {
+                    override val title = "Use Dark theme"
+                    override val checked = { false }
+                    override val onCheckedChange: (Boolean) -> Unit = {}
+                }
+            )
         }
     }
 }
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/ZeroStatePreference.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/ZeroStatePreference.kt
index b771f36..5419223 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/ZeroStatePreference.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/ZeroStatePreference.kt
@@ -54,7 +54,7 @@
     val zeroStateShape = remember {
         RoundedPolygon.star(
             numVerticesPerRadius = 6,
-            innerRadius = 0.75f,
+            innerRadius = 0.8f,
             rounding = CornerRounding(0.3f)
         )
     }
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Category.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Category.kt
index 6c5581f..acbdec0 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Category.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Category.kt
@@ -85,7 +85,7 @@
                     }
                     .then(
                         if (isSpaExpressiveEnabled)
-                            Modifier.fillMaxWidth().clip(SettingsShape.categoryCorner)
+                            Modifier.fillMaxWidth().clip(SettingsShape.CornerMedium2)
                         else Modifier
                     ),
             verticalArrangement =
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Spinner.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Spinner.kt
index 6b2db90..a9d2ef6 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Spinner.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Spinner.kt
@@ -19,9 +19,14 @@
 import androidx.compose.foundation.background
 import androidx.compose.foundation.layout.Box
 import androidx.compose.foundation.layout.PaddingValues
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.heightIn
 import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.size
 import androidx.compose.foundation.selection.selectableGroup
 import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.outlined.Check
 import androidx.compose.material.icons.outlined.ExpandLess
 import androidx.compose.material.icons.outlined.ExpandMore
 import androidx.compose.material3.Button
@@ -38,20 +43,19 @@
 import androidx.compose.runtime.saveable.rememberSaveable
 import androidx.compose.runtime.setValue
 import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.clip
 import androidx.compose.ui.graphics.Color
-import androidx.compose.ui.tooling.preview.Preview
 import androidx.compose.ui.semantics.Role
 import androidx.compose.ui.semantics.role
 import androidx.compose.ui.semantics.semantics
+import androidx.compose.ui.tooling.preview.Preview
 import androidx.compose.ui.unit.dp
 import com.android.settingslib.spa.framework.theme.SettingsDimension
+import com.android.settingslib.spa.framework.theme.SettingsShape
 import com.android.settingslib.spa.framework.theme.SettingsTheme
 import com.android.settingslib.spa.framework.theme.isSpaExpressiveEnabled
 
-data class SpinnerOption(
-    val id: Int,
-    val text: String,
-)
+data class SpinnerOption(val id: Int, val text: String)
 
 @Composable
 fun Spinner(options: List<SpinnerOption>, selectedId: Int?, setId: (id: Int) -> Unit) {
@@ -62,51 +66,101 @@
     var expanded by rememberSaveable { mutableStateOf(false) }
 
     Box(
-        modifier = Modifier
-            .padding(
-                start = SettingsDimension.itemPaddingStart,
-                top = SettingsDimension.itemPaddingAround,
-                end = SettingsDimension.itemPaddingEnd,
-                bottom = SettingsDimension.itemPaddingAround,
-            )
-            .selectableGroup(),
-    ) {
-        val contentPadding = if (isSpaExpressiveEnabled) PaddingValues(
-            horizontal = SettingsDimension.spinnerHorizontalPadding,
-            vertical = SettingsDimension.spinnerVerticalPadding
-        ) else PaddingValues(horizontal = SettingsDimension.itemPaddingEnd)
-        Button(
-            modifier = Modifier.semantics { role = Role.DropdownList },
-            onClick = { expanded = true },
-            colors = ButtonDefaults.buttonColors(
-                containerColor = MaterialTheme.colorScheme.primaryContainer,
-                contentColor = MaterialTheme.colorScheme.onPrimaryContainer,
-            ),
-            contentPadding = contentPadding,
-        ) {
-            SpinnerText(options.find { it.id == selectedId })
-            ExpandIcon(expanded)
-        }
-        DropdownMenu(
-            expanded = expanded,
-            onDismissRequest = { expanded = false },
-            modifier = Modifier.background(MaterialTheme.colorScheme.secondaryContainer),
-        ) {
-            for (option in options) {
-                DropdownMenuItem(
-                    text = {
-                        SpinnerText(
-                            option = option,
-                            modifier = Modifier.padding(end = 24.dp),
-                            color = MaterialTheme.colorScheme.onSecondaryContainer,
-                        )
-                    },
-                    onClick = {
-                        expanded = false
-                        setId(option.id)
-                    },
-                    contentPadding = contentPadding,
+        modifier =
+            Modifier.padding(
+                    start = SettingsDimension.itemPaddingStart,
+                    top = SettingsDimension.itemPaddingAround,
+                    end = SettingsDimension.itemPaddingEnd,
+                    bottom = SettingsDimension.itemPaddingAround,
                 )
+                .selectableGroup()
+    ) {
+        if (isSpaExpressiveEnabled) {
+            Button(
+                modifier = Modifier.semantics { role = Role.DropdownList },
+                onClick = { expanded = true },
+                colors =
+                    ButtonDefaults.buttonColors(
+                        containerColor = MaterialTheme.colorScheme.secondaryContainer,
+                        contentColor = MaterialTheme.colorScheme.onSecondaryContainer,
+                    ),
+                contentPadding =
+                    PaddingValues(
+                        horizontal = SettingsDimension.spinnerHorizontalPadding,
+                        vertical = SettingsDimension.spinnerVerticalPadding,
+                    ),
+            ) {
+                SpinnerText(options.find { it.id == selectedId })
+                ExpandIcon(expanded)
+            }
+            DropdownMenu(
+                expanded = expanded,
+                onDismissRequest = { expanded = false },
+                shape = SettingsShape.CornerLarge,
+                modifier =
+                    Modifier.background(MaterialTheme.colorScheme.surfaceContainerLow)
+                        .padding(horizontal = SettingsDimension.paddingSmall),
+            ) {
+                for ((index, option) in options.withIndex()) {
+                    val selected = index + 1 == selectedId
+                    DropdownMenuItem(
+                        text = { SpinnerOptionText(option = option, selected) },
+                        onClick = {
+                            expanded = false
+                            setId(option.id)
+                        },
+                        contentPadding =
+                            PaddingValues(
+                                horizontal = SettingsDimension.paddingSmall,
+                                vertical = SettingsDimension.paddingExtraSmall1,
+                            ),
+                        modifier =
+                            Modifier.heightIn(min = SettingsDimension.spinnerOptionMinHeight)
+                                .then(
+                                    if (selected)
+                                        Modifier.clip(SettingsShape.CornerMedium2)
+                                            .background(MaterialTheme.colorScheme.primaryContainer)
+                                    else Modifier
+                                ),
+                    )
+                }
+            }
+        } else {
+            val contentPadding = PaddingValues(horizontal = SettingsDimension.itemPaddingEnd)
+            Button(
+                modifier = Modifier.semantics { role = Role.DropdownList },
+                onClick = { expanded = true },
+                colors =
+                    ButtonDefaults.buttonColors(
+                        containerColor = MaterialTheme.colorScheme.primaryContainer,
+                        contentColor = MaterialTheme.colorScheme.onPrimaryContainer,
+                    ),
+                contentPadding = contentPadding,
+            ) {
+                SpinnerText(options.find { it.id == selectedId })
+                ExpandIcon(expanded)
+            }
+            DropdownMenu(
+                expanded = expanded,
+                onDismissRequest = { expanded = false },
+                modifier = Modifier.background(MaterialTheme.colorScheme.secondaryContainer),
+            ) {
+                for (option in options) {
+                    DropdownMenuItem(
+                        text = {
+                            SpinnerText(
+                                option = option,
+                                modifier = Modifier.padding(end = 24.dp),
+                                color = MaterialTheme.colorScheme.onSecondaryContainer,
+                            )
+                        },
+                        onClick = {
+                            expanded = false
+                            setId(option.id)
+                        },
+                        contentPadding = contentPadding,
+                    )
+                }
             }
         }
     }
@@ -115,10 +169,11 @@
 @Composable
 internal fun ExpandIcon(expanded: Boolean) {
     Icon(
-        imageVector = when {
-            expanded -> Icons.Outlined.ExpandLess
-            else -> Icons.Outlined.ExpandMore
-        },
+        imageVector =
+            when {
+                expanded -> Icons.Outlined.ExpandLess
+                else -> Icons.Outlined.ExpandMore
+            },
         contentDescription = null,
     )
 }
@@ -131,18 +186,42 @@
 ) {
     Text(
         text = option?.text ?: "",
-        modifier = modifier
-            .padding(end = SettingsDimension.itemPaddingEnd)
-            .then(
-                if (!isSpaExpressiveEnabled)
-                    Modifier.padding(vertical = SettingsDimension.itemPaddingAround)
-                else Modifier
-            ),
+        modifier =
+            modifier
+                .padding(end = SettingsDimension.itemPaddingEnd)
+                .then(
+                    if (!isSpaExpressiveEnabled)
+                        Modifier.padding(vertical = SettingsDimension.itemPaddingAround)
+                    else Modifier
+                ),
         color = color,
         style = MaterialTheme.typography.labelLarge,
     )
 }
 
+@Composable
+private fun SpinnerOptionText(option: SpinnerOption?, selected: Boolean) {
+    Row {
+        if (selected) {
+            Icon(
+                imageVector = Icons.Outlined.Check,
+                modifier = Modifier.size(SettingsDimension.spinnerIconSize),
+                tint = MaterialTheme.colorScheme.onPrimaryContainer,
+                contentDescription = null,
+            )
+            Spacer(Modifier.padding(SettingsDimension.paddingSmall))
+        }
+        Text(
+            text = option?.text ?: "",
+            modifier = Modifier.padding(end = SettingsDimension.itemPaddingEnd),
+            color =
+                if (selected) MaterialTheme.colorScheme.onPrimaryContainer
+                else MaterialTheme.colorScheme.onSurface,
+            style = MaterialTheme.typography.labelLarge,
+        )
+    }
+}
+
 @Preview(showBackground = true)
 @Composable
 private fun SpinnerPreview() {
diff --git a/packages/SettingsLib/res/values-af/strings.xml b/packages/SettingsLib/res/values-af/strings.xml
index 0a507d1..6ee3bd1 100644
--- a/packages/SettingsLib/res/values-af/strings.xml
+++ b/packages/SettingsLib/res/values-af/strings.xml
@@ -585,7 +585,6 @@
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"Hierdie rekenaar (intern)"</string>
     <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
     <skip />
-    <string name="media_transfer_internal_mic" msgid="797333824290228595">"Mikrofoon (intern)"</string>
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Dokluidspreker"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Eksterne toestel"</string>
     <string name="media_transfer_default_device_name" msgid="4315604017399871828">"Gekoppelde toestel"</string>
@@ -688,9 +687,10 @@
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Jou toestel moet herselflaai om hierdie verandering toe te pas. Herselflaai nou of kanselleer."</string>
     <string name="media_transfer_wired_headphone_name" msgid="8698668536022665254">"Bedrade oorfoon"</string>
     <string name="media_transfer_headphone_name" msgid="1131962659136578852">"Oorfoon"</string>
-    <string name="media_transfer_usb_speaker_name" msgid="4736537022543593896">"USB-luidspreker"</string>
+    <string name="media_transfer_usb_audio_name" msgid="1789292056757821355">"USB-oudio"</string>
     <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"Mikrofoonsok"</string>
-    <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"USB-mikrofoon"</string>
+    <string name="media_transfer_usb_device_mic_name" msgid="7171789543226269822">"USB-mikrofoon"</string>
+    <string name="media_transfer_bt_device_mic_name" msgid="1870669402238687618">"BT-mikrofoon"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Aan"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Af"</string>
     <string name="carrier_network_change_mode" msgid="4257621815706644026">"Diensverskaffernetwerk verander tans"</string>
diff --git a/packages/SettingsLib/res/values-am/strings.xml b/packages/SettingsLib/res/values-am/strings.xml
index 66644cb..40c4288 100644
--- a/packages/SettingsLib/res/values-am/strings.xml
+++ b/packages/SettingsLib/res/values-am/strings.xml
@@ -585,7 +585,6 @@
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"ይህ ኮምፒውተር (ውስጣዊ)"</string>
     <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
     <skip />
-    <string name="media_transfer_internal_mic" msgid="797333824290228595">"ማይክሮፎን (ውስጣዊ)"</string>
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"የመትከያ ድምፅ ማውጫ"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"የውጭ መሣሪያ"</string>
     <string name="media_transfer_default_device_name" msgid="4315604017399871828">"የተገናኘ መሣሪያ"</string>
@@ -688,9 +687,10 @@
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"የእርስዎን መሣሪያ ይህ ለው ለማመልከት እንደገና መነሣት አለበት። አሁን እንደገና ያስነሡ ወይም ይተዉት።"</string>
     <string name="media_transfer_wired_headphone_name" msgid="8698668536022665254">"ባለገመድ የራስ ላይ ማዳመጫ"</string>
     <string name="media_transfer_headphone_name" msgid="1131962659136578852">"የጆሮ ማዳመጫ"</string>
-    <string name="media_transfer_usb_speaker_name" msgid="4736537022543593896">"USB ድምፅ ማውጫ"</string>
+    <string name="media_transfer_usb_audio_name" msgid="1789292056757821355">"USB ኦዲዮ"</string>
     <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"የማይክሮፎን መሰኪያ"</string>
-    <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"USB ማይክሮፎን"</string>
+    <string name="media_transfer_usb_device_mic_name" msgid="7171789543226269822">"USB ማይክሮፎን"</string>
+    <string name="media_transfer_bt_device_mic_name" msgid="1870669402238687618">"ብሉቱዝ ማይክሮፎን"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"አብራ"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"አጥፋ"</string>
     <string name="carrier_network_change_mode" msgid="4257621815706644026">"የአገልግሎት አቅራቢ አውታረ መረብን በመቀየር ላይ"</string>
diff --git a/packages/SettingsLib/res/values-ar/strings.xml b/packages/SettingsLib/res/values-ar/strings.xml
index e241c8a..b54b521 100644
--- a/packages/SettingsLib/res/values-ar/strings.xml
+++ b/packages/SettingsLib/res/values-ar/strings.xml
@@ -585,7 +585,6 @@
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"هذا الكمبيوتر (داخلي)"</string>
     <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
     <skip />
-    <string name="media_transfer_internal_mic" msgid="797333824290228595">"ميكروفون (داخلي)"</string>
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"مكبّر صوت بقاعدة إرساء"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"جهاز خارجي"</string>
     <string name="media_transfer_default_device_name" msgid="4315604017399871828">"جهاز متّصل"</string>
@@ -688,9 +687,10 @@
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"يجب إعادة تشغيل جهازك ليتم تطبيق هذا التغيير. يمكنك إعادة التشغيل الآن أو إلغاء التغيير."</string>
     <string name="media_transfer_wired_headphone_name" msgid="8698668536022665254">"سماعات رأس سلكية"</string>
     <string name="media_transfer_headphone_name" msgid="1131962659136578852">"سماعات رأس"</string>
-    <string name="media_transfer_usb_speaker_name" msgid="4736537022543593896">"‏مكبّر صوت USB"</string>
+    <string name="media_transfer_usb_audio_name" msgid="1789292056757821355">"‏مكبر صوت USB"</string>
     <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"مقبس الميكروفون"</string>
-    <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"‏ميكروفون بمنفذ USB"</string>
+    <string name="media_transfer_usb_device_mic_name" msgid="7171789543226269822">"‏ميكروفون USB"</string>
+    <string name="media_transfer_bt_device_mic_name" msgid="1870669402238687618">"ميكروفون يعمل بالبلوتوث"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"مفعّلة"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"إيقاف"</string>
     <string name="carrier_network_change_mode" msgid="4257621815706644026">"جارٍ تغيير شبكة مشغِّل شبكة الجوّال."</string>
diff --git a/packages/SettingsLib/res/values-as/strings.xml b/packages/SettingsLib/res/values-as/strings.xml
index 4e734b9..a72c5f6 100644
--- a/packages/SettingsLib/res/values-as/strings.xml
+++ b/packages/SettingsLib/res/values-as/strings.xml
@@ -585,7 +585,6 @@
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"এই কম্পিউটাৰ (অভ্যন্তৰীণ)"</string>
     <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
     <skip />
-    <string name="media_transfer_internal_mic" msgid="797333824290228595">"মাইক্ৰ’ফ’ন (অভ্যন্তৰীণ)"</string>
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"ড’ক স্পীকাৰ"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"বাহ্যিক ডিভাইচ"</string>
     <string name="media_transfer_default_device_name" msgid="4315604017399871828">"সংযোগ হৈ থকা ডিভাইচ"</string>
@@ -688,9 +687,10 @@
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"এই সলনিটো কার্যকৰী হ’বলৈ আপোনাৰ ডিভাইচটো ৰিবুট কৰিবই লাগিব। এতিয়াই ৰিবুট কৰক অথবা বাতিল কৰক।"</string>
     <string name="media_transfer_wired_headphone_name" msgid="8698668536022665254">"তাঁৰযুক্ত হেডফ’ন"</string>
     <string name="media_transfer_headphone_name" msgid="1131962659136578852">"হেডফ’ন"</string>
-    <string name="media_transfer_usb_speaker_name" msgid="4736537022543593896">"USB স্পীকাৰ"</string>
+    <string name="media_transfer_usb_audio_name" msgid="1789292056757821355">"ইউএছবি অডিঅ\'"</string>
     <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"মাইকৰ জেক"</string>
-    <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"ইউএছবি মাইক"</string>
+    <string name="media_transfer_usb_device_mic_name" msgid="7171789543226269822">"ইউএছবি মাইক্ৰ’ফ’ন"</string>
+    <string name="media_transfer_bt_device_mic_name" msgid="1870669402238687618">"ব্লুটুথ মাইক্ৰ’ফ’ন"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"অন"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"অফ"</string>
     <string name="carrier_network_change_mode" msgid="4257621815706644026">"বাহক নেটৱৰ্কৰ পৰিৱৰ্তন"</string>
diff --git a/packages/SettingsLib/res/values-az/strings.xml b/packages/SettingsLib/res/values-az/strings.xml
index 057d492..4cb9ef8 100644
--- a/packages/SettingsLib/res/values-az/strings.xml
+++ b/packages/SettingsLib/res/values-az/strings.xml
@@ -585,7 +585,6 @@
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"Bu kompüter (daxili)"</string>
     <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
     <skip />
-    <string name="media_transfer_internal_mic" msgid="797333824290228595">"Mikrofon (daxili)"</string>
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Dok dinamiki"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Xarici cihaz"</string>
     <string name="media_transfer_default_device_name" msgid="4315604017399871828">"Qoşulmuş cihaz"</string>
@@ -688,9 +687,10 @@
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Bu dəyişikliyin tətbiq edilməsi üçün cihaz yenidən başladılmalıdır. İndi yenidən başladın və ya ləğv edin."</string>
     <string name="media_transfer_wired_headphone_name" msgid="8698668536022665254">"Naqilli qulaqlıq"</string>
     <string name="media_transfer_headphone_name" msgid="1131962659136578852">"Qulaqlıq"</string>
-    <string name="media_transfer_usb_speaker_name" msgid="4736537022543593896">"USB spikeri"</string>
+    <string name="media_transfer_usb_audio_name" msgid="1789292056757821355">"USB audio"</string>
     <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"Mikrofon yuvası"</string>
-    <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"USB mikrofon"</string>
+    <string name="media_transfer_usb_device_mic_name" msgid="7171789543226269822">"USB mikrofon"</string>
+    <string name="media_transfer_bt_device_mic_name" msgid="1870669402238687618">"Bluetooth mikrofonu"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Aktiv"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Deaktiv"</string>
     <string name="carrier_network_change_mode" msgid="4257621815706644026">"Operator şəbəkəsinin dəyişilməsi"</string>
diff --git a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
index fdd969d..4328192 100644
--- a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
+++ b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
@@ -585,7 +585,6 @@
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"Ovaj računar (interno)"</string>
     <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
     <skip />
-    <string name="media_transfer_internal_mic" msgid="797333824290228595">"Mikrofon (interni)"</string>
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Zvučnik bazne stanice"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Spoljni uređaj"</string>
     <string name="media_transfer_default_device_name" msgid="4315604017399871828">"Povezani uređaj"</string>
@@ -688,9 +687,10 @@
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Morate da restartujete uređaj da bi se ova promena primenila. Restartujte ga odmah ili otkažite."</string>
     <string name="media_transfer_wired_headphone_name" msgid="8698668536022665254">"Žičane slušalice"</string>
     <string name="media_transfer_headphone_name" msgid="1131962659136578852">"Slušalice"</string>
-    <string name="media_transfer_usb_speaker_name" msgid="4736537022543593896">"USB zvučnik"</string>
+    <string name="media_transfer_usb_audio_name" msgid="1789292056757821355">"USB audio"</string>
     <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"Utikač za mikrofon"</string>
-    <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"USB mikrofon"</string>
+    <string name="media_transfer_usb_device_mic_name" msgid="7171789543226269822">"USB mikrofon"</string>
+    <string name="media_transfer_bt_device_mic_name" msgid="1870669402238687618">"Bluetooth mikrofon"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Uključeno"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Isključeno"</string>
     <string name="carrier_network_change_mode" msgid="4257621815706644026">"Promena mreže mobilnog operatera"</string>
diff --git a/packages/SettingsLib/res/values-be/strings.xml b/packages/SettingsLib/res/values-be/strings.xml
index a262901..40be0a0 100644
--- a/packages/SettingsLib/res/values-be/strings.xml
+++ b/packages/SettingsLib/res/values-be/strings.xml
@@ -585,7 +585,6 @@
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"Гэты камп’ютар (унутраны)"</string>
     <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
     <skip />
-    <string name="media_transfer_internal_mic" msgid="797333824290228595">"Мікрафон (унутраны)"</string>
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Дынамік док-станцыі"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Знешняя прылада"</string>
     <string name="media_transfer_default_device_name" msgid="4315604017399871828">"Падключаная прылада"</string>
@@ -688,9 +687,10 @@
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Перазагрузіце прыладу, каб прымяніць гэта змяненне. Перазагрузіце ці скасуйце."</string>
     <string name="media_transfer_wired_headphone_name" msgid="8698668536022665254">"Правадныя навушнікі"</string>
     <string name="media_transfer_headphone_name" msgid="1131962659136578852">"Навушнікі"</string>
-    <string name="media_transfer_usb_speaker_name" msgid="4736537022543593896">"USB-дынамік"</string>
+    <string name="media_transfer_usb_audio_name" msgid="1789292056757821355">"Аўдыяпрылада USB"</string>
     <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"Раздым для мікрафона"</string>
-    <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"Мікрафон USB"</string>
+    <string name="media_transfer_usb_device_mic_name" msgid="7171789543226269822">"Мікрафон USB"</string>
+    <string name="media_transfer_bt_device_mic_name" msgid="1870669402238687618">"Мікрафон з Bluetooth"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Уключана"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Выключана"</string>
     <string name="carrier_network_change_mode" msgid="4257621815706644026">"Змяненне аператара сеткі"</string>
diff --git a/packages/SettingsLib/res/values-bg/strings.xml b/packages/SettingsLib/res/values-bg/strings.xml
index 244a090..f43758d 100644
--- a/packages/SettingsLib/res/values-bg/strings.xml
+++ b/packages/SettingsLib/res/values-bg/strings.xml
@@ -288,7 +288,7 @@
     <string name="confirm_enable_oem_unlock_title" msgid="8249318129774367535">"Да се разреши ли отключване от OEM?"</string>
     <string name="confirm_enable_oem_unlock_text" msgid="854131050791011970">"ПРЕДУПРЕЖДЕНИЕ: Функциите за защита на устройството няма да работят, докато следната настройка е включена."</string>
     <string name="mock_location_app" msgid="6269380172542248304">"Избиране на приложение за мнимо местоположение"</string>
-    <string name="mock_location_app_not_set" msgid="6972032787262831155">"Няма зададено приложение за мнимо местоположение"</string>
+    <string name="mock_location_app_not_set" msgid="6972032787262831155">"Няма зададено приложение"</string>
     <string name="mock_location_app_set" msgid="4706722469342913843">"Приложение за мнимо местоположение: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="debug_networking_category" msgid="6829757985772659599">"Мрежи"</string>
     <string name="wifi_display_certification" msgid="1805579519992520381">"Безжичен дисплей"</string>
@@ -585,7 +585,6 @@
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"Този компютър (вграден)"</string>
     <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
     <skip />
-    <string name="media_transfer_internal_mic" msgid="797333824290228595">"Микрофон (вътрешен)"</string>
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Високоговорител докинг станция"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Външно устройство"</string>
     <string name="media_transfer_default_device_name" msgid="4315604017399871828">"Свързано устройство"</string>
@@ -688,9 +687,10 @@
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"За да бъде приложена тази промяна, устройството ви трябва да бъде рестартирано. Рестартирайте сега или анулирайте."</string>
     <string name="media_transfer_wired_headphone_name" msgid="8698668536022665254">"Слушалки с кабел"</string>
     <string name="media_transfer_headphone_name" msgid="1131962659136578852">"Слушалки"</string>
-    <string name="media_transfer_usb_speaker_name" msgid="4736537022543593896">"Високоговорител с USB"</string>
+    <string name="media_transfer_usb_audio_name" msgid="1789292056757821355">"Аудиоустройство с USB"</string>
     <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"Жак за микрофон"</string>
-    <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"Микрофон с USB"</string>
+    <string name="media_transfer_usb_device_mic_name" msgid="7171789543226269822">"Микрофон с USB"</string>
+    <string name="media_transfer_bt_device_mic_name" msgid="1870669402238687618">"Микрофон с Bluetooth"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Включване"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Изключване"</string>
     <string name="carrier_network_change_mode" msgid="4257621815706644026">"Промяна на мрежата на оператора"</string>
diff --git a/packages/SettingsLib/res/values-bn/strings.xml b/packages/SettingsLib/res/values-bn/strings.xml
index 907cee1..acc8a2d 100644
--- a/packages/SettingsLib/res/values-bn/strings.xml
+++ b/packages/SettingsLib/res/values-bn/strings.xml
@@ -585,7 +585,6 @@
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"এই কম্পিউটার (ইন্টার্নাল)"</string>
     <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
     <skip />
-    <string name="media_transfer_internal_mic" msgid="797333824290228595">"মাইক্রোফোন (ইন্টার্নাল)"</string>
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"ডক স্পিকার"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"এক্সটার্নাল ডিভাইস"</string>
     <string name="media_transfer_default_device_name" msgid="4315604017399871828">"কানেক্ট থাকা ডিভাইস"</string>
@@ -688,9 +687,10 @@
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"এই পরিবর্তনটি প্রয়োগ করার জন্য আপনার ডিভাইসটি অবশ্যই রিবুট করতে হবে। এখনই রিবুট করুন বা বাতিল করুন।"</string>
     <string name="media_transfer_wired_headphone_name" msgid="8698668536022665254">"তারযুক্ত হেডফোন"</string>
     <string name="media_transfer_headphone_name" msgid="1131962659136578852">"হেডফোন"</string>
-    <string name="media_transfer_usb_speaker_name" msgid="4736537022543593896">"USB স্পিকার"</string>
+    <string name="media_transfer_usb_audio_name" msgid="1789292056757821355">"USB অডিও"</string>
     <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"মাইকের জ্যাক"</string>
-    <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"USB মাইক"</string>
+    <string name="media_transfer_usb_device_mic_name" msgid="7171789543226269822">"USB মাইক্রোফোন"</string>
+    <string name="media_transfer_bt_device_mic_name" msgid="1870669402238687618">"BT মাইক্রোফোন"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"চালু আছে"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"বন্ধ আছে"</string>
     <string name="carrier_network_change_mode" msgid="4257621815706644026">"পরিষেবা প্রদানকারীর নেটওয়ার্ক পরিবর্তন করা হচ্ছে"</string>
diff --git a/packages/SettingsLib/res/values-bs/strings.xml b/packages/SettingsLib/res/values-bs/strings.xml
index 6b09b51..99c0c9e 100644
--- a/packages/SettingsLib/res/values-bs/strings.xml
+++ b/packages/SettingsLib/res/values-bs/strings.xml
@@ -585,7 +585,6 @@
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"Ovaj računar (interno)"</string>
     <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
     <skip />
-    <string name="media_transfer_internal_mic" msgid="797333824290228595">"Mikrofon (interni)"</string>
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Zvučnik priključne stanice"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Vanjski uređaj"</string>
     <string name="media_transfer_default_device_name" msgid="4315604017399871828">"Povezani uređaj"</string>
@@ -688,9 +687,10 @@
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Morate ponovo pokrenuti uređaj da se ova promjena primijeni. Ponovo pokrenite odmah ili otkažite."</string>
     <string name="media_transfer_wired_headphone_name" msgid="8698668536022665254">"Žičane slušalice"</string>
     <string name="media_transfer_headphone_name" msgid="1131962659136578852">"Slušalice"</string>
-    <string name="media_transfer_usb_speaker_name" msgid="4736537022543593896">"USB zvučnik"</string>
+    <string name="media_transfer_usb_audio_name" msgid="1789292056757821355">"USB audio"</string>
     <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"Priključak za mikrofon"</string>
-    <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"USB mikrofon"</string>
+    <string name="media_transfer_usb_device_mic_name" msgid="7171789543226269822">"USB mikrofon"</string>
+    <string name="media_transfer_bt_device_mic_name" msgid="1870669402238687618">"BT mikrofon"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Uključi"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Isključi"</string>
     <string name="carrier_network_change_mode" msgid="4257621815706644026">"Promjena mreže mobilnog operatera"</string>
diff --git a/packages/SettingsLib/res/values-ca/strings.xml b/packages/SettingsLib/res/values-ca/strings.xml
index 3057729..c9a1411 100644
--- a/packages/SettingsLib/res/values-ca/strings.xml
+++ b/packages/SettingsLib/res/values-ca/strings.xml
@@ -288,7 +288,7 @@
     <string name="confirm_enable_oem_unlock_title" msgid="8249318129774367535">"Permetre el desbloqueig OEM?"</string>
     <string name="confirm_enable_oem_unlock_text" msgid="854131050791011970">"ADVERTIMENT: les funcions de protecció del dispositiu no funcionaran mentre aquesta opció estigui activada."</string>
     <string name="mock_location_app" msgid="6269380172542248304">"Selecciona una aplicació d\'ubicació simulada"</string>
-    <string name="mock_location_app_not_set" msgid="6972032787262831155">"No s\'ha definit cap aplicació d\'ubicació simulada"</string>
+    <string name="mock_location_app_not_set" msgid="6972032787262831155">"Cap aplicació d\'ubicació simulada definida"</string>
     <string name="mock_location_app_set" msgid="4706722469342913843">"Aplicació d\'ubicació simulada: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="debug_networking_category" msgid="6829757985772659599">"Xarxes"</string>
     <string name="wifi_display_certification" msgid="1805579519992520381">"Certificació de pantalla sense fil"</string>
@@ -585,7 +585,6 @@
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"Aquest ordinador (intern)"</string>
     <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
     <skip />
-    <string name="media_transfer_internal_mic" msgid="797333824290228595">"Micròfon (intern)"</string>
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Base d\'altaveu"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Dispositiu extern"</string>
     <string name="media_transfer_default_device_name" msgid="4315604017399871828">"Dispositiu connectat"</string>
@@ -688,9 +687,10 @@
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Has de reiniciar el teu dispositiu perquè s\'apliquin els canvis. Reinicia\'l ara o cancel·la."</string>
     <string name="media_transfer_wired_headphone_name" msgid="8698668536022665254">"Auriculars amb cable"</string>
     <string name="media_transfer_headphone_name" msgid="1131962659136578852">"Auriculars"</string>
-    <string name="media_transfer_usb_speaker_name" msgid="4736537022543593896">"Altaveu USB"</string>
+    <string name="media_transfer_usb_audio_name" msgid="1789292056757821355">"Àudio USB"</string>
     <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"Connector per al micròfon"</string>
-    <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"Micròfon USB"</string>
+    <string name="media_transfer_usb_device_mic_name" msgid="7171789543226269822">"Micròfon USB"</string>
+    <string name="media_transfer_bt_device_mic_name" msgid="1870669402238687618">"Micròfon Bluetooth"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Activa"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Desactivat"</string>
     <string name="carrier_network_change_mode" msgid="4257621815706644026">"S\'està canviant la xarxa de l\'operador de telefonia mòbil"</string>
diff --git a/packages/SettingsLib/res/values-cs/strings.xml b/packages/SettingsLib/res/values-cs/strings.xml
index d274e85..ee5fd5c 100644
--- a/packages/SettingsLib/res/values-cs/strings.xml
+++ b/packages/SettingsLib/res/values-cs/strings.xml
@@ -585,7 +585,6 @@
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"Tento počítač (interní)"</string>
     <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
     <skip />
-    <string name="media_transfer_internal_mic" msgid="797333824290228595">"Mikrofon (interní)"</string>
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Reproduktor doku"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Externí zařízení"</string>
     <string name="media_transfer_default_device_name" msgid="4315604017399871828">"Připojené zařízení"</string>
@@ -688,9 +687,10 @@
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Aby se tato změna projevila, je třeba zařízení restartovat. Restartujte zařízení nebo zrušte akci."</string>
     <string name="media_transfer_wired_headphone_name" msgid="8698668536022665254">"Kabelová sluchátka"</string>
     <string name="media_transfer_headphone_name" msgid="1131962659136578852">"Sluchátka"</string>
-    <string name="media_transfer_usb_speaker_name" msgid="4736537022543593896">"USB reproduktor"</string>
+    <string name="media_transfer_usb_audio_name" msgid="1789292056757821355">"Zvuk USB"</string>
     <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"Konektor mikrofonu"</string>
-    <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"USB mikrofon"</string>
+    <string name="media_transfer_usb_device_mic_name" msgid="7171789543226269822">"Mikrofon USB"</string>
+    <string name="media_transfer_bt_device_mic_name" msgid="1870669402238687618">"Mikrofon Bluetooth"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Zapnout"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Vypnout"</string>
     <string name="carrier_network_change_mode" msgid="4257621815706644026">"Probíhá změna sítě operátora"</string>
diff --git a/packages/SettingsLib/res/values-da/strings.xml b/packages/SettingsLib/res/values-da/strings.xml
index ef37c65..a7308f1 100644
--- a/packages/SettingsLib/res/values-da/strings.xml
+++ b/packages/SettingsLib/res/values-da/strings.xml
@@ -585,7 +585,6 @@
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"Denne computer (intern)"</string>
     <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
     <skip />
-    <string name="media_transfer_internal_mic" msgid="797333824290228595">"Mikrofon (indbygget)"</string>
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Dockhøjttaler"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Ekstern enhed"</string>
     <string name="media_transfer_default_device_name" msgid="4315604017399871828">"Forbundet enhed"</string>
@@ -688,9 +687,10 @@
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Din enhed skal genstartes for at anvende denne ændring. Genstart nu, eller annuller."</string>
     <string name="media_transfer_wired_headphone_name" msgid="8698668536022665254">"Høretelefoner med ledning"</string>
     <string name="media_transfer_headphone_name" msgid="1131962659136578852">"Høretelefoner"</string>
-    <string name="media_transfer_usb_speaker_name" msgid="4736537022543593896">"USB-højttaler"</string>
+    <string name="media_transfer_usb_audio_name" msgid="1789292056757821355">"USB-lydenhed"</string>
     <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"Stik til mikrofon"</string>
-    <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"USB-mikrofon"</string>
+    <string name="media_transfer_usb_device_mic_name" msgid="7171789543226269822">"USB-mikrofon"</string>
+    <string name="media_transfer_bt_device_mic_name" msgid="1870669402238687618">"BT-mikrofon"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Til"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Fra"</string>
     <string name="carrier_network_change_mode" msgid="4257621815706644026">"Skift af mobilnetværk"</string>
diff --git a/packages/SettingsLib/res/values-de/strings.xml b/packages/SettingsLib/res/values-de/strings.xml
index 44f7329..972bb1f 100644
--- a/packages/SettingsLib/res/values-de/strings.xml
+++ b/packages/SettingsLib/res/values-de/strings.xml
@@ -585,7 +585,6 @@
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"Dieser Computer (intern)"</string>
     <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
     <skip />
-    <string name="media_transfer_internal_mic" msgid="797333824290228595">"Mikrofon (intern)"</string>
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Dock-Lautsprecher"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Externes Gerät"</string>
     <string name="media_transfer_default_device_name" msgid="4315604017399871828">"Verbundenes Gerät"</string>
@@ -688,9 +687,11 @@
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Damit diese Änderung übernommen wird, musst du dein Gerät neu starten. Du kannst es jetzt neu starten oder den Vorgang abbrechen."</string>
     <string name="media_transfer_wired_headphone_name" msgid="8698668536022665254">"Kabelgebundene Kopfhörer"</string>
     <string name="media_transfer_headphone_name" msgid="1131962659136578852">"Kopfhörer"</string>
-    <string name="media_transfer_usb_speaker_name" msgid="4736537022543593896">"USB-Lautsprecher"</string>
+    <string name="media_transfer_usb_audio_name" msgid="1789292056757821355">"USB-Audio"</string>
     <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"Mikrofonanschluss"</string>
-    <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"USB‑Mikrofon"</string>
+    <string name="media_transfer_usb_device_mic_name" msgid="7171789543226269822">"USB-Mikrofon"</string>
+    <!-- no translation found for media_transfer_bt_device_mic_name (1870669402238687618) -->
+    <skip />
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"An"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Aus"</string>
     <string name="carrier_network_change_mode" msgid="4257621815706644026">"Mobilfunknetzwerk wird gewechselt"</string>
diff --git a/packages/SettingsLib/res/values-el/strings.xml b/packages/SettingsLib/res/values-el/strings.xml
index 9cfceb5..2d0f37b 100644
--- a/packages/SettingsLib/res/values-el/strings.xml
+++ b/packages/SettingsLib/res/values-el/strings.xml
@@ -585,7 +585,6 @@
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"Αυτός ο υπολογιστής (εσωτερ.)"</string>
     <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
     <skip />
-    <string name="media_transfer_internal_mic" msgid="797333824290228595">"Μικρόφωνο (εσωτερικό)"</string>
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Ηχείο βάσης σύνδεσης"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Εξωτερική συσκευή"</string>
     <string name="media_transfer_default_device_name" msgid="4315604017399871828">"Συνδεδεμένη συσκευή"</string>
@@ -688,9 +687,10 @@
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Για να εφαρμοστεί αυτή η αλλαγή, θα πρέπει να επανεκκινήσετε τη συσκευή σας. Επανεκκίνηση τώρα ή ακύρωση."</string>
     <string name="media_transfer_wired_headphone_name" msgid="8698668536022665254">"Ενσύρματα ακουστικά"</string>
     <string name="media_transfer_headphone_name" msgid="1131962659136578852">"Ακουστικά"</string>
-    <string name="media_transfer_usb_speaker_name" msgid="4736537022543593896">"Ηχείο USB"</string>
+    <string name="media_transfer_usb_audio_name" msgid="1789292056757821355">"Ήχος USB"</string>
     <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"Υποδοχή μικροφώνου"</string>
-    <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"Μικρόφωνο USB"</string>
+    <string name="media_transfer_usb_device_mic_name" msgid="7171789543226269822">"Μικρόφωνο USB"</string>
+    <string name="media_transfer_bt_device_mic_name" msgid="1870669402238687618">"Μικρόφωνο BT"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Ενεργό"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Ανενεργό"</string>
     <string name="carrier_network_change_mode" msgid="4257621815706644026">"Αλλαγή δικτύου εταιρείας κινητής τηλεφωνίας"</string>
diff --git a/packages/SettingsLib/res/values-en-rAU/strings.xml b/packages/SettingsLib/res/values-en-rAU/strings.xml
index d4e01de..96c844d 100644
--- a/packages/SettingsLib/res/values-en-rAU/strings.xml
+++ b/packages/SettingsLib/res/values-en-rAU/strings.xml
@@ -585,7 +585,6 @@
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"This computer (internal)"</string>
     <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
     <skip />
-    <string name="media_transfer_internal_mic" msgid="797333824290228595">"Microphone (internal)"</string>
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Dock speaker"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"External device"</string>
     <string name="media_transfer_default_device_name" msgid="4315604017399871828">"Connected device"</string>
@@ -688,9 +687,10 @@
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Your device must be rebooted for this change to apply. Reboot now or cancel."</string>
     <string name="media_transfer_wired_headphone_name" msgid="8698668536022665254">"Wired headphones"</string>
     <string name="media_transfer_headphone_name" msgid="1131962659136578852">"Headphone"</string>
-    <string name="media_transfer_usb_speaker_name" msgid="4736537022543593896">"USB speaker"</string>
+    <string name="media_transfer_usb_audio_name" msgid="1789292056757821355">"USB audio"</string>
     <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"Mic jack"</string>
-    <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"USB mic"</string>
+    <string name="media_transfer_usb_device_mic_name" msgid="7171789543226269822">"USB microphone"</string>
+    <string name="media_transfer_bt_device_mic_name" msgid="1870669402238687618">"BT microphone"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"On"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Off"</string>
     <string name="carrier_network_change_mode" msgid="4257621815706644026">"Operator network changing"</string>
diff --git a/packages/SettingsLib/res/values-en-rCA/strings.xml b/packages/SettingsLib/res/values-en-rCA/strings.xml
index 602a0ed..c07bd34 100644
--- a/packages/SettingsLib/res/values-en-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-en-rCA/strings.xml
@@ -585,7 +585,6 @@
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"This computer (internal)"</string>
     <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
     <skip />
-    <string name="media_transfer_internal_mic" msgid="797333824290228595">"Microphone (internal)"</string>
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Dock speaker"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"External Device"</string>
     <string name="media_transfer_default_device_name" msgid="4315604017399871828">"Connected device"</string>
@@ -688,9 +687,10 @@
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Your device must be rebooted for this change to apply. Reboot now or cancel."</string>
     <string name="media_transfer_wired_headphone_name" msgid="8698668536022665254">"Wired headphone"</string>
     <string name="media_transfer_headphone_name" msgid="1131962659136578852">"Headphone"</string>
-    <string name="media_transfer_usb_speaker_name" msgid="4736537022543593896">"USB speaker"</string>
+    <string name="media_transfer_usb_audio_name" msgid="1789292056757821355">"USB audio"</string>
     <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"Mic jack"</string>
-    <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"USB mic"</string>
+    <string name="media_transfer_usb_device_mic_name" msgid="7171789543226269822">"USB microphone"</string>
+    <string name="media_transfer_bt_device_mic_name" msgid="1870669402238687618">"BT microphone"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"On"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Off"</string>
     <string name="carrier_network_change_mode" msgid="4257621815706644026">"Carrier network changing"</string>
diff --git a/packages/SettingsLib/res/values-en-rGB/strings.xml b/packages/SettingsLib/res/values-en-rGB/strings.xml
index 2fd84f3..96c844d 100644
--- a/packages/SettingsLib/res/values-en-rGB/strings.xml
+++ b/packages/SettingsLib/res/values-en-rGB/strings.xml
@@ -687,11 +687,10 @@
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Your device must be rebooted for this change to apply. Reboot now or cancel."</string>
     <string name="media_transfer_wired_headphone_name" msgid="8698668536022665254">"Wired headphones"</string>
     <string name="media_transfer_headphone_name" msgid="1131962659136578852">"Headphone"</string>
-    <!-- no translation found for media_transfer_usb_audio_name (1789292056757821355) -->
-    <skip />
+    <string name="media_transfer_usb_audio_name" msgid="1789292056757821355">"USB audio"</string>
     <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"Mic jack"</string>
-    <!-- no translation found for media_transfer_usb_device_mic_name (7171789543226269822) -->
-    <skip />
+    <string name="media_transfer_usb_device_mic_name" msgid="7171789543226269822">"USB microphone"</string>
+    <string name="media_transfer_bt_device_mic_name" msgid="1870669402238687618">"BT microphone"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"On"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Off"</string>
     <string name="carrier_network_change_mode" msgid="4257621815706644026">"Operator network changing"</string>
diff --git a/packages/SettingsLib/res/values-en-rIN/strings.xml b/packages/SettingsLib/res/values-en-rIN/strings.xml
index d4e01de..96c844d 100644
--- a/packages/SettingsLib/res/values-en-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-en-rIN/strings.xml
@@ -585,7 +585,6 @@
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"This computer (internal)"</string>
     <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
     <skip />
-    <string name="media_transfer_internal_mic" msgid="797333824290228595">"Microphone (internal)"</string>
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Dock speaker"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"External device"</string>
     <string name="media_transfer_default_device_name" msgid="4315604017399871828">"Connected device"</string>
@@ -688,9 +687,10 @@
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Your device must be rebooted for this change to apply. Reboot now or cancel."</string>
     <string name="media_transfer_wired_headphone_name" msgid="8698668536022665254">"Wired headphones"</string>
     <string name="media_transfer_headphone_name" msgid="1131962659136578852">"Headphone"</string>
-    <string name="media_transfer_usb_speaker_name" msgid="4736537022543593896">"USB speaker"</string>
+    <string name="media_transfer_usb_audio_name" msgid="1789292056757821355">"USB audio"</string>
     <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"Mic jack"</string>
-    <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"USB mic"</string>
+    <string name="media_transfer_usb_device_mic_name" msgid="7171789543226269822">"USB microphone"</string>
+    <string name="media_transfer_bt_device_mic_name" msgid="1870669402238687618">"BT microphone"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"On"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Off"</string>
     <string name="carrier_network_change_mode" msgid="4257621815706644026">"Operator network changing"</string>
diff --git a/packages/SettingsLib/res/values-en-rXC/strings.xml b/packages/SettingsLib/res/values-en-rXC/strings.xml
index 0731b72..c85b12a 100644
--- a/packages/SettingsLib/res/values-en-rXC/strings.xml
+++ b/packages/SettingsLib/res/values-en-rXC/strings.xml
@@ -585,7 +585,6 @@
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‎‏‏‎‏‏‏‎‎‏‏‏‎‎‏‏‏‎‎‎‏‎‏‎‎‎‎‏‏‎‎‎‎‏‏‎‏‏‎‎‏‏‎‎‏‏‏‎‎‏‎‏‎‏‏‏‏‎‏‎‎‎This computer (internal)‎‏‎‎‏‎"</string>
     <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
     <skip />
-    <string name="media_transfer_internal_mic" msgid="797333824290228595">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‎‎‏‎‏‏‎‎‎‏‎‎‎‎‏‎‏‏‎‎‏‎‏‏‏‎‎‎‏‏‏‎‎‎‎‏‎‎‎‎‏‏‏‎‎‏‎‎‎‎‏‎‎‏‎‏‏‏‎‎‏‏‎Microphone (internal)‎‏‎‎‏‎"</string>
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‎‎‏‏‏‏‎‏‎‎‎‏‏‎‏‎‏‎‏‎‎‏‎‎‏‎‏‏‏‎‎‏‏‎‏‏‎‎‏‏‏‏‎‏‏‎‏‏‏‎‏‎‏‎‏‎‏‏‏‏‎‎Dock speaker‎‏‎‎‏‎"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‎‎‎‏‏‏‏‏‎‏‏‎‎‏‏‎‎‏‏‏‏‏‎‏‏‎‏‎‎‎‎‏‏‎‏‎‏‎‎‎‎‎‏‏‎‎‎‎‏‎‏‎‎‏‎‎‏‎‎‏‎‎External Device‎‏‎‎‏‎"</string>
     <string name="media_transfer_default_device_name" msgid="4315604017399871828">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‏‏‎‏‏‏‏‏‎‎‏‎‎‎‎‎‏‏‎‏‎‏‏‏‏‏‏‎‏‎‎‏‎‎‎‎‎‎‏‎‏‏‏‏‎‎‎‏‏‏‎‎‏‎‏‎‏‎‏‎‎‎Connected device‎‏‎‎‏‎"</string>
@@ -688,9 +687,10 @@
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‎‎‏‎‎‏‏‎‏‎‎‏‏‎‎‏‎‎‏‏‏‏‎‏‏‏‎‏‏‎‏‎‏‎‎‏‏‎‎‎‏‏‏‏‏‏‎‏‏‎‏‏‎‏‎‎‎‏‎‎‎‎‎Your device must be rebooted for this change to apply. Reboot now or cancel.‎‏‎‎‏‎"</string>
     <string name="media_transfer_wired_headphone_name" msgid="8698668536022665254">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‏‏‎‎‎‏‎‏‏‎‏‏‏‏‏‏‎‎‎‎‎‏‏‏‏‎‎‏‎‎‎‏‎‏‏‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‎‎‎‎‎‏‎‎‏‏‎‎Wired headphone‎‏‎‎‏‎"</string>
     <string name="media_transfer_headphone_name" msgid="1131962659136578852">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‎‎‏‏‏‏‏‎‏‏‎‏‎‏‏‎‎‎‏‎‏‎‎‎‎‎‏‎‏‎‏‎‎‎‎‏‎‎‏‏‎‏‎‏‏‏‏‎‏‎‎‏‎‏‎‎‏‎‎‏‎‎‎Headphone‎‏‎‎‏‎"</string>
-    <string name="media_transfer_usb_speaker_name" msgid="4736537022543593896">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‎‎‎‎‎‏‏‎‏‏‏‎‏‏‏‎‎‎‏‏‏‏‎‏‎‏‎‎‏‏‏‎‏‎‎‏‏‎‎‎‏‏‎‎‏‎‏‎‎‎‎‎‎‏‏‎‏‎‏‎‎‎‎USB speaker‎‏‎‎‏‎"</string>
+    <string name="media_transfer_usb_audio_name" msgid="1789292056757821355">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‎‏‏‏‎‎‎‏‏‎‏‎‏‎‎‏‏‎‏‎‏‏‏‏‎‏‎‎‏‎‏‎‏‎‎‎‎‏‎‎‏‏‏‏‎‏‎‎‏‎‏‏‏‏‏‏‎‏‎‏‎‏‏‎USB audio‎‏‎‎‏‎"</string>
     <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‎‎‏‏‎‏‏‏‎‏‏‏‎‏‎‏‏‎‏‏‏‎‏‎‏‎‎‎‏‏‎‏‏‎‎‎‎‎‏‎‎‏‏‎‎‏‏‎‎‎‏‎‏‏‏‎‎‎‏‎‏‎Mic jack‎‏‎‎‏‎"</string>
-    <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‎‎‏‎‎‏‎‎‏‎‎‎‏‎‏‏‎‏‏‏‎‎‏‏‎‎‎‏‎‎‏‏‎‎‎‎‏‏‏‎‏‏‎‎‎‎‏‎‏‎‎‎‏‎‎USB mic‎‏‎‎‏‎"</string>
+    <string name="media_transfer_usb_device_mic_name" msgid="7171789543226269822">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‎‎‎‏‏‏‎‎‎‎‏‏‏‎‏‎‏‎‎‎‎‏‎‎‏‎‏‏‏‎‏‏‏‏‏‏‏‏‏‎‏‏‏‎‎‏‏‏‎‎‎‎‎‎‏‏‏‏‏‏‎‎USB microphone‎‏‎‎‏‎"</string>
+    <string name="media_transfer_bt_device_mic_name" msgid="1870669402238687618">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‎‏‏‏‎‎‏‏‏‏‏‎‏‎‏‏‏‏‏‎‎‏‏‏‏‏‎‏‎‎‎‏‏‏‏‏‏‎‎‏‎‏‎‎‎‎‏‎‎‎‏‏‎‎‏‏‎‎‎‎‎‏‎‎BT microphone‎‏‎‎‏‎"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‏‎‎‎‏‎‎‏‎‎‎‏‏‎‎‏‎‏‏‏‏‎‏‎‎‎‎‏‎‏‎‎‎‎‎‎‎‏‎‏‎‎‏‏‎‎‏‎‏‎‏‏‎On‎‏‎‎‏‎"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‎‎‏‎‎‏‎‎‎‏‏‎‏‎‏‏‎‏‏‎‏‎‎‎‎‎‏‏‎‏‏‎‎‏‏‎‏‏‎‏‎‏‏‎‏‏‏‏‏‏‏‏‏‎‎‎‏‎‏‎‎‎Off‎‏‎‎‏‎"</string>
     <string name="carrier_network_change_mode" msgid="4257621815706644026">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‏‏‎‏‏‎‎‎‏‎‏‏‎‎‎‎‏‏‏‎‎‎‏‏‏‏‎‏‏‏‏‎‎‏‎‎‏‎‎‏‎‎‏‎‏‏‏‏‎‏‏‏‎‎‎‏‏‏‎‏‎‎Carrier network changing‎‏‎‎‏‎"</string>
diff --git a/packages/SettingsLib/res/values-es-rUS/strings.xml b/packages/SettingsLib/res/values-es-rUS/strings.xml
index d6222ac..ec88743 100644
--- a/packages/SettingsLib/res/values-es-rUS/strings.xml
+++ b/packages/SettingsLib/res/values-es-rUS/strings.xml
@@ -585,7 +585,6 @@
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"Esta computadora (interna)"</string>
     <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
     <skip />
-    <string name="media_transfer_internal_mic" msgid="797333824290228595">"Micrófono (interno)"</string>
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Bocina de la estación de carga"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Dispositivo externo"</string>
     <string name="media_transfer_default_device_name" msgid="4315604017399871828">"Dispositivo conectado"</string>
@@ -688,9 +687,10 @@
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Debes reiniciar el dispositivo para que se aplique el cambio. Reinícialo ahora o cancela la acción."</string>
     <string name="media_transfer_wired_headphone_name" msgid="8698668536022665254">"Auriculares con cable"</string>
     <string name="media_transfer_headphone_name" msgid="1131962659136578852">"Auriculares"</string>
-    <string name="media_transfer_usb_speaker_name" msgid="4736537022543593896">"Bocina USB"</string>
+    <string name="media_transfer_usb_audio_name" msgid="1789292056757821355">"Audio USB"</string>
     <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"Conector para micrófono"</string>
-    <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"Micrófono USB"</string>
+    <string name="media_transfer_usb_device_mic_name" msgid="7171789543226269822">"Micrófono USB"</string>
+    <string name="media_transfer_bt_device_mic_name" msgid="1870669402238687618">"Micrófono Bluetooth"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Activar"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Desactivar"</string>
     <string name="carrier_network_change_mode" msgid="4257621815706644026">"Cambio de proveedor de red"</string>
diff --git a/packages/SettingsLib/res/values-es/strings.xml b/packages/SettingsLib/res/values-es/strings.xml
index d88634e..6215e77 100644
--- a/packages/SettingsLib/res/values-es/strings.xml
+++ b/packages/SettingsLib/res/values-es/strings.xml
@@ -585,7 +585,6 @@
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"Este ordenador (interno)"</string>
     <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
     <skip />
-    <string name="media_transfer_internal_mic" msgid="797333824290228595">"Micrófono (interno)"</string>
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Altavoz de la base"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Dispositivo externo"</string>
     <string name="media_transfer_default_device_name" msgid="4315604017399871828">"Dispositivo conectado"</string>
@@ -688,9 +687,11 @@
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Es necesario reiniciar tu dispositivo para que se apliquen los cambios. Reinicia ahora o cancela la acción."</string>
     <string name="media_transfer_wired_headphone_name" msgid="8698668536022665254">"Auriculares con cable"</string>
     <string name="media_transfer_headphone_name" msgid="1131962659136578852">"Auriculares"</string>
-    <string name="media_transfer_usb_speaker_name" msgid="4736537022543593896">"Altavoz USB"</string>
+    <string name="media_transfer_usb_audio_name" msgid="1789292056757821355">"Audio USB"</string>
     <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"Conector jack para micrófono"</string>
-    <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"Micrófono USB"</string>
+    <string name="media_transfer_usb_device_mic_name" msgid="7171789543226269822">"Micrófono USB"</string>
+    <!-- no translation found for media_transfer_bt_device_mic_name (1870669402238687618) -->
+    <skip />
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Activado"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Desactivado"</string>
     <string name="carrier_network_change_mode" msgid="4257621815706644026">"Cambiando la red del operador"</string>
diff --git a/packages/SettingsLib/res/values-et/strings.xml b/packages/SettingsLib/res/values-et/strings.xml
index e3020be..77a0799 100644
--- a/packages/SettingsLib/res/values-et/strings.xml
+++ b/packages/SettingsLib/res/values-et/strings.xml
@@ -585,7 +585,6 @@
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"See arvuti (sisemine)"</string>
     <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
     <skip />
-    <string name="media_transfer_internal_mic" msgid="797333824290228595">"Mikrofon (sisemine)"</string>
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Doki kõlar"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Väline seade"</string>
     <string name="media_transfer_default_device_name" msgid="4315604017399871828">"Ühendatud seade"</string>
@@ -688,9 +687,10 @@
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Selle muudatuse rakendamiseks tuleb seade taaskäivitada. Taaskäivitage kohe või tühistage."</string>
     <string name="media_transfer_wired_headphone_name" msgid="8698668536022665254">"Juhtmega kõrvaklapid"</string>
     <string name="media_transfer_headphone_name" msgid="1131962659136578852">"Kõrvaklapid"</string>
-    <string name="media_transfer_usb_speaker_name" msgid="4736537022543593896">"USB kõlar"</string>
+    <string name="media_transfer_usb_audio_name" msgid="1789292056757821355">"USB-heli"</string>
     <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"Mikrofoni pistikupesa"</string>
-    <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"USB-mikrofon"</string>
+    <string name="media_transfer_usb_device_mic_name" msgid="7171789543226269822">"USB-mikrofon"</string>
+    <string name="media_transfer_bt_device_mic_name" msgid="1870669402238687618">"BT mikrofon"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Sees"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Väljas"</string>
     <string name="carrier_network_change_mode" msgid="4257621815706644026">"Operaatori võrku muudetakse"</string>
diff --git a/packages/SettingsLib/res/values-eu/strings.xml b/packages/SettingsLib/res/values-eu/strings.xml
index da47004..a490b7b 100644
--- a/packages/SettingsLib/res/values-eu/strings.xml
+++ b/packages/SettingsLib/res/values-eu/strings.xml
@@ -585,7 +585,6 @@
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"Ordenagailu hau (barnekoa)"</string>
     <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
     <skip />
-    <string name="media_transfer_internal_mic" msgid="797333824290228595">"Mikrofonoa (barnekoa)"</string>
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Oinarri bozgorailuduna"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Kanpoko gailua"</string>
     <string name="media_transfer_default_device_name" msgid="4315604017399871828">"Konektatutako gailua"</string>
@@ -688,9 +687,10 @@
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Aldaketa aplikatzeko, berrabiarazi egin behar da gailua. Berrabiaraz ezazu orain, edo utzi bertan behera."</string>
     <string name="media_transfer_wired_headphone_name" msgid="8698668536022665254">"Entzungailu kableduna"</string>
     <string name="media_transfer_headphone_name" msgid="1131962659136578852">"Entzungailua"</string>
-    <string name="media_transfer_usb_speaker_name" msgid="4736537022543593896">"USB bidezko bozgorailua"</string>
+    <string name="media_transfer_usb_audio_name" msgid="1789292056757821355">"USB bidezko audioa"</string>
     <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"Mikrofonoaren konektorea"</string>
-    <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"USB bidezko mikrofonoa"</string>
+    <string name="media_transfer_usb_device_mic_name" msgid="7171789543226269822">"USB bidezko mikrofonoa"</string>
+    <string name="media_transfer_bt_device_mic_name" msgid="1870669402238687618">"Bluetooth bidezko mikrofonoa"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Aktibatu"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Desaktibatu"</string>
     <string name="carrier_network_change_mode" msgid="4257621815706644026">"Operadorearen sarea aldatzen"</string>
diff --git a/packages/SettingsLib/res/values-fa/strings.xml b/packages/SettingsLib/res/values-fa/strings.xml
index 5996efb..305fcbe 100644
--- a/packages/SettingsLib/res/values-fa/strings.xml
+++ b/packages/SettingsLib/res/values-fa/strings.xml
@@ -397,7 +397,7 @@
     <string name="usb_audio_disable_routing_summary" msgid="8768242894849534699">"‏غیرفعال کردن مسیریابی خودکار به وسایل جانبی صوتی USB"</string>
     <string name="debug_layout" msgid="1659216803043339741">"نمایش محدوده‌های طرح‌بندی"</string>
     <string name="debug_layout_summary" msgid="8825829038287321978">"نمایش مرزها، حاشیه‌ها و ویژگی‌های دیگر کلیپ."</string>
-    <string name="force_rtl_layout_all_locales" msgid="8690762598501599796">"اجباری کردن چیدمان راست‌چین"</string>
+    <string name="force_rtl_layout_all_locales" msgid="8690762598501599796">"الزام جانمایی راست به چپ"</string>
     <string name="force_rtl_layout_all_locales_summary" msgid="6663016859517239880">"اجباری کردن چیدمان راست‌چین صفحه برای همه زبان‌ها"</string>
     <string name="transparent_navigation_bar" msgid="1933192171384678484">"نوار پیمایش شفاف"</string>
     <string name="transparent_navigation_bar_summary" msgid="5454359021817330722">"رنگ پس‌زمینه نوار پیمایش را به‌طور پیش‌فرض شفاف می‌کند"</string>
@@ -418,7 +418,7 @@
     <string name="verbose_vendor_logging_preference_summary_on" msgid="9017757242481762036">"به‌طور نامحدود فعال شد"</string>
     <string name="window_animation_scale_title" msgid="5236381298376812508">"مقیاس پویانمایی پنجره"</string>
     <string name="transition_animation_scale_title" msgid="1278477690695439337">"مقیاس پویانمایی انتقالی"</string>
-    <string name="animator_duration_scale_title" msgid="7082913931326085176">"مقیاس طول مدت انیماتور"</string>
+    <string name="animator_duration_scale_title" msgid="7082913931326085176">"مقیاس طول مدت مقیاس مدت پویانماساز"</string>
     <string name="overlay_display_devices_title" msgid="5411894622334469607">"شبیه‌سازی نمایشگر ثانویه"</string>
     <string name="debug_applications_category" msgid="5394089406638954196">"برنامه‌ها"</string>
     <string name="immediately_destroy_activities" msgid="1826287490705167403">"فعالیت‌ها نگه داشته نشوند"</string>
@@ -585,7 +585,6 @@
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"این رایانه (داخلی)"</string>
     <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
     <skip />
-    <string name="media_transfer_internal_mic" msgid="797333824290228595">"میکروفون (داخلی)"</string>
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"بلندگوی پایه اتصال"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"دستگاه خارجی"</string>
     <string name="media_transfer_default_device_name" msgid="4315604017399871828">"دستگاه متصل"</string>
@@ -688,9 +687,10 @@
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"برای اعمال این تغییر، دستگاه باید بازراه‌اندازی شود. یا اکنون بازراه‌اندازی کنید یا لغو کنید."</string>
     <string name="media_transfer_wired_headphone_name" msgid="8698668536022665254">"هدفون سیمی"</string>
     <string name="media_transfer_headphone_name" msgid="1131962659136578852">"هدفون"</string>
-    <string name="media_transfer_usb_speaker_name" msgid="4736537022543593896">"‏بلندگوی USB"</string>
+    <string name="media_transfer_usb_audio_name" msgid="1789292056757821355">"‏بلندگوی USB"</string>
     <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"فیش میکروفون"</string>
-    <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"‏میکروفون USB"</string>
+    <string name="media_transfer_usb_device_mic_name" msgid="7171789543226269822">"‏میکروفون USB"</string>
+    <string name="media_transfer_bt_device_mic_name" msgid="1870669402238687618">"میکروفون بلوتوث"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"روشن"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"خاموش"</string>
     <string name="carrier_network_change_mode" msgid="4257621815706644026">"تغییر شبکه شرکت مخابراتی"</string>
@@ -734,7 +734,7 @@
     <string name="back_navigation_animation" msgid="8105467568421689484">"پویانمایی‌های اشاره برگشت پیش‌گویانه"</string>
     <string name="back_navigation_animation_summary" msgid="741292224121599456">"پویانمایی‌های سیستم را برای اشاره برگشت پیش‌گویانه فعال کنید."</string>
     <string name="back_navigation_animation_dialog" msgid="8696966520944625596">"‏این تنظیم پویانمایی‌های سیستم را برای پویانمایی اشاره برگشت پیش‌بینانه فعال می‌کند. این تنظیم مستلزم تنظیم شدن enableOnBackInvokedCallback مربوط به هر برنامه روی صحیح در فایل مانیفست است."</string>
-    <string name="font_scale_percentage" msgid="2624057443622817886">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>٪"</string>
+    <string name="font_scale_percentage" msgid="2624057443622817886">"‎%%<xliff:g id="PERCENTAGE">%1$d</xliff:g>"</string>
     <string name="not_specified" msgid="5423502443185110328">"نامشخص"</string>
     <string name="neuter" msgid="2075249330106127310">"خنثی"</string>
     <string name="feminine" msgid="1529155595310784757">"مؤنث"</string>
diff --git a/packages/SettingsLib/res/values-fi/strings.xml b/packages/SettingsLib/res/values-fi/strings.xml
index 6877d75..fc6d5da 100644
--- a/packages/SettingsLib/res/values-fi/strings.xml
+++ b/packages/SettingsLib/res/values-fi/strings.xml
@@ -585,7 +585,6 @@
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"Tämä tietokone (sisäinen)"</string>
     <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
     <skip />
-    <string name="media_transfer_internal_mic" msgid="797333824290228595">"Mikrofoni (sisäinen)"</string>
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Telinekaiutin"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Ulkoinen laite"</string>
     <string name="media_transfer_default_device_name" msgid="4315604017399871828">"Yhdistetty laite"</string>
@@ -688,9 +687,10 @@
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Laitteesi on käynnistettävä uudelleen, jotta muutos tulee voimaan. Käynnistä uudelleen nyt tai peru."</string>
     <string name="media_transfer_wired_headphone_name" msgid="8698668536022665254">"Langalliset kuulokkeet"</string>
     <string name="media_transfer_headphone_name" msgid="1131962659136578852">"Kuulokkeet"</string>
-    <string name="media_transfer_usb_speaker_name" msgid="4736537022543593896">"USB-kaiutin"</string>
+    <string name="media_transfer_usb_audio_name" msgid="1789292056757821355">"USB-audio"</string>
     <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"Mikrofoniliitäntä"</string>
-    <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"USB-mikrofoni"</string>
+    <string name="media_transfer_usb_device_mic_name" msgid="7171789543226269822">"USB-mikrofoni"</string>
+    <string name="media_transfer_bt_device_mic_name" msgid="1870669402238687618">"BT-mikrofoni"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Päällä"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Ei käytössä"</string>
     <string name="carrier_network_change_mode" msgid="4257621815706644026">"Operaattorin verkko muuttuu"</string>
diff --git a/packages/SettingsLib/res/values-fr-rCA/strings.xml b/packages/SettingsLib/res/values-fr-rCA/strings.xml
index b3946ce..05157b7 100644
--- a/packages/SettingsLib/res/values-fr-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-fr-rCA/strings.xml
@@ -585,7 +585,6 @@
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"Cet ordinateur (interne)"</string>
     <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
     <skip />
-    <string name="media_transfer_internal_mic" msgid="797333824290228595">"Microphone (interne)"</string>
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Haut-parleur du socle"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Appareil externe"</string>
     <string name="media_transfer_default_device_name" msgid="4315604017399871828">"Appareil connecté"</string>
@@ -688,9 +687,11 @@
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Votre appareil doit être redémarré pour que ce changement prenne effet. Redémarrez-le maintenant ou annulez la modification."</string>
     <string name="media_transfer_wired_headphone_name" msgid="8698668536022665254">"Écouteurs filaires"</string>
     <string name="media_transfer_headphone_name" msgid="1131962659136578852">"Écouteurs"</string>
-    <string name="media_transfer_usb_speaker_name" msgid="4736537022543593896">"Haut-parleur à port USB"</string>
+    <string name="media_transfer_usb_audio_name" msgid="1789292056757821355">"Audio par USB"</string>
     <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"Prise du microphone"</string>
-    <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"Microphone USB"</string>
+    <string name="media_transfer_usb_device_mic_name" msgid="7171789543226269822">"Microphone USB"</string>
+    <!-- no translation found for media_transfer_bt_device_mic_name (1870669402238687618) -->
+    <skip />
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Activé"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Désactivé"</string>
     <string name="carrier_network_change_mode" msgid="4257621815706644026">"Changer de réseau de fournisseur de services"</string>
diff --git a/packages/SettingsLib/res/values-fr/strings.xml b/packages/SettingsLib/res/values-fr/strings.xml
index 13d57ed..31616a7 100644
--- a/packages/SettingsLib/res/values-fr/strings.xml
+++ b/packages/SettingsLib/res/values-fr/strings.xml
@@ -585,7 +585,6 @@
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"Cet ordinateur (interne)"</string>
     <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
     <skip />
-    <string name="media_transfer_internal_mic" msgid="797333824290228595">"Micro (interne)"</string>
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Haut-parleur station d\'accueil"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Appareil externe"</string>
     <string name="media_transfer_default_device_name" msgid="4315604017399871828">"Appareil connecté"</string>
@@ -688,9 +687,11 @@
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Vous devez redémarrer l\'appareil pour que cette modification soit appliquée. Redémarrez maintenant ou annulez l\'opération."</string>
     <string name="media_transfer_wired_headphone_name" msgid="8698668536022665254">"Casque filaire"</string>
     <string name="media_transfer_headphone_name" msgid="1131962659136578852">"Casque audio"</string>
-    <string name="media_transfer_usb_speaker_name" msgid="4736537022543593896">"Haut-parleur USB"</string>
+    <string name="media_transfer_usb_audio_name" msgid="1789292056757821355">"Audio USB"</string>
     <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"Connecteur micro"</string>
-    <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"Micro USB"</string>
+    <string name="media_transfer_usb_device_mic_name" msgid="7171789543226269822">"Micro USB"</string>
+    <!-- no translation found for media_transfer_bt_device_mic_name (1870669402238687618) -->
+    <skip />
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Allumé"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Éteint"</string>
     <string name="carrier_network_change_mode" msgid="4257621815706644026">"Modification du réseau de l\'opérateur"</string>
diff --git a/packages/SettingsLib/res/values-gl/strings.xml b/packages/SettingsLib/res/values-gl/strings.xml
index d95e676..25d4eb8 100644
--- a/packages/SettingsLib/res/values-gl/strings.xml
+++ b/packages/SettingsLib/res/values-gl/strings.xml
@@ -585,7 +585,6 @@
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"Este ordenador (interno)"</string>
     <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
     <skip />
-    <string name="media_transfer_internal_mic" msgid="797333824290228595">"Micrófono (interno)"</string>
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Altofalante da base"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Dispositivo externo"</string>
     <string name="media_transfer_default_device_name" msgid="4315604017399871828">"Dispositivo conectado"</string>
@@ -688,9 +687,10 @@
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"É necesario reiniciar o teu dispositivo para aplicar este cambio. Reiníciao agora ou cancela o cambio."</string>
     <string name="media_transfer_wired_headphone_name" msgid="8698668536022665254">"Auriculares con cable"</string>
     <string name="media_transfer_headphone_name" msgid="1131962659136578852">"Auriculares"</string>
-    <string name="media_transfer_usb_speaker_name" msgid="4736537022543593896">"Altofalante USB"</string>
+    <string name="media_transfer_usb_audio_name" msgid="1789292056757821355">"Audio USB"</string>
     <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"Conector do micrófono"</string>
-    <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"Micrófono USB"</string>
+    <string name="media_transfer_usb_device_mic_name" msgid="7171789543226269822">"Micrófono USB"</string>
+    <string name="media_transfer_bt_device_mic_name" msgid="1870669402238687618">"Micrófono Bluetooth"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Activada"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Desactivada"</string>
     <string name="carrier_network_change_mode" msgid="4257621815706644026">"Cambio de rede do operador"</string>
diff --git a/packages/SettingsLib/res/values-gu/strings.xml b/packages/SettingsLib/res/values-gu/strings.xml
index aa768f8..dad0ce5 100644
--- a/packages/SettingsLib/res/values-gu/strings.xml
+++ b/packages/SettingsLib/res/values-gu/strings.xml
@@ -585,7 +585,6 @@
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"આ કમ્પ્યૂટર (આંતરિક)"</string>
     <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
     <skip />
-    <string name="media_transfer_internal_mic" msgid="797333824290228595">"માઇક્રોફોન (આંતરિક)"</string>
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"ડૉક સ્પીકર"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"બહારનું ડિવાઇસ"</string>
     <string name="media_transfer_default_device_name" msgid="4315604017399871828">"કનેક્ટ કરેલું ડિવાઇસ"</string>
@@ -688,9 +687,10 @@
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"આ ફેરફારને લાગુ કરવા માટે તમારા ડિવાઇસને રીબૂટ કરવાની જરૂર છે. હમણાં જ રીબૂટ કરો કે રદ કરો."</string>
     <string name="media_transfer_wired_headphone_name" msgid="8698668536022665254">"વાયરવાળો હૅડફોન"</string>
     <string name="media_transfer_headphone_name" msgid="1131962659136578852">"હૅડફોન"</string>
-    <string name="media_transfer_usb_speaker_name" msgid="4736537022543593896">"USB સ્પીકર"</string>
+    <string name="media_transfer_usb_audio_name" msgid="1789292056757821355">"USB ઑડિયો"</string>
     <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"માઇક જૅક"</string>
-    <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"USB માઇક"</string>
+    <string name="media_transfer_usb_device_mic_name" msgid="7171789543226269822">"USB માઇક્રોફોન"</string>
+    <string name="media_transfer_bt_device_mic_name" msgid="1870669402238687618">"BT માઇક્રોફોન"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"ચાલુ"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"બંધ"</string>
     <string name="carrier_network_change_mode" msgid="4257621815706644026">"કૅરીઅર નેટવર્કમાં ફેરફાર થઈ રહ્યો છે"</string>
diff --git a/packages/SettingsLib/res/values-hi/strings.xml b/packages/SettingsLib/res/values-hi/strings.xml
index b8e55b5..fcfe9a3 100644
--- a/packages/SettingsLib/res/values-hi/strings.xml
+++ b/packages/SettingsLib/res/values-hi/strings.xml
@@ -585,7 +585,6 @@
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"इस कंप्यूटर पर (इंटरनल)"</string>
     <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
     <skip />
-    <string name="media_transfer_internal_mic" msgid="797333824290228595">"माइक्रोफ़ोन (इंटरनल)"</string>
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"डॉक स्पीकर"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"बाहरी डिवाइस"</string>
     <string name="media_transfer_default_device_name" msgid="4315604017399871828">"कनेक्ट किया गया डिवाइस"</string>
@@ -688,9 +687,10 @@
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"बदली गई सेटिंग को लागू करने के लिए, डिवाइस को रीस्टार्ट करना होगा. अपने डिवाइस को रीस्टार्ट करें या रद्द करें."</string>
     <string name="media_transfer_wired_headphone_name" msgid="8698668536022665254">"तार वाला हेडफ़ोन"</string>
     <string name="media_transfer_headphone_name" msgid="1131962659136578852">"हेडफ़ोन"</string>
-    <string name="media_transfer_usb_speaker_name" msgid="4736537022543593896">"यूएसबी स्पीकर"</string>
+    <string name="media_transfer_usb_audio_name" msgid="1789292056757821355">"यूएसबी ऑडियो"</string>
     <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"माइक्रोफ़ोन जैक"</string>
-    <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"यूएसबी माइक्रोफ़ोन"</string>
+    <string name="media_transfer_usb_device_mic_name" msgid="7171789543226269822">"यूएसबी माइक्रोफ़ोन"</string>
+    <string name="media_transfer_bt_device_mic_name" msgid="1870669402238687618">"ब्लूटूथ माइक्रोफ़ोन"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"चालू है"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"बंद है"</string>
     <string name="carrier_network_change_mode" msgid="4257621815706644026">"मोबाइल और इंटरनेट सेवा देने वाली कंपनी का नेटवर्क बदल रहा है"</string>
diff --git a/packages/SettingsLib/res/values-hr/strings.xml b/packages/SettingsLib/res/values-hr/strings.xml
index 45ac8c2..5db8507 100644
--- a/packages/SettingsLib/res/values-hr/strings.xml
+++ b/packages/SettingsLib/res/values-hr/strings.xml
@@ -585,7 +585,6 @@
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"Ovo računalo (interno)"</string>
     <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
     <skip />
-    <string name="media_transfer_internal_mic" msgid="797333824290228595">"Mikrofon (ugrađeni)"</string>
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Zvučnik priključne stanice"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Vanjski uređaj"</string>
     <string name="media_transfer_default_device_name" msgid="4315604017399871828">"Povezani uređaj"</string>
@@ -688,9 +687,10 @@
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Uređaj se mora ponovno pokrenuti da bi se ta promjena primijenila. Ponovo pokrenite uređaj odmah ili odustanite."</string>
     <string name="media_transfer_wired_headphone_name" msgid="8698668536022665254">"Žičane slušalice"</string>
     <string name="media_transfer_headphone_name" msgid="1131962659136578852">"Slušalice"</string>
-    <string name="media_transfer_usb_speaker_name" msgid="4736537022543593896">"USB zvučnik"</string>
+    <string name="media_transfer_usb_audio_name" msgid="1789292056757821355">"USB zvučnik"</string>
     <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"Utičnica za mikrofon"</string>
-    <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"USB mikrofon"</string>
+    <string name="media_transfer_usb_device_mic_name" msgid="7171789543226269822">"USB mikrofon"</string>
+    <string name="media_transfer_bt_device_mic_name" msgid="1870669402238687618">"BT mikrofon"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Uključeno"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Isključeno"</string>
     <string name="carrier_network_change_mode" msgid="4257621815706644026">"Promjena mreže mobilnog operatera"</string>
diff --git a/packages/SettingsLib/res/values-hu/strings.xml b/packages/SettingsLib/res/values-hu/strings.xml
index 6cb447e..bd70010 100644
--- a/packages/SettingsLib/res/values-hu/strings.xml
+++ b/packages/SettingsLib/res/values-hu/strings.xml
@@ -585,7 +585,6 @@
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"Ez a számítógép (belső)"</string>
     <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
     <skip />
-    <string name="media_transfer_internal_mic" msgid="797333824290228595">"Mikrofon (belső)"</string>
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Dokkhangszóró"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Külső eszköz"</string>
     <string name="media_transfer_default_device_name" msgid="4315604017399871828">"Csatlakoztatott eszköz"</string>
@@ -688,9 +687,10 @@
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Az eszközt újra kell indítani, hogy a módosítás megtörténjen. Indítsa újra most, vagy vesse el a módosítást."</string>
     <string name="media_transfer_wired_headphone_name" msgid="8698668536022665254">"Vezetékes fejhallgató"</string>
     <string name="media_transfer_headphone_name" msgid="1131962659136578852">"Fejhallgató"</string>
-    <string name="media_transfer_usb_speaker_name" msgid="4736537022543593896">"USB-hangszóró"</string>
+    <string name="media_transfer_usb_audio_name" msgid="1789292056757821355">"USB-hangeszköz"</string>
     <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"Mikrofon jack csatlakozója"</string>
-    <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"USB-mikrofon"</string>
+    <string name="media_transfer_usb_device_mic_name" msgid="7171789543226269822">"USB-mikrofon"</string>
+    <string name="media_transfer_bt_device_mic_name" msgid="1870669402238687618">"BT-mikrofon"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Be"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Ki"</string>
     <string name="carrier_network_change_mode" msgid="4257621815706644026">"Szolgáltatói hálózat váltása"</string>
diff --git a/packages/SettingsLib/res/values-hy/strings.xml b/packages/SettingsLib/res/values-hy/strings.xml
index 0e25b79..6549de0 100644
--- a/packages/SettingsLib/res/values-hy/strings.xml
+++ b/packages/SettingsLib/res/values-hy/strings.xml
@@ -585,7 +585,6 @@
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"Այս համակարգիչը (ներքին)"</string>
     <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
     <skip />
-    <string name="media_transfer_internal_mic" msgid="797333824290228595">"Խոսափող (ներքին)"</string>
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Դոկ-կայանով բարձրախոս"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Արտաքին սարք"</string>
     <string name="media_transfer_default_device_name" msgid="4315604017399871828">"Միացված սարք"</string>
@@ -688,9 +687,10 @@
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Սարքն անհրաժեշտ է վերագործարկել, որպեսզի փոփոխությունը կիրառվի։ Վերագործարկեք հիմա կամ չեղարկեք փոփոխությունը։"</string>
     <string name="media_transfer_wired_headphone_name" msgid="8698668536022665254">"Լարով ականջակալ"</string>
     <string name="media_transfer_headphone_name" msgid="1131962659136578852">"Ականջակալ"</string>
-    <string name="media_transfer_usb_speaker_name" msgid="4736537022543593896">"USB բարձրախոս"</string>
+    <string name="media_transfer_usb_audio_name" msgid="1789292056757821355">"USB աուդիո"</string>
     <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"Խոսափողի հարակցիչ"</string>
-    <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"USB խոսափող"</string>
+    <string name="media_transfer_usb_device_mic_name" msgid="7171789543226269822">"USB խոսափող"</string>
+    <string name="media_transfer_bt_device_mic_name" msgid="1870669402238687618">"Bluetooth խոսափող"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Միացնել"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Անջատել"</string>
     <string name="carrier_network_change_mode" msgid="4257621815706644026">"Օպերատորի ցանցի փոփոխություն"</string>
diff --git a/packages/SettingsLib/res/values-in/strings.xml b/packages/SettingsLib/res/values-in/strings.xml
index ceb948d..2555e9b 100644
--- a/packages/SettingsLib/res/values-in/strings.xml
+++ b/packages/SettingsLib/res/values-in/strings.xml
@@ -288,7 +288,7 @@
     <string name="confirm_enable_oem_unlock_title" msgid="8249318129774367535">"Izinkan buka kunci OEM?"</string>
     <string name="confirm_enable_oem_unlock_text" msgid="854131050791011970">"PERINGATAN: Fitur perlindungan perangkat tidak akan berfungsi di perangkat ini saat setelan diaktifkan."</string>
     <string name="mock_location_app" msgid="6269380172542248304">"Pilih aplikasi lokasi palsu"</string>
-    <string name="mock_location_app_not_set" msgid="6972032787262831155">"Tidak ada aplikasi lokasi palsu yang disetel"</string>
+    <string name="mock_location_app_not_set" msgid="6972032787262831155">"Tidak ada aplikasi lokasi simulasi yang disetel"</string>
     <string name="mock_location_app_set" msgid="4706722469342913843">"Aplikasi lokasi palsu: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="debug_networking_category" msgid="6829757985772659599">"Jaringan"</string>
     <string name="wifi_display_certification" msgid="1805579519992520381">"Sertifikasi layar nirkabel"</string>
@@ -585,7 +585,6 @@
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"Komputer ini (internal)"</string>
     <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
     <skip />
-    <string name="media_transfer_internal_mic" msgid="797333824290228595">"Mikrofon (internal)"</string>
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Speaker dok"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Perangkat Eksternal"</string>
     <string name="media_transfer_default_device_name" msgid="4315604017399871828">"Perangkat yang terhubung"</string>
@@ -688,9 +687,10 @@
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Perangkat Anda harus di-reboot agar perubahan ini diterapkan. Reboot sekarang atau batalkan."</string>
     <string name="media_transfer_wired_headphone_name" msgid="8698668536022665254">"Headphone berkabel"</string>
     <string name="media_transfer_headphone_name" msgid="1131962659136578852">"Headphone"</string>
-    <string name="media_transfer_usb_speaker_name" msgid="4736537022543593896">"Speaker USB"</string>
+    <string name="media_transfer_usb_audio_name" msgid="1789292056757821355">"Audio USB"</string>
     <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"Colokan mikrofon"</string>
-    <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"Mikrofon USB"</string>
+    <string name="media_transfer_usb_device_mic_name" msgid="7171789543226269822">"Mikrofon USB"</string>
+    <string name="media_transfer_bt_device_mic_name" msgid="1870669402238687618">"Mikrofon BT"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Aktif"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Nonaktif"</string>
     <string name="carrier_network_change_mode" msgid="4257621815706644026">"Jaringan operator berubah"</string>
diff --git a/packages/SettingsLib/res/values-is/strings.xml b/packages/SettingsLib/res/values-is/strings.xml
index fd31a6f9..eba432f 100644
--- a/packages/SettingsLib/res/values-is/strings.xml
+++ b/packages/SettingsLib/res/values-is/strings.xml
@@ -585,7 +585,6 @@
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"Þessi tölva (innbyggður)"</string>
     <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
     <skip />
-    <string name="media_transfer_internal_mic" msgid="797333824290228595">"Hljóðnemi (innbyggður)"</string>
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Hátalaradokka"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Ytra tæki"</string>
     <string name="media_transfer_default_device_name" msgid="4315604017399871828">"Tengt tæki"</string>
@@ -688,9 +687,10 @@
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Endurræsa þarf tækið til að þessi breyting taki gildi. Endurræstu núna eða hættu við."</string>
     <string name="media_transfer_wired_headphone_name" msgid="8698668536022665254">"Heyrnartól með snúru"</string>
     <string name="media_transfer_headphone_name" msgid="1131962659136578852">"Heyrnartól"</string>
-    <string name="media_transfer_usb_speaker_name" msgid="4736537022543593896">"USB-hátalari"</string>
+    <string name="media_transfer_usb_audio_name" msgid="1789292056757821355">"USB-hljóð"</string>
     <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"Hljóðnematengi"</string>
-    <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"USB-hljóðnemi"</string>
+    <string name="media_transfer_usb_device_mic_name" msgid="7171789543226269822">"USB-hljóðnemi"</string>
+    <string name="media_transfer_bt_device_mic_name" msgid="1870669402238687618">"BT-hljóðnemi"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Kveikt"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Slökkt"</string>
     <string name="carrier_network_change_mode" msgid="4257621815706644026">"Skiptir um farsímakerfi"</string>
diff --git a/packages/SettingsLib/res/values-it/strings.xml b/packages/SettingsLib/res/values-it/strings.xml
index c2931fc..c0f1557 100644
--- a/packages/SettingsLib/res/values-it/strings.xml
+++ b/packages/SettingsLib/res/values-it/strings.xml
@@ -585,7 +585,6 @@
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"Questo computer (interno)"</string>
     <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
     <skip />
-    <string name="media_transfer_internal_mic" msgid="797333824290228595">"Microfono (interno)"</string>
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Base con altoparlante"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Dispositivo esterno"</string>
     <string name="media_transfer_default_device_name" msgid="4315604017399871828">"Dispositivo connesso"</string>
@@ -688,9 +687,11 @@
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Per applicare questa modifica, devi riavviare il dispositivo. Riavvia ora o annulla."</string>
     <string name="media_transfer_wired_headphone_name" msgid="8698668536022665254">"Cuffie con cavo"</string>
     <string name="media_transfer_headphone_name" msgid="1131962659136578852">"Cuffie"</string>
-    <string name="media_transfer_usb_speaker_name" msgid="4736537022543593896">"Altoparlante USB"</string>
+    <string name="media_transfer_usb_audio_name" msgid="1789292056757821355">"Audio USB"</string>
     <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"Jack per microfono"</string>
-    <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"Microfono USB"</string>
+    <string name="media_transfer_usb_device_mic_name" msgid="7171789543226269822">"Microfono USB"</string>
+    <!-- no translation found for media_transfer_bt_device_mic_name (1870669402238687618) -->
+    <skip />
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"On"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Off"</string>
     <string name="carrier_network_change_mode" msgid="4257621815706644026">"Cambio della rete dell\'operatore"</string>
diff --git a/packages/SettingsLib/res/values-iw/strings.xml b/packages/SettingsLib/res/values-iw/strings.xml
index bcf7e92..b6f863e 100644
--- a/packages/SettingsLib/res/values-iw/strings.xml
+++ b/packages/SettingsLib/res/values-iw/strings.xml
@@ -416,7 +416,7 @@
     <string name="verbose_vendor_logging_notification_action" msgid="1190831050259046071">"הפעלה ליום אחד נוסף"</string>
     <string name="verbose_vendor_logging_preference_summary_will_disable" msgid="6175431593394522553">"מתבצעת השבתה אחרי יום אחד"</string>
     <string name="verbose_vendor_logging_preference_summary_on" msgid="9017757242481762036">"בוצעה הפעלה ללא הגבלת זמן"</string>
-    <string name="window_animation_scale_title" msgid="5236381298376812508">"קנה מידה לאנימציה של חלון"</string>
+    <string name="window_animation_scale_title" msgid="5236381298376812508">"מהירות אנימציית מעבר במסכים"</string>
     <string name="transition_animation_scale_title" msgid="1278477690695439337">"קנה מידה לאנימציית מעבר"</string>
     <string name="animator_duration_scale_title" msgid="7082913931326085176">"קנה מידה למשך זמן אנימציה"</string>
     <string name="overlay_display_devices_title" msgid="5411894622334469607">"יצירת הדמיה של תצוגות משניות"</string>
@@ -585,7 +585,6 @@
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"המחשב הזה (פנימי)"</string>
     <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
     <skip />
-    <string name="media_transfer_internal_mic" msgid="797333824290228595">"מיקרופון (פנימי)"</string>
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"רמקול של אביזר העגינה"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"מכשיר חיצוני"</string>
     <string name="media_transfer_default_device_name" msgid="4315604017399871828">"המכשיר המחובר"</string>
@@ -688,9 +687,10 @@
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"צריך להפעיל מחדש את המכשיר כדי להחיל את השינוי. יש להפעיל מחדש עכשיו או לבטל."</string>
     <string name="media_transfer_wired_headphone_name" msgid="8698668536022665254">"אוזניות חוטיות"</string>
     <string name="media_transfer_headphone_name" msgid="1131962659136578852">"אוזניות"</string>
-    <string name="media_transfer_usb_speaker_name" msgid="4736537022543593896">"‏רמקול ב-USB"</string>
+    <string name="media_transfer_usb_audio_name" msgid="1789292056757821355">"‏אודיו ב-USB"</string>
     <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"שקע למיקרופון"</string>
-    <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"‏מיקרופון USB"</string>
+    <string name="media_transfer_usb_device_mic_name" msgid="7171789543226269822">"‏מיקרופון ב-USB"</string>
+    <string name="media_transfer_bt_device_mic_name" msgid="1870669402238687618">"‏מיקרופון BT"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"פועלת"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"מצב כבוי"</string>
     <string name="carrier_network_change_mode" msgid="4257621815706644026">"רשת ספק משתנה"</string>
diff --git a/packages/SettingsLib/res/values-ja/strings.xml b/packages/SettingsLib/res/values-ja/strings.xml
index 185c6c9..ff3870a 100644
--- a/packages/SettingsLib/res/values-ja/strings.xml
+++ b/packages/SettingsLib/res/values-ja/strings.xml
@@ -585,7 +585,6 @@
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"このパソコン(内蔵)"</string>
     <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
     <skip />
-    <string name="media_transfer_internal_mic" msgid="797333824290228595">"マイク(内蔵)"</string>
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"ホルダー スピーカー"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"外部デバイス"</string>
     <string name="media_transfer_default_device_name" msgid="4315604017399871828">"接続済みのデバイス"</string>
@@ -688,9 +687,10 @@
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"この変更を適用するには、デバイスの再起動が必要です。今すぐ再起動するか、キャンセルしてください。"</string>
     <string name="media_transfer_wired_headphone_name" msgid="8698668536022665254">"有線ヘッドフォン"</string>
     <string name="media_transfer_headphone_name" msgid="1131962659136578852">"ヘッドフォン"</string>
-    <string name="media_transfer_usb_speaker_name" msgid="4736537022543593896">"USB スピーカー"</string>
+    <string name="media_transfer_usb_audio_name" msgid="1789292056757821355">"USB オーディオ"</string>
     <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"マイク差込口"</string>
-    <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"USB マイク"</string>
+    <string name="media_transfer_usb_device_mic_name" msgid="7171789543226269822">"USB マイク"</string>
+    <string name="media_transfer_bt_device_mic_name" msgid="1870669402238687618">"BT マイク"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"ON"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"OFF"</string>
     <string name="carrier_network_change_mode" msgid="4257621815706644026">"携帯通信会社のネットワークを変更します"</string>
diff --git a/packages/SettingsLib/res/values-ka/strings.xml b/packages/SettingsLib/res/values-ka/strings.xml
index 9532c3a..0ec0648 100644
--- a/packages/SettingsLib/res/values-ka/strings.xml
+++ b/packages/SettingsLib/res/values-ka/strings.xml
@@ -585,7 +585,6 @@
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"ეს კომპიუტერი (შიდა)"</string>
     <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
     <skip />
-    <string name="media_transfer_internal_mic" msgid="797333824290228595">"მიკროფონი (შიდა)"</string>
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"სამაგრის დინამიკი"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"გარე მოწყობილობა"</string>
     <string name="media_transfer_default_device_name" msgid="4315604017399871828">"დაკავშირებული მოწყობილობა"</string>
@@ -688,9 +687,10 @@
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"ამ ცვლილების ასამოქმედებლად თქვენი მოწყობილობა უნდა გადაიტვირთოს. გადატვირთეთ ახლავე ან გააუქმეთ."</string>
     <string name="media_transfer_wired_headphone_name" msgid="8698668536022665254">"სადენიანი ყურსასმენი"</string>
     <string name="media_transfer_headphone_name" msgid="1131962659136578852">"ყურსასმენი"</string>
-    <string name="media_transfer_usb_speaker_name" msgid="4736537022543593896">"USB დინამიკი"</string>
+    <string name="media_transfer_usb_audio_name" msgid="1789292056757821355">"USB აუდიო"</string>
     <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"მიკროფონის ჯეკი"</string>
-    <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"USB მიკროფონი"</string>
+    <string name="media_transfer_usb_device_mic_name" msgid="7171789543226269822">"USB მიკროფონი"</string>
+    <string name="media_transfer_bt_device_mic_name" msgid="1870669402238687618">"BT მიკროფონი"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"ჩართვა"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"გამორთვა"</string>
     <string name="carrier_network_change_mode" msgid="4257621815706644026">"ოპერატორის ქსელის შეცვლა"</string>
diff --git a/packages/SettingsLib/res/values-kk/strings.xml b/packages/SettingsLib/res/values-kk/strings.xml
index 4f64bb9..f7547170 100644
--- a/packages/SettingsLib/res/values-kk/strings.xml
+++ b/packages/SettingsLib/res/values-kk/strings.xml
@@ -585,7 +585,6 @@
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"Осы компьютер (ішкі)"</string>
     <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
     <skip />
-    <string name="media_transfer_internal_mic" msgid="797333824290228595">"Микрофон (ішкі)"</string>
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Динамигі бар қондыру станциясы"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Сыртқы құрылғы"</string>
     <string name="media_transfer_default_device_name" msgid="4315604017399871828">"Жалғанған құрылғы"</string>
@@ -688,9 +687,10 @@
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Бұл өзгеріс күшіне енуі үшін, құрылғыны қайта жүктеу керек. Қазір қайта жүктеңіз не бас тартыңыз."</string>
     <string name="media_transfer_wired_headphone_name" msgid="8698668536022665254">"Сымды құлақаспап"</string>
     <string name="media_transfer_headphone_name" msgid="1131962659136578852">"Құлақаспап"</string>
-    <string name="media_transfer_usb_speaker_name" msgid="4736537022543593896">"USB динамик"</string>
+    <string name="media_transfer_usb_audio_name" msgid="1789292056757821355">"USB аудио"</string>
     <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"Микрофон ұяшығы"</string>
-    <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"USB микрофоны"</string>
+    <string name="media_transfer_usb_device_mic_name" msgid="7171789543226269822">"USB микрофон"</string>
+    <string name="media_transfer_bt_device_mic_name" msgid="1870669402238687618">"Bluetooth микрофоны"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Қосу"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Өшіру"</string>
     <string name="carrier_network_change_mode" msgid="4257621815706644026">"Оператор желісін өзгерту"</string>
diff --git a/packages/SettingsLib/res/values-km/strings.xml b/packages/SettingsLib/res/values-km/strings.xml
index 43807a0..cac7c55 100644
--- a/packages/SettingsLib/res/values-km/strings.xml
+++ b/packages/SettingsLib/res/values-km/strings.xml
@@ -388,7 +388,7 @@
     <string name="show_hw_screen_updates_summary" msgid="3539770072741435691">"ទិដ្ឋភាព​បញ្ចេញពន្លឺភ្លឹបភ្លែត​នៅក្នុង​វិនដូនៅ​ពេលគូរ"</string>
     <string name="show_hw_layers_updates" msgid="5268370750002509767">"បង្ហាញ​​បច្ចុប្បន្នភាព​ស្រទាប់​ហាតវែរ"</string>
     <string name="show_hw_layers_updates_summary" msgid="5850955890493054618">"ស្រទាប់​ហាតវែរ​បញ្ចេញ​ពន្លឺ​បៃ​តង​នៅពេលធ្វើ​បច្ចុប្បន្នភាព"</string>
-    <string name="debug_hw_overdraw" msgid="8944851091008756796">"ជួសជុល​ការគូរលើស GPU"</string>
+    <string name="debug_hw_overdraw" msgid="8944851091008756796">"ជួសជុលការដាក់បង្ហាញពីលើច្រើនជ្រុលរបស់ GPU"</string>
     <string name="disable_overlays" msgid="4206590799671557143">"បិទ​ការ​ត្រួត HW"</string>
     <string name="disable_overlays_summary" msgid="1954852414363338166">"ប្រើ GPU ជា​និច្ច​សម្រាប់​​ផ្សំ​អេក្រង់"</string>
     <string name="simulate_color_space" msgid="1206503300335835151">"ត្រាប់តាមគំរូពណ៌"</string>
@@ -417,8 +417,8 @@
     <string name="verbose_vendor_logging_preference_summary_will_disable" msgid="6175431593394522553">"បិទក្រោយពេលមួយថ្ងៃ"</string>
     <string name="verbose_vendor_logging_preference_summary_on" msgid="9017757242481762036">"បានបើកដោយគ្មានពេលកំណត់"</string>
     <string name="window_animation_scale_title" msgid="5236381298376812508">"មាត្រដ្ឋាន​ចលនា​វិនដូ"</string>
-    <string name="transition_animation_scale_title" msgid="1278477690695439337">"មាត្រដ្ឋាន​ដំណើរ​ផ្លាស់ប្ដូរ​ចលនា"</string>
-    <string name="animator_duration_scale_title" msgid="7082913931326085176">"មាត្រដ្ឋាន​រយៈពេល​នៃ​កម្មវិធី​ចលនា"</string>
+    <string name="transition_animation_scale_title" msgid="1278477690695439337">"មាត្រដ្ឋាន​ចលនាបែបផែនឆ្លង"</string>
+    <string name="animator_duration_scale_title" msgid="7082913931326085176">"មាត្រដ្ឋាន​រយៈពេល​ចលនា"</string>
     <string name="overlay_display_devices_title" msgid="5411894622334469607">"ត្រាប់ជាអេក្រង់​ទី​ពីរ"</string>
     <string name="debug_applications_category" msgid="5394089406638954196">"កម្មវិធី"</string>
     <string name="immediately_destroy_activities" msgid="1826287490705167403">"កុំ​រក្សា​ទុកសកម្មភាព"</string>
@@ -585,7 +585,6 @@
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"កុំព្យូទ័រនេះ (ខាងក្នុង)"</string>
     <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
     <skip />
-    <string name="media_transfer_internal_mic" msgid="797333824290228595">"មីក្រូហ្វូន (ខាងក្នុង)"</string>
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"ឧបាល័រជើងទម្រ"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"ឧបករណ៍ខាងក្រៅ"</string>
     <string name="media_transfer_default_device_name" msgid="4315604017399871828">"​ឧបករណ៍ដែលបាន​ភ្ជាប់"</string>
@@ -688,9 +687,10 @@
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"ត្រូវតែ​ចាប់ផ្ដើម​ឧបករណ៍​របស់អ្នក​ឡើងវិញ ដើម្បីឱ្យ​ការផ្លាស់ប្ដូរ​នេះ​មានប្រសិទ្ធភាព។ ចាប់ផ្ដើមឡើងវិញ​ឥឡូវនេះ ឬ​បោះបង់​។"</string>
     <string name="media_transfer_wired_headphone_name" msgid="8698668536022665254">"កាស​មានខ្សែ"</string>
     <string name="media_transfer_headphone_name" msgid="1131962659136578852">"កាស"</string>
-    <string name="media_transfer_usb_speaker_name" msgid="4736537022543593896">"ឧបករណ៍បំពងសំឡេង USB"</string>
+    <string name="media_transfer_usb_audio_name" msgid="1789292056757821355">"ឧបករណ៍បំពងសំឡេង USB"</string>
     <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"ឌុយ​មីក្រូហ្វូន"</string>
-    <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"មីក្រូហ្វូន USB"</string>
+    <string name="media_transfer_usb_device_mic_name" msgid="7171789543226269822">"មីក្រូហ្វូន USB"</string>
+    <string name="media_transfer_bt_device_mic_name" msgid="1870669402238687618">"មីក្រូហ្វូន BT"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"បើក"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"បិទ"</string>
     <string name="carrier_network_change_mode" msgid="4257621815706644026">"បណ្តាញ​ក្រុមហ៊ុនសេវាទូរសព្ទ​កំពុងផ្លាស់ប្តូរ"</string>
diff --git a/packages/SettingsLib/res/values-kn/strings.xml b/packages/SettingsLib/res/values-kn/strings.xml
index 016f8b9..92534ae 100644
--- a/packages/SettingsLib/res/values-kn/strings.xml
+++ b/packages/SettingsLib/res/values-kn/strings.xml
@@ -241,7 +241,7 @@
     <string name="category_clone" msgid="1554511758987195974">"ಕ್ಲೋನ್"</string>
     <string name="development_settings_title" msgid="140296922921597393">"ಡೆವಲಪರ್ ಆಯ್ಕೆಗಳು"</string>
     <string name="development_settings_enable" msgid="4285094651288242183">"ಡೆವಲಪರ್ ಆಯ್ಕೆಗಳನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಿ"</string>
-    <string name="development_settings_summary" msgid="8718917813868735095">"ಅಪ್ಲಿಕೇಶನ್ ಅಭಿವೃದ್ಧಿಗಾಗಿ ಆಯ್ಕೆಗಳನ್ನು ಹೊಂದಿಸಿ"</string>
+    <string name="development_settings_summary" msgid="8718917813868735095">"ಆ್ಯಪ್‌ ಅಭಿವೃದ್ಧಿಗಾಗಿ ಆಯ್ಕೆಗಳನ್ನು ಹೊಂದಿಸಿ"</string>
     <string name="development_settings_not_available" msgid="355070198089140951">"ಈ ಬಳಕೆದಾರರಿಗೆ ಡೆವಲಪರ್‌ ಆಯ್ಕೆಗಳು ಲಭ್ಯವಿಲ್ಲ"</string>
     <string name="vpn_settings_not_available" msgid="2894137119965668920">"VPN ಸೆಟ್ಟಿಂಗ್‌ಗಳು ಈ ಬಳಕೆದಾರರಿಗೆ ಲಭ್ಯವಿಲ್ಲ"</string>
     <string name="tethering_settings_not_available" msgid="266821736434699780">"ಟೆಥರಿಂಗ್ ಸೆಟ್ಟಿಂಗ್‌ಗಳು ಈ ಬಳಕೆದಾರರಿಗೆ ಲಭ್ಯವಿಲ್ಲ"</string>
@@ -287,9 +287,9 @@
     <string name="oem_unlock_enable_summary" msgid="5857388174390953829">"ಬೂಟ್‌ಲೋಡರ್‌ ಅನ್‌ಲಾಕ್‌ ಮಾಡಲು ಅನುಮತಿಸಿ"</string>
     <string name="confirm_enable_oem_unlock_title" msgid="8249318129774367535">"OEM ಅನ್‌ಲಾಕ್‌ ಮಾಡುವಿಕೆಯನ್ನು ಅನುಮತಿಸುವುದೇ?"</string>
     <string name="confirm_enable_oem_unlock_text" msgid="854131050791011970">"ಎಚ್ಚರಿಕೆ: ಈ ಸೆಟ್ಟಿಂಗ್‌ ಆನ್‌ ಇರುವಾಗ ಈ ಸಾಧನದಲ್ಲಿ ಸಾಧನ ಸಂರಕ್ಷಣಾ ವೈಶಿಷ್ಟ್ಯಗಳು ಕಾರ್ಯ ನಿರ್ವಹಿಸುವುದಿಲ್ಲ."</string>
-    <string name="mock_location_app" msgid="6269380172542248304">"ಅಣಕು ಸ್ಥಳ ಅಪ್ಲಿಕೇಶನ್ ಆಯ್ಕೆಮಾಡಿ"</string>
-    <string name="mock_location_app_not_set" msgid="6972032787262831155">"ಯಾವುದೇ ಅಣಕು ಸ್ಥಳ ಅಪ್ಲಿಕೇಶನ್ ಹೊಂದಿಕೆಯಾಗಿಲ್ಲ"</string>
-    <string name="mock_location_app_set" msgid="4706722469342913843">"ಅಣಕು ಸ್ಥಳ ಅಪ್ಲಿಕೇಶನ್: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="mock_location_app" msgid="6269380172542248304">"ಅಣಕು ಸ್ಥಳ ಆ್ಯಪ್‌ ಆಯ್ಕೆಮಾಡಿ"</string>
+    <string name="mock_location_app_not_set" msgid="6972032787262831155">"ಯಾವುದೇ ಅಣಕು ಸ್ಥಳ ಆ್ಯಪ್‌ ಹೊಂದಿಕೆಯಾಗಿಲ್ಲ"</string>
+    <string name="mock_location_app_set" msgid="4706722469342913843">"ಅಣಕು ಸ್ಥಳ ಆ್ಯಪ್‌: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="debug_networking_category" msgid="6829757985772659599">"ನೆಟ್‌ವರ್ಕಿಂಗ್"</string>
     <string name="wifi_display_certification" msgid="1805579519992520381">"ವೈರ್‌ಲೆಸ್ ಪ್ರದರ್ಶನ ಪ್ರಮಾಣೀಕರಣ"</string>
     <string name="wifi_verbose_logging" msgid="1785910450009679371">"Wi‑Fi ವೆರ್ಬೋಸ್ ಲಾಗಿಂಗ್ ಸಕ್ರಿಯಗೊಳಿಸಿ"</string>
@@ -356,17 +356,17 @@
     <string name="bluetooth_enable_gabeldorsche_summary" msgid="2054730331770712629">"ಬ್ಲೂಟೂತ್ Gabeldorsche ವೈಶಿಷ್ಟ್ಯದ ಸ್ಟ್ಯಾಕ್‌ ಅನ್ನು ಸಕ್ರಿಯಗೊಳಿಸುತ್ತದೆ."</string>
     <string name="enhanced_connectivity_summary" msgid="1576414159820676330">"ವರ್ಧಿತ ಸಂಪರ್ಕ ವೈಶಿಷ್ಟ್ಯವನ್ನು ಸಕ್ರಿಯಗೊಳಿಸುತ್ತದೆ"</string>
     <string name="enable_terminal_title" msgid="3834790541986303654">"ಸ್ಥಳೀಯ ಟರ್ಮಿನಲ್"</string>
-    <string name="enable_terminal_summary" msgid="2481074834856064500">"ಸ್ಥಳೀಯ ಶೆಲ್ ಪ್ರವೇಶವನ್ನು ಒದಗಿಸುವ ಟರ್ಮಿನಲ್ ಅಪ್ಲಿಕೇಶನ್ ಸಕ್ರಿಯಗೊಳಿಸಿ"</string>
+    <string name="enable_terminal_summary" msgid="2481074834856064500">"ಸ್ಥಳೀಯ ಶೆಲ್ ಪ್ರವೇಶವನ್ನು ಒದಗಿಸುವ ಟರ್ಮಿನಲ್ ಆ್ಯಪ್‌ ಸಕ್ರಿಯಗೊಳಿಸಿ"</string>
     <string name="hdcp_checking_title" msgid="3155692785074095986">"HDCP ಪರೀಕ್ಷಿಸುವಿಕೆ"</string>
     <string name="hdcp_checking_dialog_title" msgid="7691060297616217781">"HDCP ಪರಿಶೀಲನಾ ನಡವಳಿಕೆಯನ್ನು ಹೊಂದಿಸಿ"</string>
     <string name="debug_debugging_category" msgid="535341063709248842">"ಡೀಬಗ್ ಮಾಡುವಿಕೆ"</string>
-    <string name="debug_app" msgid="8903350241392391766">"ಡೀಬಗ್ ಅಪ್ಲಿಕೇಶನ್‌ ಆಯ್ಕೆಮಾಡಿ"</string>
+    <string name="debug_app" msgid="8903350241392391766">"ಡೀಬಗ್ ಆ್ಯಪ್‌ ಆಯ್ಕೆಮಾಡಿ"</string>
     <string name="debug_app_not_set" msgid="1934083001283807188">"ಯಾವುದೇ ಡೀಬಗ್ ಅಪ್ಲಿಕೇಶನ್‌ ಅನ್ನು ಹೊಂದಿಸಿಲ್ಲ"</string>
     <string name="debug_app_set" msgid="6599535090477753651">"ಡೀಬಗ್ ಅಪ್ಲಿಕೇಶನ್‌: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="select_application" msgid="2543228890535466325">"ಅಪ್ಲಿಕೇಶನ್ ಆಯ್ಕೆಮಾಡಿ"</string>
     <string name="no_application" msgid="9038334538870247690">"ಏನೂ ಇಲ್ಲ"</string>
     <string name="wait_for_debugger" msgid="7461199843335409809">"ಡೀಬಗರ್‌‌ಗಾಗಿ ನಿರೀಕ್ಷಿಸಿ"</string>
-    <string name="wait_for_debugger_summary" msgid="6846330006113363286">"ಲಗತ್ತನ್ನು ಕಾರ್ಯಗತಗೊಳಿಸುವ ಮೊದಲು ಡೀಬಗರ್‌‌ಗಾಗಿ ಡೀಬಗ್‌‌‌ ಮಾಡಿದ ಅಪ್ಲಿಕೇಶನ್‌‌ ಕಾಯುತ್ತದೆ"</string>
+    <string name="wait_for_debugger_summary" msgid="6846330006113363286">"ಲಗತ್ತನ್ನು ಕಾರ್ಯಗತಗೊಳಿಸುವ ಮೊದಲು ಡೀಬಗರ್‌‌ಗಾಗಿ ಡೀಬಗ್‌‌‌ ಮಾಡಿದ ಆ್ಯಪ್‌ ಕಾಯುತ್ತದೆ"</string>
     <string name="debug_input_category" msgid="7349460906970849771">"ಇನ್‌ಪುಟ್"</string>
     <string name="debug_drawing_category" msgid="5066171112313666619">"ಚಿತ್ರಣ"</string>
     <string name="debug_hw_drawing_category" msgid="5830815169336975162">"ಹಾರ್ಡ್‌ವೇರ್‌ ವೇಗವರ್ಧಿತ ರೆಂಡರಿಂಗ್"</string>
@@ -425,11 +425,11 @@
     <string name="immediately_destroy_activities_summary" msgid="6289590341144557614">"ಬಳಕೆದಾರರು ಹೊರಹೋಗುತ್ತಿದ್ದಂತೆಯೇ ಚಟುವಟಿಕೆ ನಾಶಪಡಿಸು"</string>
     <string name="app_process_limit_title" msgid="8361367869453043007">"ಹಿನ್ನೆಲೆ ಪ್ರಕ್ರಿಯೆ ಮಿತಿ"</string>
     <string name="show_all_anrs" msgid="9160563836616468726">"ಹಿನ್ನೆಲೆ ANR ಗಳನ್ನು ತೋರಿಸಿ"</string>
-    <string name="show_all_anrs_summary" msgid="8562788834431971392">"ಹಿನ್ನೆಲೆ ಅಪ್ಲಿಕೇಶನ್‌ಗಳಿಗಾಗಿ ಅಪ್ಲಿಕೇಶನ್ ಪ್ರತಿಕ್ರಿಯಿಸುತ್ತಿಲ್ಲ ಎಂಬ ಸಂಭಾಷಣೆ ತೋರಿಸಿ"</string>
+    <string name="show_all_anrs_summary" msgid="8562788834431971392">"ಹಿನ್ನೆಲೆ ಆ್ಯಪ್‌ಗಳಿಗಾಗಿ ಆ್ಯಪ್‌ ಪ್ರತಿಕ್ರಿಯಿಸುತ್ತಿಲ್ಲ ಎಂಬ ಸಂಭಾಷಣೆ ತೋರಿಸಿ"</string>
     <string name="show_notification_channel_warnings" msgid="3448282400127597331">"ನೋಟಿಫಿಕೇಶನ್ ಎಚ್ಚರಿಕೆ ತೋರಿಸಿ"</string>
     <string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"ಅಮಾನ್ಯ ಚಾನಲ್ ಅಧಿಸೂಚನೆಗಾಗಿ ಪರದೆಯಲ್ಲಿ ಎಚ್ಚರಿಕೆ"</string>
     <string name="force_allow_on_external" msgid="9187902444231637880">"ಬಾಹ್ಯವಾಗಿ ಅಪ್ಲಿಕೇಶನ್‌ಗಳನ್ನು ಒತ್ತಾಯವಾಗಿ ಅನುಮತಿಸಿ"</string>
-    <string name="force_allow_on_external_summary" msgid="8525425782530728238">"ಮ್ಯಾನಿಫೆಸ್ಟ್ ಮೌಲ್ಯಗಳು ಯಾವುದೇ ಆಗಿದ್ದರೂ, ಬಾಹ್ಯ ಸಂಗ್ರಹಣೆಗೆ ಬರೆಯಲು ಯಾವುದೇ ಅಪ್ಲಿಕೇಶನ್‌ ಅನ್ನು ಅರ್ಹಗೊಳಿಸುತ್ತದೆ"</string>
+    <string name="force_allow_on_external_summary" msgid="8525425782530728238">"ಮ್ಯಾನಿಫೆಸ್ಟ್ ಮೌಲ್ಯಗಳು ಯಾವುದೇ ಆಗಿದ್ದರೂ, ಬಾಹ್ಯ ಸಂಗ್ರಹಣೆಗೆ ಬರೆಯಲು ಯಾವುದೇ ಆ್ಯಪ್‌ ಅನ್ನು ಅರ್ಹಗೊಳಿಸುತ್ತದೆ"</string>
     <string name="force_resizable_activities" msgid="7143612144399959606">"ಚಟುವಟಿಕೆಗಳನ್ನು ಮರುಗಾತ್ರಗೊಳಿಸುವಂತೆ ಒತ್ತಾಯ ಮಾಡಿ"</string>
     <string name="force_resizable_activities_summary" msgid="2490382056981583062">"ಮ್ಯಾನಿಫೆಸ್ಟ್ ಮೌಲ್ಯಗಳನ್ನು ಪರಿಗಣಿಸದೇ, ಬಹು-ವಿಂಡೊಗೆ ಎಲ್ಲಾ ಚಟುವಟಿಕೆಗಳನ್ನು ಮರುಗಾತ್ರಗೊಳಿಸುವಂತೆ ಮಾಡಿ."</string>
     <string name="enable_freeform_support" msgid="7599125687603914253">"ಮುಕ್ತಸ್ವರೂಪದ ವಿಂಡೊಗಳನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಿ"</string>
@@ -453,7 +453,7 @@
     <string name="inactive_apps_title" msgid="5372523625297212320">"ಸ್ಟ್ಯಾಂಡ್‌ಬೈ ಅಪ್ಲಿಕೇಶನ್‌ಗಳು"</string>
     <string name="inactive_app_inactive_summary" msgid="3161222402614236260">"ನಿಷ್ಕ್ರಿಯ. ಟಾಗಲ್ ಮಾಡಲು ಟ್ಯಾಪ್ ಮಾಡಿ."</string>
     <string name="inactive_app_active_summary" msgid="8047630990208722344">"ಸಕ್ರಿಯ. ಟಾಗಲ್ ಮಾಡಲು ಟ್ಯಾಪ್ ಮಾಡಿ."</string>
-    <string name="standby_bucket_summary" msgid="5128193447550429600">"ಅಪ್ಲಿಕೇಶನ್ ಸ್ಟ್ಯಾಂಡ್‌ಬೈ ಸ್ಥಿತಿ:<xliff:g id="BUCKET"> %s</xliff:g>"</string>
+    <string name="standby_bucket_summary" msgid="5128193447550429600">"ಆ್ಯಪ್‌ ಸ್ಟ್ಯಾಂಡ್‌ಬೈ ಸ್ಥಿತಿ:<xliff:g id="BUCKET"> %s</xliff:g>"</string>
     <string name="transcode_settings_title" msgid="2581975870429850549">"ಮೀಡಿಯಾ ಟ್ರಾನ್ಸ್‌ಕೋಡಿಂಗ್ ಸೆಟ್ಟಿಂಗ್‌ಗಳು"</string>
     <string name="transcode_user_control" msgid="6176368544817731314">"ಟ್ರಾನ್ಸ್‌ಕೋಡಿಂಗ್ ಡೀಫಾಲ್ಟ್‌ಗಳನ್ನು ಅತಿಕ್ರಮಿಸಿ"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"ಟ್ರಾನ್ಸ್‌ಕೋಡಿಂಗ್ ಅನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಿ"</string>
@@ -585,7 +585,6 @@
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"ಈ ಕಂಪ್ಯೂಟರ್ (ಆಂತರಿಕ)"</string>
     <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
     <skip />
-    <string name="media_transfer_internal_mic" msgid="797333824290228595">"ಮೈಕ್ರೊಫೋನ್‌ (ಆಂತರಿಕ)"</string>
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"ಡಾಕ್ ಸ್ಪೀಕರ್"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"ಬಾಹ್ಯ ಸಾಧನ"</string>
     <string name="media_transfer_default_device_name" msgid="4315604017399871828">"ಕನೆಕ್ಟ್ ಮಾಡಿರುವ ಸಾಧನ"</string>
@@ -688,9 +687,10 @@
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"ಈ ಬದಲಾವಣೆ ಅನ್ವಯವಾಗಲು ನಿಮ್ಮ ಸಾಧನವನ್ನು ರೀಬೂಟ್ ಮಾಡಬೇಕು. ಇದೀಗ ರೀಬೂಟ್ ಮಾಡಿ ಅಥವಾ ರದ್ದುಗೊಳಿಸಿ."</string>
     <string name="media_transfer_wired_headphone_name" msgid="8698668536022665254">"ವೈಯರ್ ಹೊಂದಿರುವ ಹೆಡ್‌ಫೋನ್"</string>
     <string name="media_transfer_headphone_name" msgid="1131962659136578852">"ಹೆಡ್‌ಫೋನ್"</string>
-    <string name="media_transfer_usb_speaker_name" msgid="4736537022543593896">"USB ಸ್ಪೀಕರ್"</string>
+    <string name="media_transfer_usb_audio_name" msgid="1789292056757821355">"USB ಆಡಿಯೋ"</string>
     <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"ಮೈಕ್‌ ಜ್ಯಾಕ್‌"</string>
-    <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"USB ಮೈಕ್‌"</string>
+    <string name="media_transfer_usb_device_mic_name" msgid="7171789543226269822">"USB ಮೈಕ್ರೊಫೋನ್‌"</string>
+    <string name="media_transfer_bt_device_mic_name" msgid="1870669402238687618">"BT ಮೈಕ್ರೊಫೋನ್"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"ಆನ್ ಆಗಿದೆ"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"ಆಫ್"</string>
     <string name="carrier_network_change_mode" msgid="4257621815706644026">"ವಾಹಕ ನೆಟ್‌ವರ್ಕ್ ಬದಲಾಯಿಸುವಿಕೆ"</string>
diff --git a/packages/SettingsLib/res/values-ko/strings.xml b/packages/SettingsLib/res/values-ko/strings.xml
index 0af77dd..1bfe19c 100644
--- a/packages/SettingsLib/res/values-ko/strings.xml
+++ b/packages/SettingsLib/res/values-ko/strings.xml
@@ -585,7 +585,6 @@
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"이 컴퓨터(내부)"</string>
     <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
     <skip />
-    <string name="media_transfer_internal_mic" msgid="797333824290228595">"마이크(내부)"</string>
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"도크 스피커"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"외부 기기"</string>
     <string name="media_transfer_default_device_name" msgid="4315604017399871828">"연결된 기기"</string>
@@ -688,9 +687,10 @@
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"변경사항을 적용하려면 기기를 재부팅해야 합니다. 지금 재부팅하거나 취소하세요."</string>
     <string name="media_transfer_wired_headphone_name" msgid="8698668536022665254">"유선 헤드폰"</string>
     <string name="media_transfer_headphone_name" msgid="1131962659136578852">"헤드폰"</string>
-    <string name="media_transfer_usb_speaker_name" msgid="4736537022543593896">"USB 스피커"</string>
+    <string name="media_transfer_usb_audio_name" msgid="1789292056757821355">"USB 오디오"</string>
     <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"마이크 잭"</string>
-    <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"USB 마이크"</string>
+    <string name="media_transfer_usb_device_mic_name" msgid="7171789543226269822">"USB 마이크"</string>
+    <string name="media_transfer_bt_device_mic_name" msgid="1870669402238687618">"블루투스 마이크"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"사용"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"사용 안 함"</string>
     <string name="carrier_network_change_mode" msgid="4257621815706644026">"이동통신사 네트워크 변경"</string>
diff --git a/packages/SettingsLib/res/values-ky/strings.xml b/packages/SettingsLib/res/values-ky/strings.xml
index a3ff033..1884b03 100644
--- a/packages/SettingsLib/res/values-ky/strings.xml
+++ b/packages/SettingsLib/res/values-ky/strings.xml
@@ -585,7 +585,6 @@
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"Бул компьютер (ички)"</string>
     <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
     <skip />
-    <string name="media_transfer_internal_mic" msgid="797333824290228595">"Микрофон (ички)"</string>
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Док бекеттин динамиги"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Тышкы түзмөк"</string>
     <string name="media_transfer_default_device_name" msgid="4315604017399871828">"Туташкан түзмөк"</string>
@@ -688,9 +687,10 @@
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Бул өзгөрүү күчүнө кириши үчүн, түзмөктү өчүрүп күйгүзүңүз. Азыр же кийинчерээк өчүрүп күйгүзсөңүз болот."</string>
     <string name="media_transfer_wired_headphone_name" msgid="8698668536022665254">"Зымдуу гарнитура"</string>
     <string name="media_transfer_headphone_name" msgid="1131962659136578852">"Гарнитура"</string>
-    <string name="media_transfer_usb_speaker_name" msgid="4736537022543593896">"USB динамиги"</string>
+    <string name="media_transfer_usb_audio_name" msgid="1789292056757821355">"USB аудио"</string>
     <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"Микрофондун оюкчасы"</string>
-    <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"USB микрофон"</string>
+    <string name="media_transfer_usb_device_mic_name" msgid="7171789543226269822">"USB микрофон"</string>
+    <string name="media_transfer_bt_device_mic_name" msgid="1870669402238687618">"Bluetooth микрофону"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Күйгүзүү"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Өчүрүү"</string>
     <string name="carrier_network_change_mode" msgid="4257621815706644026">"Байланыш оператору өзгөртүлүүдө"</string>
diff --git a/packages/SettingsLib/res/values-lo/strings.xml b/packages/SettingsLib/res/values-lo/strings.xml
index 1d89e3e..0f83134 100644
--- a/packages/SettingsLib/res/values-lo/strings.xml
+++ b/packages/SettingsLib/res/values-lo/strings.xml
@@ -585,7 +585,6 @@
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"ຄອມພິວເຕີນີ້ (ພາຍໃນ)"</string>
     <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
     <skip />
-    <string name="media_transfer_internal_mic" msgid="797333824290228595">"ໄມໂຄຣໂຟນ (ພາຍໃນ)"</string>
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"ແທ່ນວາງລຳໂພງ"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"ອຸປະກອນພາຍນອກ"</string>
     <string name="media_transfer_default_device_name" msgid="4315604017399871828">"ອຸປະກອນທີ່ເຊື່ອມຕໍ່"</string>
@@ -688,9 +687,10 @@
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"ທ່ານຕ້ອງປິດເປີດອຸປະກອນຄືນໃໝ່ເພື່ອນຳໃຊ້ການປ່ຽນແປງນີ້. ປິດເປີດໃໝ່ດຽວນີ້ ຫຼື ຍົກເລີກ."</string>
     <string name="media_transfer_wired_headphone_name" msgid="8698668536022665254">"ຫູຟັງແບບມີສາຍ"</string>
     <string name="media_transfer_headphone_name" msgid="1131962659136578852">"ຫູຟັງ"</string>
-    <string name="media_transfer_usb_speaker_name" msgid="4736537022543593896">"ລຳໂພງ USB"</string>
+    <string name="media_transfer_usb_audio_name" msgid="1789292056757821355">"ສຽງ USB"</string>
     <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"ຊ່ອງສຽງໄມ"</string>
-    <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"ໄມ USB"</string>
+    <string name="media_transfer_usb_device_mic_name" msgid="7171789543226269822">"ໄມໂຄຣໂຟນ USB"</string>
+    <string name="media_transfer_bt_device_mic_name" msgid="1870669402238687618">"ໄມໂຄຣໂຟນ BT"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"ເປີດ"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"ປິດ"</string>
     <string name="carrier_network_change_mode" msgid="4257621815706644026">"ການປ່ຽນເຄືອຂ່າຍຜູ້ໃຫ້ບໍລິການ"</string>
diff --git a/packages/SettingsLib/res/values-lt/strings.xml b/packages/SettingsLib/res/values-lt/strings.xml
index 265eb9a..3a81c91 100644
--- a/packages/SettingsLib/res/values-lt/strings.xml
+++ b/packages/SettingsLib/res/values-lt/strings.xml
@@ -585,7 +585,6 @@
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"Šis kompiuteris (vidinis)"</string>
     <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
     <skip />
-    <string name="media_transfer_internal_mic" msgid="797333824290228595">"Mikrofonas (vidinis)"</string>
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Doko garsiakalbis"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Išorinis įrenginys"</string>
     <string name="media_transfer_default_device_name" msgid="4315604017399871828">"Prijungtas įrenginys"</string>
@@ -688,9 +687,10 @@
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Kad pakeitimas būtų pritaikytas, įrenginį reikia paleisti iš naujo. Dabar paleiskite iš naujo arba atšaukite."</string>
     <string name="media_transfer_wired_headphone_name" msgid="8698668536022665254">"Laidinės ausinės"</string>
     <string name="media_transfer_headphone_name" msgid="1131962659136578852">"Ausinės"</string>
-    <string name="media_transfer_usb_speaker_name" msgid="4736537022543593896">"USB garsiakalbis"</string>
+    <string name="media_transfer_usb_audio_name" msgid="1789292056757821355">"USB garsas"</string>
     <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"Mikrofono jungtis"</string>
-    <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"USB mikrofonas"</string>
+    <string name="media_transfer_usb_device_mic_name" msgid="7171789543226269822">"USB mikrofonas"</string>
+    <string name="media_transfer_bt_device_mic_name" msgid="1870669402238687618">"„Bluetooth“ mikrofonas"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Įjungta"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Išjungta"</string>
     <string name="carrier_network_change_mode" msgid="4257621815706644026">"Keičiamas operatoriaus tinklas"</string>
diff --git a/packages/SettingsLib/res/values-lv/strings.xml b/packages/SettingsLib/res/values-lv/strings.xml
index c24dafb..8e1f20e 100644
--- a/packages/SettingsLib/res/values-lv/strings.xml
+++ b/packages/SettingsLib/res/values-lv/strings.xml
@@ -585,7 +585,6 @@
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"Šī datora iekšējais skaļrunis"</string>
     <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
     <skip />
-    <string name="media_transfer_internal_mic" msgid="797333824290228595">"Mikrofons (iebūvētais)"</string>
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Doka skaļrunis"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Ārēja ierīce"</string>
     <string name="media_transfer_default_device_name" msgid="4315604017399871828">"Pievienotā ierīce"</string>
@@ -688,9 +687,10 @@
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Lai šīs izmaiņas tiktu piemērotas, nepieciešama ierīces atkārtota palaišana. Atkārtoti palaidiet to tūlīt vai atceliet izmaiņas."</string>
     <string name="media_transfer_wired_headphone_name" msgid="8698668536022665254">"Vadu austiņas"</string>
     <string name="media_transfer_headphone_name" msgid="1131962659136578852">"Austiņas"</string>
-    <string name="media_transfer_usb_speaker_name" msgid="4736537022543593896">"USB skaļrunis"</string>
+    <string name="media_transfer_usb_audio_name" msgid="1789292056757821355">"USB audio"</string>
     <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"Mikrofona ligzda"</string>
-    <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"USB mikrofons"</string>
+    <string name="media_transfer_usb_device_mic_name" msgid="7171789543226269822">"USB mikrofons"</string>
+    <string name="media_transfer_bt_device_mic_name" msgid="1870669402238687618">"Bluetooth mikrofons"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Ieslēgts"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Izslēgts"</string>
     <string name="carrier_network_change_mode" msgid="4257621815706644026">"Mobilo sakaru operatora tīkla mainīšana"</string>
diff --git a/packages/SettingsLib/res/values-mk/strings.xml b/packages/SettingsLib/res/values-mk/strings.xml
index ea9ff6c..66de2829 100644
--- a/packages/SettingsLib/res/values-mk/strings.xml
+++ b/packages/SettingsLib/res/values-mk/strings.xml
@@ -585,7 +585,6 @@
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"Овој компјуер (внатрешен)"</string>
     <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
     <skip />
-    <string name="media_transfer_internal_mic" msgid="797333824290228595">"Микрофон (внатрешен)"</string>
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Док со звучник"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Надворешен уред"</string>
     <string name="media_transfer_default_device_name" msgid="4315604017399871828">"Поврзан уред"</string>
@@ -688,9 +687,10 @@
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"За да се примени променава, уредот мора да се рестартира. Рестартирајте сега или откажете."</string>
     <string name="media_transfer_wired_headphone_name" msgid="8698668536022665254">"Жичени слушалки"</string>
     <string name="media_transfer_headphone_name" msgid="1131962659136578852">"Слушалка"</string>
-    <string name="media_transfer_usb_speaker_name" msgid="4736537022543593896">"USB-звучник"</string>
+    <string name="media_transfer_usb_audio_name" msgid="1789292056757821355">"USB-аудио"</string>
     <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"Приклучок за микрофон"</string>
-    <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"USB-микрофон"</string>
+    <string name="media_transfer_usb_device_mic_name" msgid="7171789543226269822">"USB-микрофон"</string>
+    <string name="media_transfer_bt_device_mic_name" msgid="1870669402238687618">"Микрофон со Bluetooth"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Вклучено"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Исклучено"</string>
     <string name="carrier_network_change_mode" msgid="4257621815706644026">"Променување на мрежата на операторот"</string>
diff --git a/packages/SettingsLib/res/values-ml/strings.xml b/packages/SettingsLib/res/values-ml/strings.xml
index 7af53aa..fe2a996 100644
--- a/packages/SettingsLib/res/values-ml/strings.xml
+++ b/packages/SettingsLib/res/values-ml/strings.xml
@@ -585,7 +585,6 @@
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"ഈ കമ്പ്യൂട്ടർ (ഇന്റേണൽ)"</string>
     <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
     <skip />
-    <string name="media_transfer_internal_mic" msgid="797333824290228595">"മൈക്രോഫോൺ (ഇന്റേണൽ)"</string>
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"ഡോക്ക് സ്‌പീക്കർ"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"ബാഹ്യ ഉപകരണം"</string>
     <string name="media_transfer_default_device_name" msgid="4315604017399871828">"കണക്‌റ്റ് ചെയ്‌ത ഉപകരണം"</string>
@@ -688,9 +687,10 @@
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"ഈ മാറ്റം ബാധകമാകുന്നതിന് നിങ്ങളുടെ ഉപകരണം റീബൂട്ട് ചെയ്യേണ്ടതുണ്ട്. ഇപ്പോൾ റീബൂട്ട് ചെയ്യുകയോ റദ്ദാക്കുകയോ ചെയ്യുക."</string>
     <string name="media_transfer_wired_headphone_name" msgid="8698668536022665254">"വയേർഡ് ഹെഡ്ഫോൺ"</string>
     <string name="media_transfer_headphone_name" msgid="1131962659136578852">"ഹെഡ്ഫോൺ"</string>
-    <string name="media_transfer_usb_speaker_name" msgid="4736537022543593896">"USB സ്‌പീക്കർ"</string>
+    <string name="media_transfer_usb_audio_name" msgid="1789292056757821355">"USB ഓഡിയോ"</string>
     <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"മൈക്ക് ജാക്ക്"</string>
-    <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"USB മൈക്ക്"</string>
+    <string name="media_transfer_usb_device_mic_name" msgid="7171789543226269822">"USB മൈക്രോഫോൺ"</string>
+    <string name="media_transfer_bt_device_mic_name" msgid="1870669402238687618">"BT മൈക്രോഫോൺ"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"ഓണാണ്"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"ഓഫാണ്"</string>
     <string name="carrier_network_change_mode" msgid="4257621815706644026">"കാരിയർ നെറ്റ്‌വർക്ക് മാറ്റൽ"</string>
diff --git a/packages/SettingsLib/res/values-mn/strings.xml b/packages/SettingsLib/res/values-mn/strings.xml
index 9fdbdc6..c9668f1 100644
--- a/packages/SettingsLib/res/values-mn/strings.xml
+++ b/packages/SettingsLib/res/values-mn/strings.xml
@@ -585,7 +585,6 @@
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"Энэ компьютер (дотоод)"</string>
     <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
     <skip />
-    <string name="media_transfer_internal_mic" msgid="797333824290228595">"Микрофон (дотоод)"</string>
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Суурилуулагчийн чанга яригч"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Гадаад төхөөрөмж"</string>
     <string name="media_transfer_default_device_name" msgid="4315604017399871828">"Холбогдсон төхөөрөмж"</string>
@@ -688,9 +687,10 @@
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Энэ өөрчлөлтийг хэрэгжүүлэхийн тулд таны төхөөрөмжийг дахин асаах ёстой. Одоо дахин асаах эсвэл цуцлана уу."</string>
     <string name="media_transfer_wired_headphone_name" msgid="8698668536022665254">"Утастай чихэвч"</string>
     <string name="media_transfer_headphone_name" msgid="1131962659136578852">"Чихэвч"</string>
-    <string name="media_transfer_usb_speaker_name" msgid="4736537022543593896">"USB чанга яригч"</string>
+    <string name="media_transfer_usb_audio_name" msgid="1789292056757821355">"USB аудио"</string>
     <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"Микрофоны чихэвчний оролт"</string>
-    <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"USB микрофон"</string>
+    <string name="media_transfer_usb_device_mic_name" msgid="7171789543226269822">"USB микрофон"</string>
+    <string name="media_transfer_bt_device_mic_name" msgid="1870669402238687618">"BT микрофон"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Асаах"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Унтраах"</string>
     <string name="carrier_network_change_mode" msgid="4257621815706644026">"Оператор компанийн сүлжээг өөрчилж байна"</string>
diff --git a/packages/SettingsLib/res/values-mr/strings.xml b/packages/SettingsLib/res/values-mr/strings.xml
index 581545d..600779d 100644
--- a/packages/SettingsLib/res/values-mr/strings.xml
+++ b/packages/SettingsLib/res/values-mr/strings.xml
@@ -585,7 +585,6 @@
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"हा काँप्युटर (अंतर्गत)"</string>
     <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
     <skip />
-    <string name="media_transfer_internal_mic" msgid="797333824290228595">"मायक्रोफोन (अंतर्गत)"</string>
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"डॉक स्पीकर"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"बाह्य डिव्हाइस"</string>
     <string name="media_transfer_default_device_name" msgid="4315604017399871828">"कनेक्ट केलेले डिव्हाइस"</string>
@@ -688,9 +687,10 @@
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"हा बदल लागू करण्यासाठी तुमचे डिव्हाइस रीबूट करणे आवश्यक आहे. आता रीबूट करा किंवा रद्द करा."</string>
     <string name="media_transfer_wired_headphone_name" msgid="8698668536022665254">"वायर्ड हेडफोन"</string>
     <string name="media_transfer_headphone_name" msgid="1131962659136578852">"हेडफोन"</string>
-    <string name="media_transfer_usb_speaker_name" msgid="4736537022543593896">"USB स्पीकर"</string>
+    <string name="media_transfer_usb_audio_name" msgid="1789292056757821355">"USB ऑडिओ"</string>
     <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"माइक जॅक"</string>
-    <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"USB माइक"</string>
+    <string name="media_transfer_usb_device_mic_name" msgid="7171789543226269822">"USB मायक्रोफोन"</string>
+    <string name="media_transfer_bt_device_mic_name" msgid="1870669402238687618">"BT मायक्रोफोन"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"सुरू करा"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"बंद करा"</string>
     <string name="carrier_network_change_mode" msgid="4257621815706644026">"वाहक नेटवर्क बदलत आहे"</string>
diff --git a/packages/SettingsLib/res/values-ms/strings.xml b/packages/SettingsLib/res/values-ms/strings.xml
index 7990e04..d4eb1ba 100644
--- a/packages/SettingsLib/res/values-ms/strings.xml
+++ b/packages/SettingsLib/res/values-ms/strings.xml
@@ -585,7 +585,6 @@
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"Komputer ini (dalaman)"</string>
     <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
     <skip />
-    <string name="media_transfer_internal_mic" msgid="797333824290228595">"Mikrofon (dalaman)"</string>
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Pembesar suara dok"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Peranti Luar"</string>
     <string name="media_transfer_default_device_name" msgid="4315604017399871828">"Peranti yang disambungkan"</string>
@@ -688,9 +687,10 @@
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Peranti anda mesti dibut semula supaya perubahan ini berlaku. But semula sekarang atau batalkan."</string>
     <string name="media_transfer_wired_headphone_name" msgid="8698668536022665254">"Fon kepala berwayar"</string>
     <string name="media_transfer_headphone_name" msgid="1131962659136578852">"Fon kepala"</string>
-    <string name="media_transfer_usb_speaker_name" msgid="4736537022543593896">"Pembesar suara USB"</string>
+    <string name="media_transfer_usb_audio_name" msgid="1789292056757821355">"Audio USB"</string>
     <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"Bicu mikrofon"</string>
-    <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"Mikrofon USB"</string>
+    <string name="media_transfer_usb_device_mic_name" msgid="7171789543226269822">"Mikrofon USB"</string>
+    <string name="media_transfer_bt_device_mic_name" msgid="1870669402238687618">"Mikrofon BT"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Hidup"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Mati"</string>
     <string name="carrier_network_change_mode" msgid="4257621815706644026">"Rangkaian pembawa berubah"</string>
diff --git a/packages/SettingsLib/res/values-my/strings.xml b/packages/SettingsLib/res/values-my/strings.xml
index 8fbc8bd..92f9cbb 100644
--- a/packages/SettingsLib/res/values-my/strings.xml
+++ b/packages/SettingsLib/res/values-my/strings.xml
@@ -376,7 +376,7 @@
     <string name="strict_mode_summary" msgid="1838248687233554654">"အက်ပ်လုပ်ဆောင်မှု ရှည်ကြာလျှင် စကရင်ပြန်စသည်"</string>
     <string name="pointer_location" msgid="7516929526199520173">"မြား၏တည်နေရာ"</string>
     <string name="pointer_location_summary" msgid="957120116989798464">"လက်ရှိထိတွေ့မှုဒေတာကို ဖန်သားပေါ်တွင်ထပ်၍ ပြသသည်"</string>
-    <string name="show_touches" msgid="8437666942161289025">"တို့ခြင်းများကို ပြပါ"</string>
+    <string name="show_touches" msgid="8437666942161289025">"တို့ချက်များ ပြရန်"</string>
     <string name="show_touches_summary" msgid="3692861665994502193">"တို့ခြင်းများအတွက် အမြင်ဖြင့် တုံ့ပြန်မှုပြသည်"</string>
     <string name="show_key_presses" msgid="6360141722735900214">"ကီးနှိပ်မှုများ ပြပါ"</string>
     <string name="show_key_presses_summary" msgid="725387457373015024">"ပကတိကီးနှိပ်မှုများအတွက် ရုပ်မြင်အကြံပြုချက် ပြပါ"</string>
@@ -585,7 +585,6 @@
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"ဤကွန်ပျူတာ (စက်တွင်း)"</string>
     <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
     <skip />
-    <string name="media_transfer_internal_mic" msgid="797333824290228595">"မိုက်ခရိုဖုန်း (စက်တွင်း)"</string>
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"အထိုင် စပီကာ"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"ပြင်ပစက်"</string>
     <string name="media_transfer_default_device_name" msgid="4315604017399871828">"ချိတ်ဆက်ကိရိယာ"</string>
@@ -688,9 +687,10 @@
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"ဤအပြောင်းအလဲ ထည့်သွင်းရန် သင့်စက်ကို ပြန်လည်စတင်ရမည်။ ယခု ပြန်လည်စတင်ပါ သို့မဟုတ် ပယ်ဖျက်ပါ။"</string>
     <string name="media_transfer_wired_headphone_name" msgid="8698668536022665254">"ကြိုးတပ်နားကြပ်"</string>
     <string name="media_transfer_headphone_name" msgid="1131962659136578852">"နားကြပ်"</string>
-    <string name="media_transfer_usb_speaker_name" msgid="4736537022543593896">"USB စပီကာ"</string>
+    <string name="media_transfer_usb_audio_name" msgid="1789292056757821355">"USB အသံ"</string>
     <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"မိုက်ဂျက်ပင်"</string>
-    <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"USB မိုက်"</string>
+    <string name="media_transfer_usb_device_mic_name" msgid="7171789543226269822">"USB မိုက်ခရိုဖုန်း"</string>
+    <string name="media_transfer_bt_device_mic_name" msgid="1870669402238687618">"BT မိုက်ခရိုဖုန်း"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"ဖွင့်"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"ပိတ်"</string>
     <string name="carrier_network_change_mode" msgid="4257621815706644026">"ဝန်ဆောင်မှုပေးသူ ကွန်ရက် ပြောင်းလဲနေသည်။"</string>
diff --git a/packages/SettingsLib/res/values-nb/strings.xml b/packages/SettingsLib/res/values-nb/strings.xml
index 569b900..83f40af 100644
--- a/packages/SettingsLib/res/values-nb/strings.xml
+++ b/packages/SettingsLib/res/values-nb/strings.xml
@@ -585,7 +585,6 @@
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"Denne datamaskinen (intern)"</string>
     <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
     <skip />
-    <string name="media_transfer_internal_mic" msgid="797333824290228595">"Mikrofon (intern)"</string>
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Dokkhøyttaler"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Ekstern enhet"</string>
     <string name="media_transfer_default_device_name" msgid="4315604017399871828">"Tilkoblet enhet"</string>
@@ -688,9 +687,10 @@
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Enheten din må startes på nytt for at denne endringen skal tre i kraft. Start på nytt nå eller avbryt."</string>
     <string name="media_transfer_wired_headphone_name" msgid="8698668536022665254">"Hodetelefoner med kabel"</string>
     <string name="media_transfer_headphone_name" msgid="1131962659136578852">"Hodetelefoner"</string>
-    <string name="media_transfer_usb_speaker_name" msgid="4736537022543593896">"USB-høyttaler"</string>
+    <string name="media_transfer_usb_audio_name" msgid="1789292056757821355">"USB-lyd"</string>
     <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"Mikrofonkontakt"</string>
-    <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"USB-mikrofon"</string>
+    <string name="media_transfer_usb_device_mic_name" msgid="7171789543226269822">"USB-mikrofon"</string>
+    <string name="media_transfer_bt_device_mic_name" msgid="1870669402238687618">"BT-mikrofon"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"På"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Av"</string>
     <string name="carrier_network_change_mode" msgid="4257621815706644026">"Bytting av operatørnettverk"</string>
diff --git a/packages/SettingsLib/res/values-ne/strings.xml b/packages/SettingsLib/res/values-ne/strings.xml
index 916aba9..d9d12db 100644
--- a/packages/SettingsLib/res/values-ne/strings.xml
+++ b/packages/SettingsLib/res/values-ne/strings.xml
@@ -585,7 +585,6 @@
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"यो कम्प्युटर (आन्तरिक)"</string>
     <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
     <skip />
-    <string name="media_transfer_internal_mic" msgid="797333824290228595">"माइक्रोफोन (आन्तरिक)"</string>
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"डक स्पिकर"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"बाह्य डिभाइस"</string>
     <string name="media_transfer_default_device_name" msgid="4315604017399871828">"कनेक्ट गरिएको डिभाइस"</string>
@@ -688,9 +687,10 @@
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"यो परिवर्तन लागू गर्न तपाईंको यन्त्र अनिवार्य रूपमा रिबुट गर्नु पर्छ। अहिले रिबुट गर्नुहोस् वा रद्द गर्नुहोस्।"</string>
     <string name="media_transfer_wired_headphone_name" msgid="8698668536022665254">"तारयुक्त हेडफोन"</string>
     <string name="media_transfer_headphone_name" msgid="1131962659136578852">"हेडफोन"</string>
-    <string name="media_transfer_usb_speaker_name" msgid="4736537022543593896">"USB स्पिकर"</string>
+    <string name="media_transfer_usb_audio_name" msgid="1789292056757821355">"USB अडियो"</string>
     <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"माइकको ज्याक"</string>
-    <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"USB माइक"</string>
+    <string name="media_transfer_usb_device_mic_name" msgid="7171789543226269822">"USB माइक्रोफोन"</string>
+    <string name="media_transfer_bt_device_mic_name" msgid="1870669402238687618">"BT माइक्रोफोन"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"अन छ"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"अफ छ"</string>
     <string name="carrier_network_change_mode" msgid="4257621815706644026">"सेवा प्रदायकको नेटवर्क परिवर्तन गर्ने आइकन"</string>
diff --git a/packages/SettingsLib/res/values-nl/strings.xml b/packages/SettingsLib/res/values-nl/strings.xml
index 78dfd35..f5b5409 100644
--- a/packages/SettingsLib/res/values-nl/strings.xml
+++ b/packages/SettingsLib/res/values-nl/strings.xml
@@ -585,7 +585,6 @@
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"Deze computer (intern)"</string>
     <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
     <skip />
-    <string name="media_transfer_internal_mic" msgid="797333824290228595">"Microfoon (intern)"</string>
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Dockspeaker"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Extern apparaat"</string>
     <string name="media_transfer_default_device_name" msgid="4315604017399871828">"Verbonden apparaat"</string>
@@ -688,9 +687,10 @@
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Je apparaat moet opnieuw worden opgestart om deze wijziging toe te passen. Start nu opnieuw op of annuleer de wijziging."</string>
     <string name="media_transfer_wired_headphone_name" msgid="8698668536022665254">"Bedrade koptelefoon"</string>
     <string name="media_transfer_headphone_name" msgid="1131962659136578852">"Koptelefoon"</string>
-    <string name="media_transfer_usb_speaker_name" msgid="4736537022543593896">"USB-speaker"</string>
+    <string name="media_transfer_usb_audio_name" msgid="1789292056757821355">"USB-audio"</string>
     <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"Microfoonaansluiting"</string>
-    <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"USB-microfoon"</string>
+    <string name="media_transfer_usb_device_mic_name" msgid="7171789543226269822">"USB-microfoon"</string>
+    <string name="media_transfer_bt_device_mic_name" msgid="1870669402238687618">"BT-microfoon"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Aan"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Uit"</string>
     <string name="carrier_network_change_mode" msgid="4257621815706644026">"Netwerk van provider wordt gewijzigd"</string>
diff --git a/packages/SettingsLib/res/values-or/strings.xml b/packages/SettingsLib/res/values-or/strings.xml
index c2439f9..508d2fc 100644
--- a/packages/SettingsLib/res/values-or/strings.xml
+++ b/packages/SettingsLib/res/values-or/strings.xml
@@ -585,7 +585,6 @@
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"ଏହି କମ୍ପ୍ୟୁଟର (ଇଣ୍ଟର୍ନଲ)"</string>
     <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
     <skip />
-    <string name="media_transfer_internal_mic" msgid="797333824290228595">"ମାଇକ୍ରୋଫୋନ (ଇଣ୍ଟର୍ନଲ)"</string>
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"ଡକ ସ୍ପିକର"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"ଏକ୍ସଟର୍ନଲ ଡିଭାଇସ"</string>
     <string name="media_transfer_default_device_name" msgid="4315604017399871828">"କନେକ୍ଟ କରାଯାଇଥିବା ଡିଭାଇସ"</string>
@@ -688,9 +687,10 @@
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"ଏହି ପରିବର୍ତ୍ତନ ଲାଗୁ କରିବା ପାଇଁ ଆପଣଙ୍କ ଡିଭାଇସକୁ ନିଶ୍ଚିତ ରୂପେ ରିବୁଟ୍ କରାଯିବା ଆବଶ୍ୟକ। ବର୍ତ୍ତମାନ ରିବୁଟ୍ କରନ୍ତୁ କିମ୍ବା ବାତିଲ କରନ୍ତୁ।"</string>
     <string name="media_transfer_wired_headphone_name" msgid="8698668536022665254">"ତାରଯୁକ୍ତ ହେଡଫୋନ"</string>
     <string name="media_transfer_headphone_name" msgid="1131962659136578852">"ହେଡଫୋନ"</string>
-    <string name="media_transfer_usb_speaker_name" msgid="4736537022543593896">"USB ସ୍ପିକର"</string>
+    <string name="media_transfer_usb_audio_name" msgid="1789292056757821355">"USB ଅଡିଓ"</string>
     <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"ମାଇକ ଜେକ"</string>
-    <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"USB ମାଇକ"</string>
+    <string name="media_transfer_usb_device_mic_name" msgid="7171789543226269822">"USB ମାଇକ୍ରୋଫୋନ"</string>
+    <string name="media_transfer_bt_device_mic_name" msgid="1870669402238687618">"BT ମାଇକ୍ରୋଫୋନ"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"ଚାଲୁ ଅଛି"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"ବନ୍ଦ ଅଛି"</string>
     <string name="carrier_network_change_mode" msgid="4257621815706644026">"କେରିଅର୍‍ ନେଟ୍‌ୱର୍କ ବଦଳୁଛି"</string>
diff --git a/packages/SettingsLib/res/values-pa/strings.xml b/packages/SettingsLib/res/values-pa/strings.xml
index 4a4f924..ebff08d 100644
--- a/packages/SettingsLib/res/values-pa/strings.xml
+++ b/packages/SettingsLib/res/values-pa/strings.xml
@@ -585,7 +585,6 @@
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"ਇਸ ਕੰਪਿਊਟਰ \'ਤੇ (ਅੰਦਰੂਨੀ)"</string>
     <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
     <skip />
-    <string name="media_transfer_internal_mic" msgid="797333824290228595">"ਮਾਈਕ੍ਰੋਫ਼ੋਨ (ਅੰਦਰੂਨੀ)"</string>
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"ਡੌਕ ਸਪੀਕਰ"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"ਬਾਹਰੀ ਡੀਵਾਈਸ"</string>
     <string name="media_transfer_default_device_name" msgid="4315604017399871828">"ਕਨੈਕਟ ਕੀਤਾ ਡੀਵਾਈਸ"</string>
@@ -688,9 +687,10 @@
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"ਇਸ ਤਬਦੀਲੀ ਨੂੰ ਲਾਗੂ ਕਰਨ ਲਈ ਤੁਹਾਡੇ ਡੀਵਾਈਸ ਨੂੰ ਰੀਬੂਟ ਕਰਨਾ ਲਾਜ਼ਮੀ ਹੈ। ਹੁਣੇ ਰੀਬੂਟ ਕਰੋ ਜਾਂ ਰੱਦ ਕਰੋ।"</string>
     <string name="media_transfer_wired_headphone_name" msgid="8698668536022665254">"ਤਾਰ ਵਾਲੇ ਹੈੱਡਫ਼ੋਨ"</string>
     <string name="media_transfer_headphone_name" msgid="1131962659136578852">"ਹੈੱਡਫ਼ੋਨ"</string>
-    <string name="media_transfer_usb_speaker_name" msgid="4736537022543593896">"USB ਸਪੀਕਰ"</string>
+    <string name="media_transfer_usb_audio_name" msgid="1789292056757821355">"USB ਆਡੀਓ"</string>
     <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"ਮਾਈਕ ਜੈਕ"</string>
-    <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"USB ਮਾਈਕ"</string>
+    <string name="media_transfer_usb_device_mic_name" msgid="7171789543226269822">"USB ਮਾਈਕ੍ਰੋਫ਼ੋਨ"</string>
+    <string name="media_transfer_bt_device_mic_name" msgid="1870669402238687618">"BT ਮਾਈਕ੍ਰੋਫ਼ੋਨ"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"ਚਾਲੂ"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"ਬੰਦ"</string>
     <string name="carrier_network_change_mode" msgid="4257621815706644026">"ਕੈਰੀਅਰ ਨੈੱਟਵਰਕ ਦੀ ਬਦਲੀ"</string>
diff --git a/packages/SettingsLib/res/values-pl/strings.xml b/packages/SettingsLib/res/values-pl/strings.xml
index bb8fe2e..e5cd6f0 100644
--- a/packages/SettingsLib/res/values-pl/strings.xml
+++ b/packages/SettingsLib/res/values-pl/strings.xml
@@ -585,7 +585,6 @@
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"Ten komputer (wewnętrzny)"</string>
     <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
     <skip />
-    <string name="media_transfer_internal_mic" msgid="797333824290228595">"Mikrofon (wewnętrzny)"</string>
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Głośnik ze stacją dokującą"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Urządzenie zewnętrzne"</string>
     <string name="media_transfer_default_device_name" msgid="4315604017399871828">"Połączone urządzenie"</string>
@@ -688,9 +687,10 @@
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Wprowadzenie zmiany wymaga ponownego uruchomienia urządzenia. Uruchom ponownie teraz lub anuluj."</string>
     <string name="media_transfer_wired_headphone_name" msgid="8698668536022665254">"Słuchawki przewodowe"</string>
     <string name="media_transfer_headphone_name" msgid="1131962659136578852">"Słuchawki"</string>
-    <string name="media_transfer_usb_speaker_name" msgid="4736537022543593896">"Głośnik USB"</string>
+    <string name="media_transfer_usb_audio_name" msgid="1789292056757821355">"Dźwięk przez USB"</string>
     <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"Gniazdo mikrofonu"</string>
-    <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"Mikrofon USB"</string>
+    <string name="media_transfer_usb_device_mic_name" msgid="7171789543226269822">"Mikrofon USB"</string>
+    <string name="media_transfer_bt_device_mic_name" msgid="1870669402238687618">"Mikrofon Bluetooth"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Włączono"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Wyłączono"</string>
     <string name="carrier_network_change_mode" msgid="4257621815706644026">"Zmiana sieci operatora"</string>
diff --git a/packages/SettingsLib/res/values-pt-rBR/strings.xml b/packages/SettingsLib/res/values-pt-rBR/strings.xml
index e286643..7bc0db9 100644
--- a/packages/SettingsLib/res/values-pt-rBR/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rBR/strings.xml
@@ -687,11 +687,10 @@
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"É necessário reinicializar o dispositivo para que a mudança seja aplicada. Faça isso agora ou cancele."</string>
     <string name="media_transfer_wired_headphone_name" msgid="8698668536022665254">"Fones de ouvido com fio"</string>
     <string name="media_transfer_headphone_name" msgid="1131962659136578852">"Fone de ouvido"</string>
-    <!-- no translation found for media_transfer_usb_audio_name (1789292056757821355) -->
-    <skip />
+    <string name="media_transfer_usb_audio_name" msgid="1789292056757821355">"Áudio USB"</string>
     <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"Entrada para microfone"</string>
-    <!-- no translation found for media_transfer_usb_device_mic_name (7171789543226269822) -->
-    <skip />
+    <string name="media_transfer_usb_device_mic_name" msgid="7171789543226269822">"Microfone USB"</string>
+    <string name="media_transfer_bt_device_mic_name" msgid="1870669402238687618">"Microfone Bluetooth"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Ativado"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Desativado"</string>
     <string name="carrier_network_change_mode" msgid="4257621815706644026">"Alteração de rede da operadora"</string>
diff --git a/packages/SettingsLib/res/values-pt-rPT/strings.xml b/packages/SettingsLib/res/values-pt-rPT/strings.xml
index f489d91..94a21c8 100644
--- a/packages/SettingsLib/res/values-pt-rPT/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rPT/strings.xml
@@ -585,7 +585,6 @@
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"Este computador (interno)"</string>
     <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
     <skip />
-    <string name="media_transfer_internal_mic" msgid="797333824290228595">"Microfone (interno)"</string>
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Altifalante estação carregamento"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Dispositivo externo"</string>
     <string name="media_transfer_default_device_name" msgid="4315604017399871828">"Dispositivo associado"</string>
@@ -688,9 +687,10 @@
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"É necessário reiniciar o dispositivo para aplicar esta alteração. Reinicie agora ou cancele."</string>
     <string name="media_transfer_wired_headphone_name" msgid="8698668536022665254">"Auscultadores com fios"</string>
     <string name="media_transfer_headphone_name" msgid="1131962659136578852">"Auscultadores"</string>
-    <string name="media_transfer_usb_speaker_name" msgid="4736537022543593896">"Altifalante USB"</string>
+    <string name="media_transfer_usb_audio_name" msgid="1789292056757821355">"Áudio USB"</string>
     <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"Entrada para microfone"</string>
-    <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"Microfone USB"</string>
+    <string name="media_transfer_usb_device_mic_name" msgid="7171789543226269822">"Microfone USB"</string>
+    <string name="media_transfer_bt_device_mic_name" msgid="1870669402238687618">"Microfone BT"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Ligado"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Desligado"</string>
     <string name="carrier_network_change_mode" msgid="4257621815706644026">"Rede do operador em mudança."</string>
diff --git a/packages/SettingsLib/res/values-pt/strings.xml b/packages/SettingsLib/res/values-pt/strings.xml
index 7f5bb0f..7bc0db9 100644
--- a/packages/SettingsLib/res/values-pt/strings.xml
+++ b/packages/SettingsLib/res/values-pt/strings.xml
@@ -585,7 +585,6 @@
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"Este computador (interno)"</string>
     <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
     <skip />
-    <string name="media_transfer_internal_mic" msgid="797333824290228595">"Microfone (interno)"</string>
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Alto-falante da base"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Dispositivo externo"</string>
     <string name="media_transfer_default_device_name" msgid="4315604017399871828">"Dispositivo conectado"</string>
@@ -688,9 +687,10 @@
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"É necessário reinicializar o dispositivo para que a mudança seja aplicada. Faça isso agora ou cancele."</string>
     <string name="media_transfer_wired_headphone_name" msgid="8698668536022665254">"Fones de ouvido com fio"</string>
     <string name="media_transfer_headphone_name" msgid="1131962659136578852">"Fone de ouvido"</string>
-    <string name="media_transfer_usb_speaker_name" msgid="4736537022543593896">"Alto-falante USB"</string>
+    <string name="media_transfer_usb_audio_name" msgid="1789292056757821355">"Áudio USB"</string>
     <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"Entrada para microfone"</string>
-    <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"Microfone USB"</string>
+    <string name="media_transfer_usb_device_mic_name" msgid="7171789543226269822">"Microfone USB"</string>
+    <string name="media_transfer_bt_device_mic_name" msgid="1870669402238687618">"Microfone Bluetooth"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Ativado"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Desativado"</string>
     <string name="carrier_network_change_mode" msgid="4257621815706644026">"Alteração de rede da operadora"</string>
diff --git a/packages/SettingsLib/res/values-ro/strings.xml b/packages/SettingsLib/res/values-ro/strings.xml
index f79c2e1..47ae7ef 100644
--- a/packages/SettingsLib/res/values-ro/strings.xml
+++ b/packages/SettingsLib/res/values-ro/strings.xml
@@ -585,7 +585,6 @@
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"Acest computer (intern)"</string>
     <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
     <skip />
-    <string name="media_transfer_internal_mic" msgid="797333824290228595">"Microfon (intern)"</string>
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Difuzorul dispozitivului de andocare"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Dispozitiv extern"</string>
     <string name="media_transfer_default_device_name" msgid="4315604017399871828">"Dispozitiv conectat"</string>
@@ -688,9 +687,10 @@
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Pentru ca modificarea să se aplice, trebuie să repornești dispozitivul. Repornește-l acum sau anulează."</string>
     <string name="media_transfer_wired_headphone_name" msgid="8698668536022665254">"Căști cu fir"</string>
     <string name="media_transfer_headphone_name" msgid="1131962659136578852">"Căști"</string>
-    <string name="media_transfer_usb_speaker_name" msgid="4736537022543593896">"Difuzor USB"</string>
+    <string name="media_transfer_usb_audio_name" msgid="1789292056757821355">"Audio USB"</string>
     <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"Mufă pentru microfon"</string>
-    <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"Microfon USB"</string>
+    <string name="media_transfer_usb_device_mic_name" msgid="7171789543226269822">"Microfon USB"</string>
+    <string name="media_transfer_bt_device_mic_name" msgid="1870669402238687618">"Microfon BT"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Activat"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Dezactivat"</string>
     <string name="carrier_network_change_mode" msgid="4257621815706644026">"Se schimbă rețeaua operatorului"</string>
diff --git a/packages/SettingsLib/res/values-ru/strings.xml b/packages/SettingsLib/res/values-ru/strings.xml
index 1cdef05..1342321 100644
--- a/packages/SettingsLib/res/values-ru/strings.xml
+++ b/packages/SettingsLib/res/values-ru/strings.xml
@@ -585,7 +585,6 @@
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"Встроенный динамик компьютера"</string>
     <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
     <skip />
-    <string name="media_transfer_internal_mic" msgid="797333824290228595">"Микрофон (встроенный)"</string>
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Колонка с док-станцией"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Внешнее устройство"</string>
     <string name="media_transfer_default_device_name" msgid="4315604017399871828">"Подключенное устройство"</string>
@@ -688,9 +687,10 @@
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Чтобы изменение вступило в силу, необходимо перезапустить устройство. Вы можете сделать это сейчас или позже."</string>
     <string name="media_transfer_wired_headphone_name" msgid="8698668536022665254">"Проводные наушники"</string>
     <string name="media_transfer_headphone_name" msgid="1131962659136578852">"Наушники"</string>
-    <string name="media_transfer_usb_speaker_name" msgid="4736537022543593896">"USB-колонка"</string>
+    <string name="media_transfer_usb_audio_name" msgid="1789292056757821355">"USB-аудиоустройство"</string>
     <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"Микрофонный разъем"</string>
-    <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"USB-микрофон"</string>
+    <string name="media_transfer_usb_device_mic_name" msgid="7171789543226269822">"USB-микрофон"</string>
+    <string name="media_transfer_bt_device_mic_name" msgid="1870669402238687618">"Bluetooth-микрофон"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Вкл."</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Выкл."</string>
     <string name="carrier_network_change_mode" msgid="4257621815706644026">"Сменить сеть"</string>
diff --git a/packages/SettingsLib/res/values-si/strings.xml b/packages/SettingsLib/res/values-si/strings.xml
index 980f9c8..be0356a 100644
--- a/packages/SettingsLib/res/values-si/strings.xml
+++ b/packages/SettingsLib/res/values-si/strings.xml
@@ -585,7 +585,6 @@
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"මෙම පරිගණකය (අභ්‍යන්තර)"</string>
     <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
     <skip />
-    <string name="media_transfer_internal_mic" msgid="797333824290228595">"මයික්‍රෆෝනය (අභ්‍යන්තර)"</string>
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"ඩොක් ස්පීකරය"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"බාහිර උපාංගය"</string>
     <string name="media_transfer_default_device_name" msgid="4315604017399871828">"සම්බන්ධ කළ උපාංගය"</string>
@@ -688,9 +687,10 @@
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"මෙම වෙනස යෙදීමට ඔබේ උපාංගය නැවත පණ ගැන්විය යුතුය. දැන් නැවත පණ ගන්වන්න හෝ අවලංගු කරන්න."</string>
     <string name="media_transfer_wired_headphone_name" msgid="8698668536022665254">"රැහැන්ගත හෙඩ්ෆෝන්"</string>
     <string name="media_transfer_headphone_name" msgid="1131962659136578852">"හෙඩ්ෆෝන්"</string>
-    <string name="media_transfer_usb_speaker_name" msgid="4736537022543593896">"USB ස්පීකරය"</string>
+    <string name="media_transfer_usb_audio_name" msgid="1789292056757821355">"USB ශ්‍රව්‍ය"</string>
     <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"මයික් ජැක්කුව"</string>
-    <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"USB මයික්"</string>
+    <string name="media_transfer_usb_device_mic_name" msgid="7171789543226269822">"USB මයික්‍රෆෝනය"</string>
+    <string name="media_transfer_bt_device_mic_name" msgid="1870669402238687618">"BT මයික්‍රෆෝනය"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"ක්‍රියාත්මකයි"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"ක්‍රියාවිරහිතයි"</string>
     <string name="carrier_network_change_mode" msgid="4257621815706644026">"වාහක ජාලය වෙනස් වෙමින්"</string>
diff --git a/packages/SettingsLib/res/values-sk/strings.xml b/packages/SettingsLib/res/values-sk/strings.xml
index b172649..e3a8a8c 100644
--- a/packages/SettingsLib/res/values-sk/strings.xml
+++ b/packages/SettingsLib/res/values-sk/strings.xml
@@ -585,7 +585,6 @@
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"Tento počítač (interný)"</string>
     <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
     <skip />
-    <string name="media_transfer_internal_mic" msgid="797333824290228595">"Mikrofón (vnútorný)"</string>
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Reproduktor doku"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Externé zariadenie"</string>
     <string name="media_transfer_default_device_name" msgid="4315604017399871828">"Pripojené zariadenie"</string>
@@ -688,9 +687,10 @@
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Zmena sa prejaví až po reštarte zariadenia. Môžete ho teraz reštartovať alebo akciu zrušiť."</string>
     <string name="media_transfer_wired_headphone_name" msgid="8698668536022665254">"Slúchadlá s káblom"</string>
     <string name="media_transfer_headphone_name" msgid="1131962659136578852">"Slúchadlá"</string>
-    <string name="media_transfer_usb_speaker_name" msgid="4736537022543593896">"Reproduktor s rozhraním USB"</string>
+    <string name="media_transfer_usb_audio_name" msgid="1789292056757821355">"Zvuk cez USB"</string>
     <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"Konektor mikrofónu"</string>
-    <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"Mikrofón USB"</string>
+    <string name="media_transfer_usb_device_mic_name" msgid="7171789543226269822">"Mikrofón s rozhraním USB"</string>
+    <string name="media_transfer_bt_device_mic_name" msgid="1870669402238687618">"Mikrofón Bluetooth"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Zapnúť"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Vypnúť"</string>
     <string name="carrier_network_change_mode" msgid="4257621815706644026">"Mení sa sieť operátora"</string>
diff --git a/packages/SettingsLib/res/values-sl/strings.xml b/packages/SettingsLib/res/values-sl/strings.xml
index 2ee1241..717e7baf 100644
--- a/packages/SettingsLib/res/values-sl/strings.xml
+++ b/packages/SettingsLib/res/values-sl/strings.xml
@@ -585,7 +585,6 @@
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"Ta računalnik (notranji)"</string>
     <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
     <skip />
-    <string name="media_transfer_internal_mic" msgid="797333824290228595">"Mikrofon (notranji)"</string>
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Zvočnik nosilca"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Zunanja naprava"</string>
     <string name="media_transfer_default_device_name" msgid="4315604017399871828">"Povezana naprava"</string>
@@ -688,9 +687,10 @@
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Napravo je treba znova zagnati, da bo ta sprememba uveljavljena. Znova zaženite zdaj ali prekličite."</string>
     <string name="media_transfer_wired_headphone_name" msgid="8698668536022665254">"Žične slušalke"</string>
     <string name="media_transfer_headphone_name" msgid="1131962659136578852">"Slušalke"</string>
-    <string name="media_transfer_usb_speaker_name" msgid="4736537022543593896">"Zvočnik USB"</string>
+    <string name="media_transfer_usb_audio_name" msgid="1789292056757821355">"Zvok USB"</string>
     <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"Vtič za mikrofon"</string>
-    <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"Mikrofon USB"</string>
+    <string name="media_transfer_usb_device_mic_name" msgid="7171789543226269822">"Mikrofon USB"</string>
+    <string name="media_transfer_bt_device_mic_name" msgid="1870669402238687618">"Mikrofon Bluetooth"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Vklop"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Izklop"</string>
     <string name="carrier_network_change_mode" msgid="4257621815706644026">"Spreminjanje omrežja operaterja"</string>
diff --git a/packages/SettingsLib/res/values-sq/strings.xml b/packages/SettingsLib/res/values-sq/strings.xml
index 7c21063..97e6c7d 100644
--- a/packages/SettingsLib/res/values-sq/strings.xml
+++ b/packages/SettingsLib/res/values-sq/strings.xml
@@ -585,7 +585,6 @@
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"Ky kompjuter (i brendshëm)"</string>
     <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
     <skip />
-    <string name="media_transfer_internal_mic" msgid="797333824290228595">"Mikrofoni (i brendshëm)"</string>
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Altoparlanti i stacionit"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Pajisja e jashtme"</string>
     <string name="media_transfer_default_device_name" msgid="4315604017399871828">"Pajisja e lidhur"</string>
@@ -688,9 +687,10 @@
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Pajisja jote duhet të riniset që ky ndryshim të zbatohet. Rinise tani ose anuloje."</string>
     <string name="media_transfer_wired_headphone_name" msgid="8698668536022665254">"Kufje me tela"</string>
     <string name="media_transfer_headphone_name" msgid="1131962659136578852">"Kufje"</string>
-    <string name="media_transfer_usb_speaker_name" msgid="4736537022543593896">"Altoparlant me USB"</string>
+    <string name="media_transfer_usb_audio_name" msgid="1789292056757821355">"Pajisja audio me USB"</string>
     <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"Fisha e mikrofonit"</string>
-    <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"Mikrofoni me USB"</string>
+    <string name="media_transfer_usb_device_mic_name" msgid="7171789543226269822">"Mikrofoni me USB"</string>
+    <string name="media_transfer_bt_device_mic_name" msgid="1870669402238687618">"Mikrofoni me Bluetooth"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Aktive"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Joaktive"</string>
     <string name="carrier_network_change_mode" msgid="4257621815706644026">"Rrjeti i operatorit celular po ndryshohet"</string>
diff --git a/packages/SettingsLib/res/values-sr/strings.xml b/packages/SettingsLib/res/values-sr/strings.xml
index 34ccdaf..3cf73a7 100644
--- a/packages/SettingsLib/res/values-sr/strings.xml
+++ b/packages/SettingsLib/res/values-sr/strings.xml
@@ -585,7 +585,6 @@
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"Овај рачунар (интерно)"</string>
     <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
     <skip />
-    <string name="media_transfer_internal_mic" msgid="797333824290228595">"Микрофон (интерни)"</string>
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Звучник базне станице"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Спољни уређај"</string>
     <string name="media_transfer_default_device_name" msgid="4315604017399871828">"Повезани уређај"</string>
@@ -688,9 +687,10 @@
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Морате да рестартујете уређај да би се ова промена применила. Рестартујте га одмах или откажите."</string>
     <string name="media_transfer_wired_headphone_name" msgid="8698668536022665254">"Жичане слушалице"</string>
     <string name="media_transfer_headphone_name" msgid="1131962659136578852">"Слушалице"</string>
-    <string name="media_transfer_usb_speaker_name" msgid="4736537022543593896">"USB звучник"</string>
+    <string name="media_transfer_usb_audio_name" msgid="1789292056757821355">"USB аудио"</string>
     <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"Утикач за микрофон"</string>
-    <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"USB микрофон"</string>
+    <string name="media_transfer_usb_device_mic_name" msgid="7171789543226269822">"USB микрофон"</string>
+    <string name="media_transfer_bt_device_mic_name" msgid="1870669402238687618">"Bluetooth микрофон"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Укључено"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Искључено"</string>
     <string name="carrier_network_change_mode" msgid="4257621815706644026">"Промена мреже мобилног оператера"</string>
diff --git a/packages/SettingsLib/res/values-sv/strings.xml b/packages/SettingsLib/res/values-sv/strings.xml
index c553c1d..9586a0c 100644
--- a/packages/SettingsLib/res/values-sv/strings.xml
+++ b/packages/SettingsLib/res/values-sv/strings.xml
@@ -585,7 +585,6 @@
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"Den här datorn (intern)"</string>
     <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
     <skip />
-    <string name="media_transfer_internal_mic" msgid="797333824290228595">"Mikrofon (inbyggd)"</string>
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Dockningsstationens högtalare"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Extern enhet"</string>
     <string name="media_transfer_default_device_name" msgid="4315604017399871828">"Ansluten enhet"</string>
@@ -688,9 +687,10 @@
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Enheten måste startas om för att ändringen ska börja gälla. Starta om nu eller avbryt."</string>
     <string name="media_transfer_wired_headphone_name" msgid="8698668536022665254">"Hörlur med kabel"</string>
     <string name="media_transfer_headphone_name" msgid="1131962659136578852">"Hörlur"</string>
-    <string name="media_transfer_usb_speaker_name" msgid="4736537022543593896">"USB-högtalare"</string>
+    <string name="media_transfer_usb_audio_name" msgid="1789292056757821355">"USB-ljud"</string>
     <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"Mikrofonuttag"</string>
-    <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"USB-mikrofon"</string>
+    <string name="media_transfer_usb_device_mic_name" msgid="7171789543226269822">"USB-mikrofon"</string>
+    <string name="media_transfer_bt_device_mic_name" msgid="1870669402238687618">"BT-mikrofon"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"På"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Av"</string>
     <string name="carrier_network_change_mode" msgid="4257621815706644026">"Byter leverantörsnätverk"</string>
diff --git a/packages/SettingsLib/res/values-sw/strings.xml b/packages/SettingsLib/res/values-sw/strings.xml
index 6890d55..8f0b246 100644
--- a/packages/SettingsLib/res/values-sw/strings.xml
+++ b/packages/SettingsLib/res/values-sw/strings.xml
@@ -585,7 +585,6 @@
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"Kompyuta hii (spika ya ndani)"</string>
     <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
     <skip />
-    <string name="media_transfer_internal_mic" msgid="797333824290228595">"Maikrofoni (ya ndani)"</string>
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Spika ya kituo"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Kifaa cha Nje"</string>
     <string name="media_transfer_default_device_name" msgid="4315604017399871828">"Kifaa kilichounganishwa"</string>
@@ -688,9 +687,10 @@
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Ni lazima uwashe tena kifaa chako ili mabadiliko haya yatekelezwe. Washa tena sasa au ughairi."</string>
     <string name="media_transfer_wired_headphone_name" msgid="8698668536022665254">"Kipokea sauti cha kichwani chenye waya"</string>
     <string name="media_transfer_headphone_name" msgid="1131962659136578852">"Kipokea sauti cha kichwani"</string>
-    <string name="media_transfer_usb_speaker_name" msgid="4736537022543593896">"Spika ya USB"</string>
+    <string name="media_transfer_usb_audio_name" msgid="1789292056757821355">"Sauti ya USB"</string>
     <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"Pini ya maikrofoni"</string>
-    <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"Maikrofoni ya USB"</string>
+    <string name="media_transfer_usb_device_mic_name" msgid="7171789543226269822">"Maikrofoni ya USB"</string>
+    <string name="media_transfer_bt_device_mic_name" msgid="1870669402238687618">"Maikrofoni ya Bluetooth"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Umewashwa"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Umezimwa"</string>
     <string name="carrier_network_change_mode" msgid="4257621815706644026">"Mabadiliko katika mtandao wa mtoa huduma"</string>
diff --git a/packages/SettingsLib/res/values-ta/strings.xml b/packages/SettingsLib/res/values-ta/strings.xml
index 5664290..e1a697c 100644
--- a/packages/SettingsLib/res/values-ta/strings.xml
+++ b/packages/SettingsLib/res/values-ta/strings.xml
@@ -585,7 +585,6 @@
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"இந்தக் கம்ப்யூட்டர் (அகம்)"</string>
     <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
     <skip />
-    <string name="media_transfer_internal_mic" msgid="797333824290228595">"மைக்ரோஃபோன் (அகம்)"</string>
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"டாக் ஸ்பீக்கர்"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"வெளிப்புறச் சாதனம்"</string>
     <string name="media_transfer_default_device_name" msgid="4315604017399871828">"இணைக்கப்பட்டுள்ள சாதனம்"</string>
@@ -688,9 +687,10 @@
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"இந்த மாற்றங்கள் செயல்படுத்தப்பட உங்கள் சாதனத்தை மறுபடி தொடங்க வேண்டும். இப்போதே மறுபடி தொடங்கவும் அல்லது ரத்துசெய்யவும்."</string>
     <string name="media_transfer_wired_headphone_name" msgid="8698668536022665254">"வயர்டு ஹெட்ஃபோன்"</string>
     <string name="media_transfer_headphone_name" msgid="1131962659136578852">"ஹெட்ஃபோன்"</string>
-    <string name="media_transfer_usb_speaker_name" msgid="4736537022543593896">"USB ஸ்பீக்கர்"</string>
+    <string name="media_transfer_usb_audio_name" msgid="1789292056757821355">"USB ஆடியோ"</string>
     <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"மைக் ஜாக்"</string>
-    <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"USB மைக்"</string>
+    <string name="media_transfer_usb_device_mic_name" msgid="7171789543226269822">"USB மைக்ரோஃபோன்"</string>
+    <string name="media_transfer_bt_device_mic_name" msgid="1870669402238687618">"BT மைக்ரோஃபோன்"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"ஆன்"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"ஆஃப்"</string>
     <string name="carrier_network_change_mode" msgid="4257621815706644026">"மொபைல் நிறுவன நெட்வொர்க்கை மாற்றும்"</string>
diff --git a/packages/SettingsLib/res/values-te/strings.xml b/packages/SettingsLib/res/values-te/strings.xml
index 56d0a7d..22e539b 100644
--- a/packages/SettingsLib/res/values-te/strings.xml
+++ b/packages/SettingsLib/res/values-te/strings.xml
@@ -585,7 +585,6 @@
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"ఈ కంప్యూటర్ (ఇంటర్నల్)"</string>
     <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
     <skip />
-    <string name="media_transfer_internal_mic" msgid="797333824290228595">"మైక్రోఫోన్ (అంతర్గతం)"</string>
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"డాక్ స్పీకర్"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"ఎక్స్‌టర్నల్ పరికరం"</string>
     <string name="media_transfer_default_device_name" msgid="4315604017399871828">"కనెక్ట్ చేసిన పరికరం"</string>
@@ -688,9 +687,10 @@
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"ఈ మార్పును వర్తింపజేయాలంటే మీరు మీ పరికరాన్ని తప్పనిసరిగా రీబూట్ చేయాలి. ఇప్పుడే రీబూట్ చేయండి లేదా రద్దు చేయండి."</string>
     <string name="media_transfer_wired_headphone_name" msgid="8698668536022665254">"వైర్ ఉన్న హెడ్‌ఫోన్"</string>
     <string name="media_transfer_headphone_name" msgid="1131962659136578852">"హెడ్‌ఫోన్"</string>
-    <string name="media_transfer_usb_speaker_name" msgid="4736537022543593896">"USB స్పీకర్"</string>
+    <string name="media_transfer_usb_audio_name" msgid="1789292056757821355">"USB ఆడియో"</string>
     <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"మైక్ జాక్"</string>
-    <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"USB మైక్"</string>
+    <string name="media_transfer_usb_device_mic_name" msgid="7171789543226269822">"USB మైక్రోఫోన్"</string>
+    <string name="media_transfer_bt_device_mic_name" msgid="1870669402238687618">"BT మైక్రోఫోన్"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"ఆన్‌లో ఉంది"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"ఆఫ్‌లో ఉంది"</string>
     <string name="carrier_network_change_mode" msgid="4257621815706644026">"క్యారియర్ నెట్‌వర్క్ మారుతోంది"</string>
diff --git a/packages/SettingsLib/res/values-th/strings.xml b/packages/SettingsLib/res/values-th/strings.xml
index 28a0d64..c9d9309 100644
--- a/packages/SettingsLib/res/values-th/strings.xml
+++ b/packages/SettingsLib/res/values-th/strings.xml
@@ -585,7 +585,6 @@
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"คอมพิวเตอร์เครื่องนี้ (ภายใน)"</string>
     <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
     <skip />
-    <string name="media_transfer_internal_mic" msgid="797333824290228595">"ไมโครโฟน (ภายใน)"</string>
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"แท่นชาร์จที่มีลำโพง"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"อุปกรณ์ภายนอก"</string>
     <string name="media_transfer_default_device_name" msgid="4315604017399871828">"อุปกรณ์ที่เชื่อมต่อ"</string>
@@ -688,9 +687,10 @@
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"คุณต้องรีบูตอุปกรณ์เพื่อให้การเปลี่ยนแปลงนี้มีผล รีบูตเลยหรือยกเลิก"</string>
     <string name="media_transfer_wired_headphone_name" msgid="8698668536022665254">"หูฟังแบบใช้สาย"</string>
     <string name="media_transfer_headphone_name" msgid="1131962659136578852">"หูฟัง"</string>
-    <string name="media_transfer_usb_speaker_name" msgid="4736537022543593896">"ลำโพง USB"</string>
+    <string name="media_transfer_usb_audio_name" msgid="1789292056757821355">"เสียง USB"</string>
     <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"ช่องเสียบไมค์"</string>
-    <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"ไมค์ USB"</string>
+    <string name="media_transfer_usb_device_mic_name" msgid="7171789543226269822">"ไมโครโฟน USB"</string>
+    <string name="media_transfer_bt_device_mic_name" msgid="1870669402238687618">"ไมโครโฟน BT"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"เปิด"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"ปิด"</string>
     <string name="carrier_network_change_mode" msgid="4257621815706644026">"การเปลี่ยนเครือข่ายผู้ให้บริการ"</string>
diff --git a/packages/SettingsLib/res/values-tl/strings.xml b/packages/SettingsLib/res/values-tl/strings.xml
index 926ce8f..5d7ed87 100644
--- a/packages/SettingsLib/res/values-tl/strings.xml
+++ b/packages/SettingsLib/res/values-tl/strings.xml
@@ -585,7 +585,6 @@
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"Sa computer na ito (internal)"</string>
     <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
     <skip />
-    <string name="media_transfer_internal_mic" msgid="797333824290228595">"Mikropono (internal)"</string>
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Speaker ng dock"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"External na Device"</string>
     <string name="media_transfer_default_device_name" msgid="4315604017399871828">"Nakakonektang device"</string>
@@ -688,9 +687,10 @@
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Dapat i-reboot ang iyong device para mailapat ang pagbabagong ito. Mag-reboot ngayon o kanselahin."</string>
     <string name="media_transfer_wired_headphone_name" msgid="8698668536022665254">"Wired na headphone"</string>
     <string name="media_transfer_headphone_name" msgid="1131962659136578852">"Headphone"</string>
-    <string name="media_transfer_usb_speaker_name" msgid="4736537022543593896">"USB speaker"</string>
+    <string name="media_transfer_usb_audio_name" msgid="1789292056757821355">"USB audio"</string>
     <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"Jack ng mikropono"</string>
-    <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"USB na mikropono"</string>
+    <string name="media_transfer_usb_device_mic_name" msgid="7171789543226269822">"USB na mikropono"</string>
+    <string name="media_transfer_bt_device_mic_name" msgid="1870669402238687618">"BT na mikropono"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Naka-on"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Naka-off"</string>
     <string name="carrier_network_change_mode" msgid="4257621815706644026">"Nagpapalit ng carrier network"</string>
diff --git a/packages/SettingsLib/res/values-tr/strings.xml b/packages/SettingsLib/res/values-tr/strings.xml
index 14c2108..9e4b6f2 100644
--- a/packages/SettingsLib/res/values-tr/strings.xml
+++ b/packages/SettingsLib/res/values-tr/strings.xml
@@ -585,7 +585,6 @@
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"Bu bilgisayar (dahili)"</string>
     <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
     <skip />
-    <string name="media_transfer_internal_mic" msgid="797333824290228595">"Mikrofon (dahili)"</string>
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Yuva hoparlörü"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Harici Cihaz"</string>
     <string name="media_transfer_default_device_name" msgid="4315604017399871828">"Bağlı cihaz"</string>
@@ -688,9 +687,10 @@
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Bu değişikliğin geçerli olması için cihazınızın yeniden başlatılması gerekir. Şimdi yeniden başlatın veya iptal edin."</string>
     <string name="media_transfer_wired_headphone_name" msgid="8698668536022665254">"Kablolu kulaklık"</string>
     <string name="media_transfer_headphone_name" msgid="1131962659136578852">"Kulaklık"</string>
-    <string name="media_transfer_usb_speaker_name" msgid="4736537022543593896">"USB hoparlör"</string>
+    <string name="media_transfer_usb_audio_name" msgid="1789292056757821355">"USB ses cihazı"</string>
     <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"Mikrofon jakı"</string>
-    <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"USB mikrofon"</string>
+    <string name="media_transfer_usb_device_mic_name" msgid="7171789543226269822">"USB mikrofon"</string>
+    <string name="media_transfer_bt_device_mic_name" msgid="1870669402238687618">"BT mikrofonu"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Açık"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Kapalı"</string>
     <string name="carrier_network_change_mode" msgid="4257621815706644026">"Operatör ağı değiştiriliyor"</string>
diff --git a/packages/SettingsLib/res/values-uk/strings.xml b/packages/SettingsLib/res/values-uk/strings.xml
index 25475d5..75c6b54 100644
--- a/packages/SettingsLib/res/values-uk/strings.xml
+++ b/packages/SettingsLib/res/values-uk/strings.xml
@@ -585,7 +585,6 @@
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"Цей комп’ютер (внутрішній)"</string>
     <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
     <skip />
-    <string name="media_transfer_internal_mic" msgid="797333824290228595">"Мікрофон (внутрішній)"</string>
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Динамік док-станції"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Зовнішній пристрій"</string>
     <string name="media_transfer_default_device_name" msgid="4315604017399871828">"Підключений пристрій"</string>
@@ -688,9 +687,10 @@
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Щоб застосувати ці зміни, потрібний перезапуск. Перезапустіть пристрій або скасуйте зміни."</string>
     <string name="media_transfer_wired_headphone_name" msgid="8698668536022665254">"Дротові навушники"</string>
     <string name="media_transfer_headphone_name" msgid="1131962659136578852">"Навушники"</string>
-    <string name="media_transfer_usb_speaker_name" msgid="4736537022543593896">"USB-динамік"</string>
+    <string name="media_transfer_usb_audio_name" msgid="1789292056757821355">"USB-аудіо"</string>
     <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"Гніздо для мікрофона"</string>
-    <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"USB-мікрофон"</string>
+    <string name="media_transfer_usb_device_mic_name" msgid="7171789543226269822">"USB-мікрофон"</string>
+    <string name="media_transfer_bt_device_mic_name" msgid="1870669402238687618">"Bluetooth-мікрофон"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Увімкнено"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Вимкнено"</string>
     <string name="carrier_network_change_mode" msgid="4257621815706644026">"Змінення мережі оператора"</string>
diff --git a/packages/SettingsLib/res/values-ur/strings.xml b/packages/SettingsLib/res/values-ur/strings.xml
index 2157f63..ebd2845 100644
--- a/packages/SettingsLib/res/values-ur/strings.xml
+++ b/packages/SettingsLib/res/values-ur/strings.xml
@@ -585,7 +585,6 @@
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"یہ کمپیوٹر (داخلی)"</string>
     <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
     <skip />
-    <string name="media_transfer_internal_mic" msgid="797333824290228595">"مائیکروفون (داخلی)"</string>
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"ڈاک اسپیکر"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"بیرونی آلہ"</string>
     <string name="media_transfer_default_device_name" msgid="4315604017399871828">"منسلک آلہ"</string>
@@ -688,9 +687,10 @@
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"اس تبدیلی کو لاگو کرنے کے ليے آپ کے آلہ کو ریبوٹ کرنا ضروری ہے۔ ابھی ریبوٹ کریں یا منسوخ کریں۔"</string>
     <string name="media_transfer_wired_headphone_name" msgid="8698668536022665254">"تار والا ہیڈ فون"</string>
     <string name="media_transfer_headphone_name" msgid="1131962659136578852">"ہیڈ فون"</string>
-    <string name="media_transfer_usb_speaker_name" msgid="4736537022543593896">"‏‫USB اسپیکر"</string>
+    <string name="media_transfer_usb_audio_name" msgid="1789292056757821355">"‏‫USB آڈیو"</string>
     <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"مائیک جیک"</string>
-    <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"‏‫USB مائیک"</string>
+    <string name="media_transfer_usb_device_mic_name" msgid="7171789543226269822">"‏‫USB مائیکروفون"</string>
+    <string name="media_transfer_bt_device_mic_name" msgid="1870669402238687618">"‏‫BT مائیکروفون"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"آن"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"آف"</string>
     <string name="carrier_network_change_mode" msgid="4257621815706644026">"کیریئر نیٹ ورک کی تبدیلی"</string>
diff --git a/packages/SettingsLib/res/values-uz/strings.xml b/packages/SettingsLib/res/values-uz/strings.xml
index 71fdae2..60fdf93 100644
--- a/packages/SettingsLib/res/values-uz/strings.xml
+++ b/packages/SettingsLib/res/values-uz/strings.xml
@@ -585,7 +585,6 @@
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"Bu kompyuter (ichki)"</string>
     <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
     <skip />
-    <string name="media_transfer_internal_mic" msgid="797333824290228595">"Mikrofon (ichki)"</string>
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Dok-stansiyali karnay"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Tashqi qurilma"</string>
     <string name="media_transfer_default_device_name" msgid="4315604017399871828">"Ulangan qurilma"</string>
@@ -688,9 +687,10 @@
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Oʻzgarishlar kuchga kirishi uchun qurilmani oʻchirib yoqing. Buni hozir yoki keyinroq bajarishingiz mumkin."</string>
     <string name="media_transfer_wired_headphone_name" msgid="8698668536022665254">"Simli quloqlik"</string>
     <string name="media_transfer_headphone_name" msgid="1131962659136578852">"Quloqlik"</string>
-    <string name="media_transfer_usb_speaker_name" msgid="4736537022543593896">"USB karnay"</string>
+    <string name="media_transfer_usb_audio_name" msgid="1789292056757821355">"USB audio"</string>
     <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"Mikrofon ulagichi"</string>
-    <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"USB mik"</string>
+    <string name="media_transfer_usb_device_mic_name" msgid="7171789543226269822">"USB mikrofon"</string>
+    <string name="media_transfer_bt_device_mic_name" msgid="1870669402238687618">"Bluetooth mikrofon"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Yoniq"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Oʻchiq"</string>
     <string name="carrier_network_change_mode" msgid="4257621815706644026">"Mobil tarmoqni o‘zgartirish"</string>
diff --git a/packages/SettingsLib/res/values-vi/strings.xml b/packages/SettingsLib/res/values-vi/strings.xml
index f53e816..dbd270f 100644
--- a/packages/SettingsLib/res/values-vi/strings.xml
+++ b/packages/SettingsLib/res/values-vi/strings.xml
@@ -585,7 +585,6 @@
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"Máy tính này (nội bộ)"</string>
     <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
     <skip />
-    <string name="media_transfer_internal_mic" msgid="797333824290228595">"Micrô (bên trong)"</string>
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Loa có gắn đế"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Thiết bị bên ngoài"</string>
     <string name="media_transfer_default_device_name" msgid="4315604017399871828">"Thiết bị đã kết nối"</string>
@@ -688,9 +687,10 @@
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Bạn phải khởi động lại thiết bị để áp dụng sự thay đổi này. Hãy khởi động lại ngay hoặc hủy."</string>
     <string name="media_transfer_wired_headphone_name" msgid="8698668536022665254">"Tai nghe có dây"</string>
     <string name="media_transfer_headphone_name" msgid="1131962659136578852">"Tai nghe"</string>
-    <string name="media_transfer_usb_speaker_name" msgid="4736537022543593896">"Loa USB"</string>
+    <string name="media_transfer_usb_audio_name" msgid="1789292056757821355">"Âm thanh qua cổng USB"</string>
     <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"Giắc cắm micrô"</string>
-    <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"Micrô có cổng USB"</string>
+    <string name="media_transfer_usb_device_mic_name" msgid="7171789543226269822">"Micrô USB"</string>
+    <string name="media_transfer_bt_device_mic_name" msgid="1870669402238687618">"Micrô BT"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Đang bật"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Đang tắt"</string>
     <string name="carrier_network_change_mode" msgid="4257621815706644026">"Thay đổi mạng của nhà mạng"</string>
diff --git a/packages/SettingsLib/res/values-zh-rCN/strings.xml b/packages/SettingsLib/res/values-zh-rCN/strings.xml
index 9275f1b..5c50e7f 100644
--- a/packages/SettingsLib/res/values-zh-rCN/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rCN/strings.xml
@@ -585,7 +585,6 @@
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"此计算机(内部)"</string>
     <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
     <skip />
-    <string name="media_transfer_internal_mic" msgid="797333824290228595">"麦克风(内部)"</string>
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"基座音箱"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"外部设备"</string>
     <string name="media_transfer_default_device_name" msgid="4315604017399871828">"连接的设备"</string>
@@ -688,9 +687,10 @@
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"设备必须重新启动才能应用此更改。您可以立即重新启动或取消。"</string>
     <string name="media_transfer_wired_headphone_name" msgid="8698668536022665254">"有线耳机"</string>
     <string name="media_transfer_headphone_name" msgid="1131962659136578852">"头戴式耳机"</string>
-    <string name="media_transfer_usb_speaker_name" msgid="4736537022543593896">"USB 音箱"</string>
+    <string name="media_transfer_usb_audio_name" msgid="1789292056757821355">"USB 音频"</string>
     <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"麦克风插孔"</string>
-    <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"USB 麦克风"</string>
+    <string name="media_transfer_usb_device_mic_name" msgid="7171789543226269822">"USB 麦克风"</string>
+    <string name="media_transfer_bt_device_mic_name" msgid="1870669402238687618">"蓝牙麦克风"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"开启"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"关闭"</string>
     <string name="carrier_network_change_mode" msgid="4257621815706644026">"运营商网络正在更改"</string>
diff --git a/packages/SettingsLib/res/values-zh-rHK/strings.xml b/packages/SettingsLib/res/values-zh-rHK/strings.xml
index 4acc52d..877fa7b 100644
--- a/packages/SettingsLib/res/values-zh-rHK/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rHK/strings.xml
@@ -585,7 +585,6 @@
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"此電腦 (內置)"</string>
     <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
     <skip />
-    <string name="media_transfer_internal_mic" msgid="797333824290228595">"麥克風 (內置)"</string>
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"插座喇叭"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"外部裝置"</string>
     <string name="media_transfer_default_device_name" msgid="4315604017399871828">"已連接的裝置"</string>
@@ -688,9 +687,10 @@
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"你的裝置必須重新開機,才能套用此變更。請立即重新開機或取消。"</string>
     <string name="media_transfer_wired_headphone_name" msgid="8698668536022665254">"有線耳機"</string>
     <string name="media_transfer_headphone_name" msgid="1131962659136578852">"耳機"</string>
-    <string name="media_transfer_usb_speaker_name" msgid="4736537022543593896">"USB 喇叭"</string>
+    <string name="media_transfer_usb_audio_name" msgid="1789292056757821355">"USB 音訊"</string>
     <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"麥克風插孔"</string>
-    <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"USB 麥克風"</string>
+    <string name="media_transfer_usb_device_mic_name" msgid="7171789543226269822">"USB 麥克風"</string>
+    <string name="media_transfer_bt_device_mic_name" msgid="1870669402238687618">"藍牙麥克風"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"開啟"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"關閉"</string>
     <string name="carrier_network_change_mode" msgid="4257621815706644026">"流動網絡供應商網絡正在變更"</string>
diff --git a/packages/SettingsLib/res/values-zh-rTW/strings.xml b/packages/SettingsLib/res/values-zh-rTW/strings.xml
index 8ded5d08e..fa016ba 100644
--- a/packages/SettingsLib/res/values-zh-rTW/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rTW/strings.xml
@@ -585,7 +585,6 @@
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"這部電腦 (內部)"</string>
     <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
     <skip />
-    <string name="media_transfer_internal_mic" msgid="797333824290228595">"麥克風 (內部)"</string>
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"座架喇叭"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"外部裝置"</string>
     <string name="media_transfer_default_device_name" msgid="4315604017399871828">"已連結的裝置"</string>
@@ -688,9 +687,10 @@
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"裝置必須重新啟動才能套用這項變更。請立即重新啟動或取消變更。"</string>
     <string name="media_transfer_wired_headphone_name" msgid="8698668536022665254">"有線耳機"</string>
     <string name="media_transfer_headphone_name" msgid="1131962659136578852">"耳機"</string>
-    <string name="media_transfer_usb_speaker_name" msgid="4736537022543593896">"USB 喇叭"</string>
+    <string name="media_transfer_usb_audio_name" msgid="1789292056757821355">"USB 音訊"</string>
     <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"麥克風插孔"</string>
-    <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"USB 麥克風"</string>
+    <string name="media_transfer_usb_device_mic_name" msgid="7171789543226269822">"USB 麥克風"</string>
+    <string name="media_transfer_bt_device_mic_name" msgid="1870669402238687618">"藍牙麥克風"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"開啟"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"關閉"</string>
     <string name="carrier_network_change_mode" msgid="4257621815706644026">"電信業者網路正在進行變更"</string>
diff --git a/packages/SettingsLib/res/values-zu/strings.xml b/packages/SettingsLib/res/values-zu/strings.xml
index 972eed7..063b6e7 100644
--- a/packages/SettingsLib/res/values-zu/strings.xml
+++ b/packages/SettingsLib/res/values-zu/strings.xml
@@ -585,7 +585,6 @@
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"Le khompyutha (ngaphakathi)"</string>
     <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
     <skip />
-    <string name="media_transfer_internal_mic" msgid="797333824290228595">"Imakrofoni (okwangaphakathi)"</string>
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Isipikha sentuba"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Idivayisi Yangaphandle"</string>
     <string name="media_transfer_default_device_name" msgid="4315604017399871828">"Idivayisi exhunyiwe"</string>
@@ -688,9 +687,10 @@
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Kufanele idivayisi yakho iqaliswe ukuze lolu shintsho lusebenze. Qalisa manje noma khansela."</string>
     <string name="media_transfer_wired_headphone_name" msgid="8698668536022665254">"Amahedifoni anentambo"</string>
     <string name="media_transfer_headphone_name" msgid="1131962659136578852">"Amahedifoni"</string>
-    <string name="media_transfer_usb_speaker_name" msgid="4736537022543593896">"Isipikha se-USB"</string>
+    <string name="media_transfer_usb_audio_name" msgid="1789292056757821355">"Umsindo we-USB"</string>
     <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"Umgodi we-earphone ye-mic"</string>
-    <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"I-mic ye-USB"</string>
+    <string name="media_transfer_usb_device_mic_name" msgid="7171789543226269822">"Imakrofoni ye-USB"</string>
+    <string name="media_transfer_bt_device_mic_name" msgid="1870669402238687618">"Imakrofoni ye-BT"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Vuliwe"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Valiwe"</string>
     <string name="carrier_network_change_mode" msgid="4257621815706644026">"Inethiwekhi yenkampani yenethiwekhi iyashintsha"</string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/applications/ServiceListing.java b/packages/SettingsLib/src/com/android/settingslib/applications/ServiceListing.java
index c8bcabf..261c722 100644
--- a/packages/SettingsLib/src/com/android/settingslib/applications/ServiceListing.java
+++ b/packages/SettingsLib/src/com/android/settingslib/applications/ServiceListing.java
@@ -138,23 +138,37 @@
         }
 
         final PackageManager pmWrapper = mContext.getPackageManager();
+        // Add requesting apps, with full validation
         List<ResolveInfo> installedServices = pmWrapper.queryIntentServicesAsUser(
                 new Intent(mIntentAction), flags, user);
         for (ResolveInfo resolveInfo : installedServices) {
             ServiceInfo info = resolveInfo.serviceInfo;
 
-            if (!mPermission.equals(info.permission)) {
-                Slog.w(mTag, "Skipping " + mNoun + " service "
-                        + info.packageName + "/" + info.name
-                        + ": it does not require the permission "
-                        + mPermission);
-                continue;
+            if (!mEnabledServices.contains(info.getComponentName())) {
+                if (!mPermission.equals(info.permission)) {
+                    Slog.w(mTag, "Skipping " + mNoun + " service "
+                            + info.packageName + "/" + info.name
+                            + ": it does not require the permission "
+                            + mPermission);
+                    continue;
+                }
+                if (mValidator != null && !mValidator.test(info)) {
+                    continue;
+                }
+                mServices.add(info);
             }
-            if (mValidator != null && !mValidator.test(info)) {
-                continue;
-            }
-            mServices.add(info);
         }
+
+        // Add all apps with access, in case prior approval was granted without full validation
+        for (ComponentName cn : mEnabledServices) {
+            List<ResolveInfo> enabledServices = pmWrapper.queryIntentServicesAsUser(
+                    new Intent().setComponent(cn), flags, user);
+            for (ResolveInfo resolveInfo : enabledServices) {
+                ServiceInfo info = resolveInfo.serviceInfo;
+                mServices.add(info);
+            }
+        }
+
         for (Callback callback : mCallbacks) {
             callback.onServicesReloaded(mServices);
         }
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
index 92da2be..8845d2e 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
@@ -38,7 +38,6 @@
 import android.os.Message;
 import android.os.ParcelUuid;
 import android.os.SystemClock;
-import android.provider.Settings;
 import android.text.SpannableStringBuilder;
 import android.text.TextUtils;
 import android.text.style.ForegroundColorSpan;
@@ -1291,12 +1290,10 @@
         if (BluetoothUtils.hasConnectedBroadcastSource(this, mBluetoothManager)) {
             // Gets summary for the buds which are in the audio sharing.
             int groupId = BluetoothUtils.getGroupId(this);
-            if (groupId != BluetoothCsipSetCoordinator.GROUP_ID_INVALID
-                    && groupId
-                            == Settings.Secure.getInt(
-                                    mContext.getContentResolver(),
-                                    "bluetooth_le_broadcast_fallback_active_group_id",
-                                    BluetoothCsipSetCoordinator.GROUP_ID_INVALID)) {
+            int primaryGroupId = BluetoothUtils.getPrimaryGroupIdForBroadcast(
+                    mContext.getContentResolver());
+            if ((primaryGroupId != BluetoothCsipSetCoordinator.GROUP_ID_INVALID)
+                    ? (groupId == primaryGroupId) : isActiveDevice(BluetoothProfile.LE_AUDIO)) {
                 // The buds are primary buds
                 return getSummaryWithBatteryInfo(
                         R.string.bluetooth_active_battery_level_untethered,
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java
index 8b6351e..7fdb32c 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java
@@ -60,7 +60,7 @@
         mBtManager = localBtManager;
         mHearingAidDeviceManager = new HearingAidDeviceManager(context, localBtManager,
                 mCachedDevices);
-        mCsipDeviceManager = new CsipDeviceManager(localBtManager, mCachedDevices);
+        mCsipDeviceManager = new CsipDeviceManager(context, localBtManager, mCachedDevices);
     }
 
     public synchronized Collection<CachedBluetoothDevice> getCachedDevicesCopy() {
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CsipDeviceManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CsipDeviceManager.java
index 6dab224..b9f16ed 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CsipDeviceManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CsipDeviceManager.java
@@ -21,8 +21,10 @@
 import android.bluetooth.BluetoothLeBroadcastMetadata;
 import android.bluetooth.BluetoothProfile;
 import android.bluetooth.BluetoothUuid;
+import android.content.Context;
 import android.os.Build;
 import android.os.ParcelUuid;
+import android.os.UserManager;
 import android.util.Log;
 
 import androidx.annotation.ChecksSdkIntAtLeast;
@@ -45,9 +47,11 @@
 
     private final LocalBluetoothManager mBtManager;
     private final List<CachedBluetoothDevice> mCachedDevices;
+    private final Context mContext;
 
-    CsipDeviceManager(LocalBluetoothManager localBtManager,
+    CsipDeviceManager(Context context, LocalBluetoothManager localBtManager,
             List<CachedBluetoothDevice> cachedDevices) {
+        mContext = context;
         mBtManager = localBtManager;
         mCachedDevices = cachedDevices;
     }
@@ -379,7 +383,11 @@
                 preferredMainDevice.refresh();
                 hasChanged = true;
             }
-            syncAudioSharingSourceIfNeeded(preferredMainDevice);
+            if (isWorkProfile()) {
+                log("addMemberDevicesIntoMainDevice: skip sync source for work profile");
+            } else {
+                syncAudioSharingSourceIfNeeded(preferredMainDevice);
+            }
         }
         if (hasChanged) {
             log("addMemberDevicesIntoMainDevice: After changed, CachedBluetoothDevice list: "
@@ -388,6 +396,11 @@
         return hasChanged;
     }
 
+    private boolean isWorkProfile() {
+        UserManager userManager = mContext.getSystemService(UserManager.class);
+        return userManager != null && userManager.isManagedProfile();
+    }
+
     private void syncAudioSharingSourceIfNeeded(CachedBluetoothDevice mainDevice) {
         boolean isAudioSharingEnabled = BluetoothUtils.isAudioSharingEnabled();
         if (isAudioSharingEnabled) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcast.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcast.java
index 364e95c..6a9d568 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcast.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcast.java
@@ -18,6 +18,8 @@
 
 import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
 
+import static java.util.stream.Collectors.toList;
+
 import android.annotation.CallbackExecutor;
 import android.annotation.IntDef;
 import android.bluetooth.BluetoothAdapter;
@@ -64,6 +66,7 @@
 import java.util.Collections;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 import java.util.UUID;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.Executor;
@@ -84,6 +87,8 @@
     public static final String EXTRA_BT_DEVICE_TO_AUTO_ADD_SOURCE = "BT_DEVICE_TO_AUTO_ADD_SOURCE";
     public static final String EXTRA_START_LE_AUDIO_SHARING = "START_LE_AUDIO_SHARING";
     public static final String EXTRA_PAIR_AND_JOIN_SHARING = "PAIR_AND_JOIN_SHARING";
+    public static final String BLUETOOTH_LE_BROADCAST_PRIMARY_DEVICE_GROUP_ID =
+            "bluetooth_le_broadcast_primary_device_group_id";
     public static final int BROADCAST_STATE_UNKNOWN = 0;
     public static final int BROADCAST_STATE_ON = 1;
     public static final int BROADCAST_STATE_OFF = 2;
@@ -1121,6 +1126,10 @@
 
     /** Update fallback active device if needed. */
     public void updateFallbackActiveDeviceIfNeeded() {
+        if (isWorkProfile(mContext)) {
+            Log.d(TAG, "Skip updateFallbackActiveDeviceIfNeeded for work profile.");
+            return;
+        }
         if (mServiceBroadcast == null) {
             Log.d(TAG, "Skip updateFallbackActiveDeviceIfNeeded due to broadcast profile is null");
             return;
@@ -1135,71 +1144,114 @@
             Log.d(TAG, "Skip updateFallbackActiveDeviceIfNeeded due to assistant profile is null");
             return;
         }
-        List<BluetoothDevice> devicesInBroadcast = getDevicesInBroadcast();
-        if (devicesInBroadcast.isEmpty()) {
+        Map<Integer, List<BluetoothDevice>> deviceGroupsInBroadcast = getDeviceGroupsInBroadcast();
+        if (deviceGroupsInBroadcast.isEmpty()) {
             Log.d(TAG, "Skip updateFallbackActiveDeviceIfNeeded due to no sinks in broadcast");
             return;
         }
-        List<BluetoothDevice> devices =
-                BluetoothAdapter.getDefaultAdapter().getMostRecentlyConnectedDevices();
-        BluetoothDevice targetDevice = null;
-        // Find the earliest connected device in sharing session.
-        int targetDeviceIdx = -1;
-        for (BluetoothDevice device : devicesInBroadcast) {
-            if (devices.contains(device)) {
-                int idx = devices.indexOf(device);
-                if (idx > targetDeviceIdx) {
-                    targetDeviceIdx = idx;
-                    targetDevice = device;
+        int targetGroupId = BluetoothCsipSetCoordinator.GROUP_ID_INVALID;
+        int fallbackActiveGroupId = BluetoothUtils.getPrimaryGroupIdForBroadcast(
+                mContext.getContentResolver());
+        if (Flags.audioSharingHysteresisModeFix()) {
+            int userPreferredPrimaryGroupId = getUserPreferredPrimaryGroupId();
+            if (userPreferredPrimaryGroupId != BluetoothCsipSetCoordinator.GROUP_ID_INVALID
+                    && deviceGroupsInBroadcast.containsKey(userPreferredPrimaryGroupId)) {
+                if (userPreferredPrimaryGroupId == fallbackActiveGroupId) {
+                    Log.d(TAG, "Skip updateFallbackActiveDeviceIfNeeded, already user preferred");
+                    return;
+                } else {
+                    targetGroupId = userPreferredPrimaryGroupId;
                 }
             }
+            if (targetGroupId == BluetoothCsipSetCoordinator.GROUP_ID_INVALID) {
+                // If there is no user preferred primary device, set the earliest connected
+                // device in sharing session as the fallback.
+                targetGroupId = getEarliestConnectedDeviceGroup(deviceGroupsInBroadcast);
+            }
+        } else {
+            // Set the earliest connected device in sharing session as the fallback.
+            targetGroupId = getEarliestConnectedDeviceGroup(deviceGroupsInBroadcast);
         }
-        if (targetDevice == null) {
-            Log.d(TAG, "Skip updateFallbackActiveDeviceIfNeeded, target is null");
+        Log.d(TAG, "updateFallbackActiveDeviceIfNeeded, target group id = " + targetGroupId);
+        if (targetGroupId == BluetoothCsipSetCoordinator.GROUP_ID_INVALID) return;
+        if (targetGroupId == fallbackActiveGroupId) {
+            Log.d(TAG, "Skip updateFallbackActiveDeviceIfNeeded, already is fallback");
             return;
         }
-        CachedBluetoothDevice targetCachedDevice = mDeviceManager.findDevice(targetDevice);
+        CachedBluetoothDevice targetCachedDevice = getMainDevice(
+                deviceGroupsInBroadcast.get(targetGroupId));
         if (targetCachedDevice == null) {
-            Log.d(TAG, "Skip updateFallbackActiveDeviceIfNeeded, fail to find cached bt device");
-            return;
-        }
-        int fallbackActiveGroupId = getFallbackActiveGroupId();
-        if (fallbackActiveGroupId != BluetoothCsipSetCoordinator.GROUP_ID_INVALID
-                && BluetoothUtils.getGroupId(targetCachedDevice) == fallbackActiveGroupId) {
-            Log.d(
-                    TAG,
-                    "Skip updateFallbackActiveDeviceIfNeeded, already is fallback: "
-                            + fallbackActiveGroupId);
+            Log.d(TAG, "Skip updateFallbackActiveDeviceIfNeeded, fail to find main device");
             return;
         }
         Log.d(
                 TAG,
                 "updateFallbackActiveDeviceIfNeeded, set active device: "
-                        + targetDevice.getAnonymizedAddress());
+                        + targetCachedDevice.getDevice());
         targetCachedDevice.setActive();
     }
 
-    private List<BluetoothDevice> getDevicesInBroadcast() {
+    @NonNull
+    private Map<Integer, List<BluetoothDevice>> getDeviceGroupsInBroadcast() {
         boolean hysteresisModeFixEnabled = Flags.audioSharingHysteresisModeFix();
         List<BluetoothDevice> connectedDevices = mServiceBroadcastAssistant.getConnectedDevices();
         return connectedDevices.stream()
                 .filter(
-                        bluetoothDevice -> {
+                        device -> {
                             List<BluetoothLeBroadcastReceiveState> sourceList =
-                                    mServiceBroadcastAssistant.getAllSources(
-                                            bluetoothDevice);
+                                    mServiceBroadcastAssistant.getAllSources(device);
                             return !sourceList.isEmpty() && sourceList.stream().anyMatch(
                                     source -> hysteresisModeFixEnabled
                                             ? BluetoothUtils.isSourceMatched(source, mBroadcastId)
                                             : BluetoothUtils.isConnected(source));
                         })
-                .collect(Collectors.toList());
+                .collect(Collectors.groupingBy(
+                        device -> BluetoothUtils.getGroupId(mDeviceManager.findDevice(device))));
     }
 
-    private int getFallbackActiveGroupId() {
+    private int getEarliestConnectedDeviceGroup(
+            @NonNull Map<Integer, List<BluetoothDevice>> deviceGroups) {
+        List<BluetoothDevice> devices =
+                BluetoothAdapter.getDefaultAdapter().getMostRecentlyConnectedDevices();
+        // Find the earliest connected device in sharing session.
+        int targetDeviceIdx = -1;
+        int targetGroupId = BluetoothCsipSetCoordinator.GROUP_ID_INVALID;
+        for (Map.Entry<Integer, List<BluetoothDevice>> entry : deviceGroups.entrySet()) {
+            for (BluetoothDevice device : entry.getValue()) {
+                if (devices.contains(device)) {
+                    int idx = devices.indexOf(device);
+                    if (idx > targetDeviceIdx) {
+                        targetDeviceIdx = idx;
+                        targetGroupId = entry.getKey();
+                    }
+                }
+            }
+        }
+        return targetGroupId;
+    }
+
+    @Nullable
+    private CachedBluetoothDevice getMainDevice(@Nullable List<BluetoothDevice> devices) {
+        if (devices == null || devices.size() == 1) return null;
+        List<CachedBluetoothDevice> cachedDevices =
+                devices.stream()
+                        .map(device -> mDeviceManager.findDevice(device))
+                        .filter(Objects::nonNull)
+                        .collect(toList());
+        for (CachedBluetoothDevice cachedDevice : cachedDevices) {
+            if (!cachedDevice.getMemberDevice().isEmpty()) {
+                return cachedDevice;
+            }
+        }
+        CachedBluetoothDevice mainDevice = cachedDevices.isEmpty() ? null : cachedDevices.get(0);
+        return mainDevice;
+    }
+
+    private int getUserPreferredPrimaryGroupId() {
+        // TODO: use real key name in SettingsProvider
         return Settings.Secure.getInt(
-                mContext.getContentResolver(),
-                "bluetooth_le_broadcast_fallback_active_group_id",
+                mContentResolver,
+                BLUETOOTH_LE_BROADCAST_PRIMARY_DEVICE_GROUP_ID,
                 BluetoothCsipSetCoordinator.GROUP_ID_INVALID);
     }
 
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcastAssistant.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcastAssistant.java
index c9f9d1b..a4c5a00d 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcastAssistant.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcastAssistant.java
@@ -42,6 +42,7 @@
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.Executor;
+import java.util.concurrent.Executors;
 
 /**
  * LocalBluetoothLeBroadcastAssistant provides an interface between the Settings app and the
@@ -63,6 +64,7 @@
     private BluetoothLeBroadcastMetadata mBluetoothLeBroadcastMetadata;
     private BluetoothLeBroadcastMetadata.Builder mBuilder;
     private boolean mIsProfileReady;
+    private Executor mExecutor;
     // Cached assistant callbacks being register before service is connected.
     private final Map<BluetoothLeBroadcastAssistant.Callback, Executor> mCachedCallbackExecutorMap =
             new ConcurrentHashMap<>();
@@ -98,15 +100,19 @@
                     }
 
                     mProfileManager.callServiceConnectedListeners();
-                    mIsProfileReady = true;
-                    if (DEBUG) {
-                        Log.d(
-                                TAG,
-                                "onServiceConnected, register mCachedCallbackExecutorMap = "
-                                        + mCachedCallbackExecutorMap);
+                    if (!mIsProfileReady) {
+                        mIsProfileReady = true;
+                        registerServiceCallBack(mExecutor, mAssistantCallback);
+                        if (DEBUG) {
+                            Log.d(
+                                    TAG,
+                                    "onServiceConnected, register mCachedCallbackExecutorMap = "
+                                            + mCachedCallbackExecutorMap);
+                        }
+                        mCachedCallbackExecutorMap.forEach(
+                                (callback, executor) -> registerServiceCallBack(executor,
+                                        callback));
                     }
-                    mCachedCallbackExecutorMap.forEach(
-                            (callback, executor) -> registerServiceCallBack(executor, callback));
                 }
 
                 @Override
@@ -119,17 +125,71 @@
                         Log.d(TAG, "Bluetooth service disconnected");
                     }
                     mProfileManager.callServiceDisconnectedListeners();
-                    mIsProfileReady = false;
-                    mCachedCallbackExecutorMap.clear();
+                    if (mIsProfileReady) {
+                        mIsProfileReady = false;
+                        unregisterServiceCallBack(mAssistantCallback);
+                        mCachedCallbackExecutorMap.clear();
+                    }
                 }
             };
 
+    private final BluetoothLeBroadcastAssistant.Callback mAssistantCallback =
+            new BluetoothLeBroadcastAssistant.Callback() {
+                @Override
+                public void onSourceAdded(@NonNull BluetoothDevice sink, int sourceId, int reason) {
+                }
+
+                @Override
+                public void onSearchStarted(int reason) {}
+
+                @Override
+                public void onSearchStartFailed(int reason) {}
+
+                @Override
+                public void onSearchStopped(int reason) {}
+
+                @Override
+                public void onSearchStopFailed(int reason) {}
+
+                @Override
+                public void onSourceFound(@NonNull BluetoothLeBroadcastMetadata source) {}
+
+                @Override
+                public void onSourceAddFailed(
+                        @NonNull BluetoothDevice sink,
+                        @NonNull BluetoothLeBroadcastMetadata source,
+                        int reason) {}
+
+                @Override
+                public void onSourceModified(
+                        @NonNull BluetoothDevice sink, int sourceId, int reason) {}
+
+                @Override
+                public void onSourceModifyFailed(
+                        @NonNull BluetoothDevice sink, int sourceId, int reason) {}
+
+                @Override
+                public void onSourceRemoved(
+                        @NonNull BluetoothDevice sink, int sourceId, int reason) {}
+
+                @Override
+                public void onSourceRemoveFailed(
+                        @NonNull BluetoothDevice sink, int sourceId, int reason) {}
+
+                @Override
+                public void onReceiveStateChanged(
+                        @NonNull BluetoothDevice sink,
+                        int sourceId,
+                        @NonNull BluetoothLeBroadcastReceiveState state) {}
+            };
+
     public LocalBluetoothLeBroadcastAssistant(
             Context context,
             CachedBluetoothDeviceManager deviceManager,
             LocalBluetoothProfileManager profileManager) {
         mProfileManager = profileManager;
         mDeviceManager = deviceManager;
+        mExecutor = Executors.newSingleThreadExecutor();
         BluetoothAdapter.getDefaultAdapter()
                 .getProfileProxy(
                         context, mServiceListener, BluetoothProfile.LE_AUDIO_BROADCAST_ASSISTANT);
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcastAssistantCallbackExt.kt b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcastAssistantCallbackExt.kt
index 24815fa..91a99ae 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcastAssistantCallbackExt.kt
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcastAssistantCallbackExt.kt
@@ -16,7 +16,6 @@
 
 package com.android.settingslib.bluetooth
 
-import android.bluetooth.BluetoothAdapter
 import android.bluetooth.BluetoothDevice
 import android.bluetooth.BluetoothLeBroadcastAssistant
 import android.bluetooth.BluetoothLeBroadcastMetadata
@@ -82,9 +81,5 @@
             ConcurrentUtils.DIRECT_EXECUTOR,
             callback,
         )
-        awaitClose {
-            if (BluetoothAdapter.getDefaultAdapter()?.isEnabled == true) {
-                unregisterServiceCallBack(callback)
-            }
-        }
+        awaitClose { unregisterServiceCallBack(callback) }
     }
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcastCallbackExt.kt b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcastCallbackExt.kt
index 0bcf7fe..07abb6b 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcastCallbackExt.kt
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcastCallbackExt.kt
@@ -68,3 +68,44 @@
                 awaitClose { unregisterServiceCallBack(listener) }
             }
             .buffer(capacity = Channel.CONFLATED)
+
+/** [Flow] for [BluetoothLeBroadcast.Callback] onPlaybackStarted event */
+val LocalBluetoothLeBroadcast.onPlaybackStarted: Flow<Unit>
+    get() =
+        callbackFlow {
+            val listener =
+                object : BluetoothLeBroadcast.Callback {
+                    override fun onBroadcastStarted(reason: Int, broadcastId: Int) {}
+
+                    override fun onBroadcastStartFailed(reason: Int) {
+                    }
+
+                    override fun onBroadcastStopped(reason: Int, broadcastId: Int) {
+                    }
+
+                    override fun onBroadcastStopFailed(reason: Int) {
+                    }
+
+                    override fun onPlaybackStarted(reason: Int, broadcastId: Int) {
+                        launch { trySend(Unit) }
+                    }
+
+                    override fun onPlaybackStopped(reason: Int, broadcastId: Int) {
+                    }
+
+                    override fun onBroadcastUpdated(reason: Int, broadcastId: Int) {}
+
+                    override fun onBroadcastUpdateFailed(reason: Int, broadcastId: Int) {}
+
+                    override fun onBroadcastMetadataChanged(
+                        broadcastId: Int,
+                        metadata: BluetoothLeBroadcastMetadata
+                    ) {}
+                }
+            registerServiceCallBack(
+                ConcurrentUtils.DIRECT_EXECUTOR,
+                listener,
+            )
+            awaitClose { unregisterServiceCallBack(listener) }
+        }
+            .buffer(capacity = Channel.CONFLATED)
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/devicesettings/ActionSwitchPreference.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/devicesettings/ActionSwitchPreference.java
index 1cbb8b4..2b9088f 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/devicesettings/ActionSwitchPreference.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/devicesettings/ActionSwitchPreference.java
@@ -16,7 +16,6 @@
 
 package com.android.settingslib.bluetooth.devicesettings;
 
-import android.content.Intent;
 import android.graphics.Bitmap;
 import android.os.Bundle;
 import android.os.Parcel;
@@ -36,7 +35,7 @@
     private final String mTitle;
     private final String mSummary;
     private final Bitmap mIcon;
-    private final Intent mIntent;
+    private final DeviceSettingAction mAction;
     private final boolean mHasSwitch;
     private final boolean mChecked;
     private final boolean mIsAllowedChangingState;
@@ -46,7 +45,7 @@
             String title,
             @Nullable String summary,
             @Nullable Bitmap icon,
-            @Nullable Intent intent,
+            @NonNull DeviceSettingAction action,
             boolean hasSwitch,
             boolean checked,
             boolean allowChangingState,
@@ -56,7 +55,7 @@
         mTitle = title;
         mSummary = summary;
         mIcon = icon;
-        mIntent = intent;
+        mAction = action;
         mHasSwitch = hasSwitch;
         mChecked = checked;
         mIsAllowedChangingState = allowChangingState;
@@ -79,13 +78,13 @@
         String title = in.readString();
         String summary = in.readString();
         Bitmap icon = in.readParcelable(Bitmap.class.getClassLoader());
-        Intent intent = in.readParcelable(Intent.class.getClassLoader());
+        DeviceSettingAction action = DeviceSettingAction.readFromParcel(in);
         boolean hasSwitch = in.readBoolean();
         boolean checked = in.readBoolean();
         boolean allowChangingState = in.readBoolean();
         Bundle extras = in.readBundle(Bundle.class.getClassLoader());
         return new ActionSwitchPreference(
-                title, summary, icon, intent, hasSwitch, checked, allowChangingState, extras);
+                title, summary, icon, action, hasSwitch, checked, allowChangingState, extras);
     }
 
     public static final Creator<ActionSwitchPreference> CREATOR =
@@ -115,7 +114,7 @@
         dest.writeString(mTitle);
         dest.writeString(mSummary);
         dest.writeParcelable(mIcon, flags);
-        dest.writeParcelable(mIntent, flags);
+        mAction.writeToParcel(dest, flags);
         dest.writeBoolean(mHasSwitch);
         dest.writeBoolean(mChecked);
         dest.writeBoolean(mIsAllowedChangingState);
@@ -127,7 +126,7 @@
         private String mTitle;
         private String mSummary;
         private Bitmap mIcon;
-        private Intent mIntent;
+        private DeviceSettingAction mAction = DeviceSettingAction.EMPTY_ACTION;
         private boolean mHasSwitch;
         private boolean mChecked;
         private boolean mIsAllowedChangingState;
@@ -170,14 +169,14 @@
         }
 
         /**
-         * Sets the Intent to launch when the preference is clicked, optional.
+         * Sets the action to trigger when the preference is clicked, optional.
          *
-         * @param intent The Intent.
+         * @param action The action to trigger.
          * @return Returns the Builder object.
          */
         @NonNull
-        public Builder setIntent(@Nullable Intent intent) {
-            mIntent = intent;
+        public Builder setAction(@Nullable DeviceSettingAction action) {
+            mAction = action == null ? DeviceSettingAction.EMPTY_ACTION : action;
             return this;
         }
 
@@ -239,7 +238,7 @@
                     mTitle,
                     mSummary,
                     mIcon,
-                    mIntent,
+                    mAction,
                     mHasSwitch,
                     mChecked,
                     mIsAllowedChangingState,
@@ -278,13 +277,13 @@
     }
 
     /**
-     * Gets the Intent to launch when the preference is clicked.
+     * Gets the action to trigger when the preference is clicked.
      *
      * @return Returns the intent to launch.
      */
-    @Nullable
-    public Intent getIntent() {
-        return mIntent;
+    @NonNull
+    public DeviceSettingAction getAction() {
+        return mAction;
     }
 
     /**
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/devicesettings/DeviceSettingAction.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/devicesettings/DeviceSettingAction.java
new file mode 100644
index 0000000..01783e0
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/devicesettings/DeviceSettingAction.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.bluetooth.devicesettings;
+
+import android.os.Parcel;
+
+import androidx.annotation.NonNull;
+
+/** An abstract class representing a device setting action. */
+public abstract class DeviceSettingAction {
+    @DeviceSettingActionType private final int mActionType;
+
+    public static final DeviceSettingAction EMPTY_ACTION =
+            new DeviceSettingAction(DeviceSettingActionType.DEVICE_SETTING_ACTION_TYPE_UNKNOWN) {};
+
+    protected DeviceSettingAction(@DeviceSettingActionType int actionType) {
+        mActionType = actionType;
+    }
+
+    /** Read a {@link DeviceSettingPreference} instance from {@link Parcel} */
+    @NonNull
+    public static DeviceSettingAction readFromParcel(@NonNull Parcel in) {
+        int type = in.readInt();
+        return switch (type) {
+            case DeviceSettingActionType.DEVICE_SETTING_ACTION_TYPE_INTENT ->
+                    DeviceSettingIntentAction.readFromParcel(in);
+            case DeviceSettingActionType.DEVICE_SETTING_ACTION_TYPE_PENDING_INTENT ->
+                    DeviceSettingPendingIntentAction.readFromParcel(in);
+            default -> EMPTY_ACTION;
+        };
+    }
+
+    /** Writes the instance to {@link Parcel}. */
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeInt(mActionType);
+    }
+
+    /**
+     * Gets the setting action type, as defined by IntDef {@link DeviceSettingActionType}.
+     *
+     * @return the setting action type.
+     */
+    @DeviceSettingType
+    public int getActionType() {
+        return mActionType;
+    }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/devicesettings/DeviceSettingActionType.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/devicesettings/DeviceSettingActionType.java
new file mode 100644
index 0000000..13d3583
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/devicesettings/DeviceSettingActionType.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.bluetooth.devicesettings;
+
+import androidx.annotation.IntDef;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+@Retention(RetentionPolicy.SOURCE)
+@IntDef(
+        value = {
+            DeviceSettingActionType.DEVICE_SETTING_ACTION_TYPE_UNKNOWN,
+            DeviceSettingActionType.DEVICE_SETTING_ACTION_TYPE_INTENT,
+            DeviceSettingActionType.DEVICE_SETTING_ACTION_TYPE_PENDING_INTENT,
+        },
+        open = true)
+public @interface DeviceSettingActionType {
+    /** Device setting action type is unknown. */
+    int DEVICE_SETTING_ACTION_TYPE_UNKNOWN = 0;
+
+    /** Device setting action is an intent to start an activity. */
+    int DEVICE_SETTING_ACTION_TYPE_INTENT = 1;
+
+    /** Device setting action is a pending intent. */
+    int DEVICE_SETTING_ACTION_TYPE_PENDING_INTENT = 2;
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/devicesettings/DeviceSettingIntentAction.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/devicesettings/DeviceSettingIntentAction.java
new file mode 100644
index 0000000..a1136e6
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/devicesettings/DeviceSettingIntentAction.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.bluetooth.devicesettings;
+
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import androidx.annotation.NonNull;
+
+import java.util.Objects;
+
+/** An abstract class representing a device setting action. */
+public class DeviceSettingIntentAction extends DeviceSettingAction implements Parcelable {
+    private final Intent mIntent;
+    private final Bundle mExtras;
+
+    DeviceSettingIntentAction(@NonNull Intent intent, @NonNull Bundle extras) {
+        super(DeviceSettingActionType.DEVICE_SETTING_ACTION_TYPE_INTENT);
+        validate(intent);
+        mIntent = intent;
+        mExtras = extras;
+    }
+
+    private static void validate(Intent intent) {
+        if (Objects.isNull(intent)) {
+            throw new IllegalArgumentException("Intent must be set");
+        }
+    }
+
+    /** Read a {@link DeviceSettingIntentAction} instance from {@link Parcel} */
+    @NonNull
+    public static DeviceSettingIntentAction readFromParcel(@NonNull Parcel in) {
+        Intent intent = in.readParcelable(Intent.class.getClassLoader());
+        Bundle extras = in.readBundle(Bundle.class.getClassLoader());
+        return new DeviceSettingIntentAction(intent, extras);
+    }
+
+    public static final Creator<DeviceSettingIntentAction> CREATOR =
+            new Creator<>() {
+                @Override
+                @NonNull
+                public DeviceSettingIntentAction createFromParcel(@NonNull Parcel in) {
+                    in.readInt();
+                    return readFromParcel(in);
+                }
+
+                @Override
+                @NonNull
+                public DeviceSettingIntentAction[] newArray(int size) {
+                    return new DeviceSettingIntentAction[size];
+                }
+            };
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    /** Writes the instance to {@link Parcel}. */
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        super.writeToParcel(dest, flags);
+        dest.writeParcelable(mIntent, flags);
+        dest.writeBundle(mExtras);
+    }
+
+    /** Builder class for {@link DeviceSettingFooterPreference}. */
+    public static final class Builder {
+        private Intent mIntent = null;
+        private Bundle mExtras = Bundle.EMPTY;
+
+        /**
+         * Sets the intent for the action.
+         *
+         * @param intent The intent.
+         * @return Returns the Builder object.
+         */
+        @NonNull
+        public Builder setIntent(@NonNull Intent intent) {
+            mIntent = intent;
+            return this;
+        }
+
+        /**
+         * Sets the extras bundle.
+         *
+         * @return Returns the Builder object.
+         */
+        @NonNull
+        public Builder setExtras(@NonNull Bundle extras) {
+            mExtras = extras;
+            return this;
+        }
+
+        /**
+         * Builds the {@link DeviceSettingIntentAction} object.
+         *
+         * @return Returns the built {@link DeviceSettingIntentAction} object.
+         */
+        @NonNull
+        public DeviceSettingIntentAction build() {
+            return new DeviceSettingIntentAction(mIntent, mExtras);
+        }
+    }
+
+    /** Gets the intent. */
+    @NonNull
+    public Intent getIntent() {
+        return mIntent;
+    }
+
+    /** Gets the extra bundle. */
+    @NonNull
+    public Bundle getExtras() {
+        return mExtras;
+    }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/devicesettings/DeviceSettingPendingIntentAction.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/devicesettings/DeviceSettingPendingIntentAction.java
new file mode 100644
index 0000000..3d4282c
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/devicesettings/DeviceSettingPendingIntentAction.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.bluetooth.devicesettings;
+
+import android.app.PendingIntent;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import androidx.annotation.NonNull;
+
+import java.util.Objects;
+
+/** An abstract class representing a device setting action. */
+public class DeviceSettingPendingIntentAction extends DeviceSettingAction implements Parcelable {
+    private final PendingIntent mPendingIntent;
+    private final Bundle mExtras;
+
+    DeviceSettingPendingIntentAction(@NonNull PendingIntent pendingIntent, @NonNull Bundle extras) {
+        super(DeviceSettingActionType.DEVICE_SETTING_ACTION_TYPE_PENDING_INTENT);
+        validate(pendingIntent);
+        mPendingIntent = pendingIntent;
+        mExtras = extras;
+    }
+
+    private static void validate(PendingIntent pendingIntent) {
+        if (Objects.isNull(pendingIntent)) {
+            throw new IllegalArgumentException("PendingIntent must be set");
+        }
+    }
+
+    /** Read a {@link DeviceSettingPendingIntentAction} instance from {@link Parcel} */
+    @NonNull
+    public static DeviceSettingPendingIntentAction readFromParcel(@NonNull Parcel in) {
+        PendingIntent pendingIntent = in.readParcelable(Intent.class.getClassLoader());
+        Bundle extras = in.readBundle(Bundle.class.getClassLoader());
+        return new DeviceSettingPendingIntentAction(pendingIntent, extras);
+    }
+
+    public static final Creator<DeviceSettingPendingIntentAction> CREATOR =
+            new Creator<>() {
+                @Override
+                @NonNull
+                public DeviceSettingPendingIntentAction createFromParcel(@NonNull Parcel in) {
+                    in.readInt();
+                    return readFromParcel(in);
+                }
+
+                @Override
+                @NonNull
+                public DeviceSettingPendingIntentAction[] newArray(int size) {
+                    return new DeviceSettingPendingIntentAction[size];
+                }
+            };
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    /** Writes the instance to {@link Parcel}. */
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        super.writeToParcel(dest, flags);
+        dest.writeParcelable(mPendingIntent, flags);
+        dest.writeBundle(mExtras);
+    }
+
+    /** Builder class for {@link DeviceSettingFooterPreference}. */
+    public static final class Builder {
+        private PendingIntent mPendingIntent = null;
+        private Bundle mExtras = Bundle.EMPTY;
+
+        /**
+         * Sets the intent for the action.
+         *
+         * @param pendingIntent The pending intent.
+         * @return Returns the Builder object.
+         */
+        @NonNull
+        public Builder setPendingIntent(@NonNull PendingIntent pendingIntent) {
+            mPendingIntent = pendingIntent;
+            return this;
+        }
+
+        /**
+         * Sets the extras bundle.
+         *
+         * @return Returns the Builder object.
+         */
+        @NonNull
+        public Builder setExtras(@NonNull Bundle extras) {
+            mExtras = extras;
+            return this;
+        }
+
+        /**
+         * Builds the {@link DeviceSettingPendingIntentAction} object.
+         *
+         * @return Returns the built {@link DeviceSettingPendingIntentAction} object.
+         */
+        @NonNull
+        public DeviceSettingPendingIntentAction build() {
+            return new DeviceSettingPendingIntentAction(mPendingIntent, mExtras);
+        }
+    }
+
+    /** Gets the pending intent. */
+    @NonNull
+    public PendingIntent getPendingIntent() {
+        return mPendingIntent;
+    }
+
+    /** Gets the extra bundle. */
+    @NonNull
+    public Bundle getExtras() {
+        return mExtras;
+    }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/devicesettings/DeviceSettingType.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/devicesettings/DeviceSettingType.java
index ae3bf5e..3cc1343 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/devicesettings/DeviceSettingType.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/devicesettings/DeviceSettingType.java
@@ -28,6 +28,7 @@
             DeviceSettingType.DEVICE_SETTING_TYPE_ACTION_SWITCH,
             DeviceSettingType.DEVICE_SETTING_TYPE_MULTI_TOGGLE,
             DeviceSettingType.DEVICE_SETTING_TYPE_FOOTER,
+            DeviceSettingType.DEVICE_SETTING_TYPE_HELP,
         },
         open = true)
 public @interface DeviceSettingType {
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/devicesettings/IDeviceSettingsConfigProviderService.aidl b/packages/SettingsLib/src/com/android/settingslib/bluetooth/devicesettings/IDeviceSettingsConfigProviderService.aidl
index 9cf4907..c85756e 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/devicesettings/IDeviceSettingsConfigProviderService.aidl
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/devicesettings/IDeviceSettingsConfigProviderService.aidl
@@ -20,5 +20,5 @@
 import com.android.settingslib.bluetooth.devicesettings.IGetDeviceSettingsConfigCallback;
 
 interface IDeviceSettingsConfigProviderService {
-   oneway void getDeviceSettingsConfig(in DeviceInfo device, in IGetDeviceSettingsConfigCallback callback);
+   void getDeviceSettingsConfig(in DeviceInfo device, in IGetDeviceSettingsConfigCallback callback);
 }
\ No newline at end of file
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/devicesettings/data/repository/DeviceSettingRepository.kt b/packages/SettingsLib/src/com/android/settingslib/bluetooth/devicesettings/data/repository/DeviceSettingRepository.kt
index 851b614..8537897 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/devicesettings/data/repository/DeviceSettingRepository.kt
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/devicesettings/data/repository/DeviceSettingRepository.kt
@@ -22,14 +22,18 @@
 import com.android.settingslib.bluetooth.CachedBluetoothDevice
 import com.android.settingslib.bluetooth.devicesettings.ActionSwitchPreference
 import com.android.settingslib.bluetooth.devicesettings.DeviceSetting
+import com.android.settingslib.bluetooth.devicesettings.DeviceSettingAction
 import com.android.settingslib.bluetooth.devicesettings.DeviceSettingContract
-import com.android.settingslib.bluetooth.devicesettings.DeviceSettingId
-import com.android.settingslib.bluetooth.devicesettings.DeviceSettingItem
-import com.android.settingslib.bluetooth.devicesettings.DeviceSettingsConfig
 import com.android.settingslib.bluetooth.devicesettings.DeviceSettingFooterPreference
 import com.android.settingslib.bluetooth.devicesettings.DeviceSettingHelpPreference
+import com.android.settingslib.bluetooth.devicesettings.DeviceSettingId
+import com.android.settingslib.bluetooth.devicesettings.DeviceSettingIntentAction
+import com.android.settingslib.bluetooth.devicesettings.DeviceSettingItem
+import com.android.settingslib.bluetooth.devicesettings.DeviceSettingPendingIntentAction
+import com.android.settingslib.bluetooth.devicesettings.DeviceSettingsConfig
 import com.android.settingslib.bluetooth.devicesettings.MultiTogglePreference
 import com.android.settingslib.bluetooth.devicesettings.ToggleInfo
+import com.android.settingslib.bluetooth.devicesettings.shared.model.DeviceSettingActionModel
 import com.android.settingslib.bluetooth.devicesettings.shared.model.DeviceSettingConfigItemModel
 import com.android.settingslib.bluetooth.devicesettings.shared.model.DeviceSettingConfigItemModel.AppProvidedItem
 import com.android.settingslib.bluetooth.devicesettings.shared.model.DeviceSettingConfigItemModel.BuiltinItem.BluetoothProfilesItem
@@ -58,7 +62,7 @@
     /** Gets device setting for the bluetooth device. */
     fun getDeviceSetting(
         cachedDevice: CachedBluetoothDevice,
-        @DeviceSettingId settingId: Int
+        @DeviceSettingId settingId: Int,
     ): Flow<DeviceSettingModel?>
 }
 
@@ -84,7 +88,8 @@
                             coroutineScope,
                             backgroundCoroutineContext,
                         )
-                })
+                }
+            )
 
     override suspend fun getDeviceSettingsConfig(
         cachedDevice: CachedBluetoothDevice
@@ -93,7 +98,7 @@
 
     override fun getDeviceSetting(
         cachedDevice: CachedBluetoothDevice,
-        settingId: Int
+        settingId: Int,
     ): Flow<DeviceSettingModel?> =
         connectionCache.get(cachedDevice).let { connection ->
             connection.getDeviceSetting(settingId).map { it?.toModel(cachedDevice, connection) }
@@ -103,7 +108,8 @@
         DeviceSettingConfigModel(
             mainItems = mainContentItems.map { it.toModel() },
             moreSettingsItems = moreSettingsItems.map { it.toModel() },
-            moreSettingsHelpItem = moreSettingsHelpItem?.toModel(), )
+            moreSettingsHelpItem = moreSettingsHelpItem?.toModel(),
+        )
 
     private fun DeviceSettingItem.toModel(): DeviceSettingConfigItemModel {
         return if (!TextUtils.isEmpty(preferenceKey)) {
@@ -113,7 +119,7 @@
                     highlighted,
                     preferenceKey!!,
                     extras.getStringArrayList(DeviceSettingContract.INVISIBLE_PROFILES)
-                        ?: emptyList()
+                        ?: emptyList(),
                 )
             } else {
                 CommonBuiltinItem(settingId, highlighted, preferenceKey!!)
@@ -123,9 +129,17 @@
         }
     }
 
+    private fun DeviceSettingAction.toModel(): DeviceSettingActionModel? =
+        when (this) {
+            is DeviceSettingIntentAction -> DeviceSettingActionModel.IntentAction(this.intent)
+            is DeviceSettingPendingIntentAction ->
+                DeviceSettingActionModel.PendingIntentAction(this.pendingIntent)
+            else -> null
+        }
+
     private fun DeviceSetting.toModel(
         cachedDevice: CachedBluetoothDevice,
-        connection: DeviceSettingServiceConnection
+        connection: DeviceSettingServiceConnection,
     ): DeviceSettingModel =
         when (val pref = preference) {
             is ActionSwitchPreference ->
@@ -136,7 +150,7 @@
                     summary = pref.summary,
                     icon = pref.icon?.let { DeviceSettingIcon.BitmapIcon(it) },
                     isAllowedChangingState = pref.isAllowedChangingState,
-                    intent = pref.intent,
+                    action = pref.action?.toModel(),
                     switchState =
                         if (pref.hasSwitch()) {
                             DeviceSettingStateModel.ActionSwitchPreferenceState(pref.checked)
@@ -145,10 +159,7 @@
                         },
                     updateState = { newState ->
                         coroutineScope.launch(backgroundCoroutineContext) {
-                            connection.updateDeviceSettings(
-                                settingId,
-                                newState.toParcelable(),
-                            )
+                            connection.updateDeviceSettings(settingId, newState.toParcelable())
                         }
                     },
                 )
@@ -167,12 +178,18 @@
                         }
                     },
                 )
-            is DeviceSettingFooterPreference -> DeviceSettingModel.FooterPreference(
-                cachedDevice = cachedDevice,
-                id = settingId, footerText = pref.footerText)
-            is DeviceSettingHelpPreference -> DeviceSettingModel.HelpPreference(
-                cachedDevice = cachedDevice,
-                id = settingId, intent = pref.intent)
+            is DeviceSettingFooterPreference ->
+                DeviceSettingModel.FooterPreference(
+                    cachedDevice = cachedDevice,
+                    id = settingId,
+                    footerText = pref.footerText,
+                )
+            is DeviceSettingHelpPreference ->
+                DeviceSettingModel.HelpPreference(
+                    cachedDevice = cachedDevice,
+                    id = settingId,
+                    intent = pref.intent,
+                )
             else -> DeviceSettingModel.Unknown(cachedDevice, settingId)
         }
 
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/devicesettings/data/repository/DeviceSettingServiceConnection.kt b/packages/SettingsLib/src/com/android/settingslib/bluetooth/devicesettings/data/repository/DeviceSettingServiceConnection.kt
index 4af0504..a33fcc6 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/devicesettings/data/repository/DeviceSettingServiceConnection.kt
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/devicesettings/data/repository/DeviceSettingServiceConnection.kt
@@ -23,6 +23,7 @@
 import android.content.ServiceConnection
 import android.os.IBinder
 import android.os.IInterface
+import android.os.RemoteException
 import android.text.TextUtils
 import android.util.Log
 import com.android.settingslib.bluetooth.BluetoothUtils
@@ -55,6 +56,7 @@
 import kotlinx.coroutines.flow.emitAll
 import kotlinx.coroutines.flow.filterIsInstance
 import kotlinx.coroutines.flow.first
+import kotlinx.coroutines.flow.firstOrNull
 import kotlinx.coroutines.flow.flatMapConcat
 import kotlinx.coroutines.flow.flatMapLatest
 import kotlinx.coroutines.flow.flow
@@ -100,6 +102,9 @@
     private var isServiceEnabled =
         coroutineScope.async(backgroundCoroutineContext, start = CoroutineStart.LAZY) {
             val states = getSettingsProviderServices()?.values ?: return@async false
+            if (states.isEmpty()) {
+                return@async true
+            }
             combine(states) { it.toList() }
                 .mapNotNull { allStatus ->
                     if (allStatus.any { it is ServiceConnectionStatus.Failed }) {
@@ -114,7 +119,7 @@
                         null
                     }
                 }
-                .first()
+                .firstOrNull() ?: false
         }
 
     private var config =
@@ -131,9 +136,15 @@
                         is ServiceConnectionStatus.Connected ->
                             flowOf(
                                 getDeviceSettingsConfigFromService(
-                                    deviceInfo { setBluetoothAddress(cachedDevice.address) },
-                                    it.service,
-                                )
+                                        deviceInfo { setBluetoothAddress(cachedDevice.address) },
+                                        it.service,
+                                    )
+                                    .also { config ->
+                                        Log.i(
+                                            TAG,
+                                            "device setting config for $cachedDevice is $config",
+                                        )
+                                    }
                             )
                         ServiceConnectionStatus.Connecting -> flowOf()
                         ServiceConnectionStatus.Failed -> flowOf(null)
@@ -146,21 +157,26 @@
         deviceInfo: DeviceInfo,
         service: IDeviceSettingsConfigProviderService,
     ): DeviceSettingsConfig? = suspendCancellableCoroutine { continuation ->
-        service.getDeviceSettingsConfig(
-            deviceInfo,
-            object : IGetDeviceSettingsConfigCallback.Stub() {
-                override fun onResult(
-                    status: DeviceSettingsConfigServiceStatus,
-                    config: DeviceSettingsConfig?,
-                ) {
-                    if (!status.success) {
-                        continuation.resume(null)
-                    } else {
-                        continuation.resume(config)
+        try {
+            service.getDeviceSettingsConfig(
+                deviceInfo,
+                object : IGetDeviceSettingsConfigCallback.Stub() {
+                    override fun onResult(
+                        status: DeviceSettingsConfigServiceStatus,
+                        config: DeviceSettingsConfig?,
+                    ) {
+                        if (!status.success) {
+                            continuation.resume(null)
+                        } else {
+                            continuation.resume(config)
+                        }
                     }
-                }
-            },
-        )
+                },
+            )
+        } catch (e: RemoteException) {
+            Log.i(TAG, "Fail to get config")
+            continuation.resume(null)
+        }
     }
 
     private val settingIdToItemMapping =
@@ -298,13 +314,16 @@
                 val serviceConnection =
                     object : ServiceConnection {
                         override fun onServiceConnected(name: ComponentName, service: IBinder) {
+                            Log.i(TAG, "Service connected for $intent")
                             launch { send(ServiceConnectionStatus.Connected(transform(service))) }
                         }
 
                         override fun onServiceDisconnected(name: ComponentName?) {
+                            Log.i(TAG, "Service disconnected for $intent")
                             launch { send(ServiceConnectionStatus.Connecting) }
                         }
                     }
+                Log.i(TAG, "Try to bind service for $intent")
                 if (
                     !context.bindService(
                         intent,
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/devicesettings/shared/model/DeviceSettingModel.kt b/packages/SettingsLib/src/com/android/settingslib/bluetooth/devicesettings/shared/model/DeviceSettingModel.kt
index 73648ac..4d9f2d6 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/devicesettings/shared/model/DeviceSettingModel.kt
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/devicesettings/shared/model/DeviceSettingModel.kt
@@ -16,6 +16,7 @@
 
 package com.android.settingslib.bluetooth.devicesettings.shared.model
 
+import android.app.PendingIntent
 import android.content.Intent
 import android.graphics.Bitmap
 import androidx.annotation.DrawableRes
@@ -34,7 +35,7 @@
         val title: String,
         val summary: String? = null,
         val icon: DeviceSettingIcon? = null,
-        val intent: Intent? = null,
+        val action: DeviceSettingActionModel? = null,
         val switchState: DeviceSettingStateModel.ActionSwitchPreferenceState? = null,
         val isAllowedChangingState: Boolean = true,
         val updateState: ((DeviceSettingStateModel.ActionSwitchPreferenceState) -> Unit)? = null,
@@ -83,3 +84,11 @@
 
     data class ResourceIcon(@DrawableRes val resId: Int) : DeviceSettingIcon
 }
+
+/** Models an action in device settings. */
+sealed interface DeviceSettingActionModel {
+
+    data class IntentAction(val intent: Intent) : DeviceSettingActionModel
+
+    data class PendingIntentAction(val pendingIntent: PendingIntent) : DeviceSettingActionModel
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/InputMediaDevice.java b/packages/SettingsLib/src/com/android/settingslib/media/InputMediaDevice.java
index 1d17b00..6335e71 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/InputMediaDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/InputMediaDevice.java
@@ -49,19 +49,23 @@
 
     private final boolean mIsVolumeFixed;
 
+    private final String mProductName;
+
     private InputMediaDevice(
             @NonNull Context context,
             @NonNull String id,
             @AudioDeviceType int audioDeviceInfoType,
             int maxVolume,
             int currentVolume,
-            boolean isVolumeFixed) {
+            boolean isVolumeFixed,
+            @Nullable String productName) {
         super(context, /* info= */ null, /* item= */ null);
         mId = id;
         mAudioDeviceInfoType = audioDeviceInfoType;
         mMaxVolume = maxVolume;
         mCurrentVolume = currentVolume;
         mIsVolumeFixed = isVolumeFixed;
+        mProductName = productName;
         initDeviceRecord();
     }
 
@@ -72,13 +76,20 @@
             @AudioDeviceType int audioDeviceInfoType,
             int maxVolume,
             int currentVolume,
-            boolean isVolumeFixed) {
+            boolean isVolumeFixed,
+            @Nullable String productName) {
         if (!isSupportedInputDevice(audioDeviceInfoType)) {
             return null;
         }
 
         return new InputMediaDevice(
-                context, id, audioDeviceInfoType, maxVolume, currentVolume, isVolumeFixed);
+                context,
+                id,
+                audioDeviceInfoType,
+                maxVolume,
+                currentVolume,
+                isVolumeFixed,
+                productName);
     }
 
     public @AudioDeviceType int getAudioDeviceInfoType() {
@@ -98,18 +109,25 @@
         };
     }
 
+    @Nullable
+    public String getProductName() {
+        return mProductName;
+    }
+
     @Override
     public @NonNull String getName() {
-        CharSequence name = switch (mAudioDeviceInfoType) {
-            case TYPE_WIRED_HEADSET -> mContext.getString(
-                    R.string.media_transfer_wired_device_mic_name);
-            case TYPE_USB_DEVICE, TYPE_USB_HEADSET, TYPE_USB_ACCESSORY -> mContext.getString(
-                    R.string.media_transfer_usb_device_mic_name);
-            case TYPE_BLUETOOTH_SCO -> mContext.getString(
-                    R.string.media_transfer_bt_device_mic_name);
+        return switch (mAudioDeviceInfoType) {
+            case TYPE_WIRED_HEADSET ->
+                    mContext.getString(R.string.media_transfer_wired_device_mic_name);
+            case TYPE_USB_DEVICE, TYPE_USB_HEADSET, TYPE_USB_ACCESSORY ->
+                    // The product name is assumed to be a well-formed string if it's not null.
+                    mProductName != null
+                            ? mProductName
+                            : mContext.getString(R.string.media_transfer_usb_device_mic_name);
+            case TYPE_BLUETOOTH_SCO ->
+                    mContext.getString(R.string.media_transfer_bt_device_mic_name);
             default -> mContext.getString(R.string.media_transfer_this_device_name_desktop);
         };
-        return name.toString();
     }
 
     @Override
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/InputRouteManager.java b/packages/SettingsLib/src/com/android/settingslib/media/InputRouteManager.java
index 9164b64..4f315a2 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/InputRouteManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/InputRouteManager.java
@@ -22,6 +22,7 @@
 import android.media.AudioDeviceAttributes;
 import android.media.AudioDeviceCallback;
 import android.media.AudioDeviceInfo;
+import android.media.AudioDeviceInfo.AudioDeviceType;
 import android.media.AudioManager;
 import android.media.MediaRecorder;
 import android.os.Handler;
@@ -63,7 +64,7 @@
 
     @VisibleForTesting final List<MediaDevice> mInputMediaDevices = new CopyOnWriteArrayList<>();
 
-    private MediaDevice mSelectedInputDevice;
+    private @AudioDeviceType int mSelectedInputDeviceType;
 
     private final Collection<InputDeviceCallback> mCallbacks = new CopyOnWriteArrayList<>();
     private final Object mCallbackLock = new Object();
@@ -73,12 +74,12 @@
             new AudioDeviceCallback() {
                 @Override
                 public void onAudioDevicesAdded(@NonNull AudioDeviceInfo[] addedDevices) {
-                    dispatchInputDeviceListUpdate();
+                    applyDefaultSelectedTypeToAllPresets();
                 }
 
                 @Override
                 public void onAudioDevicesRemoved(@NonNull AudioDeviceInfo[] removedDevices) {
-                    dispatchInputDeviceListUpdate();
+                    applyDefaultSelectedTypeToAllPresets();
                 }
             };
 
@@ -92,9 +93,12 @@
         mAudioManager.addOnPreferredDevicesForCapturePresetChangedListener(
                 new HandlerExecutor(handler),
                 this::onPreferredDevicesForCapturePresetChangedListener);
+
+        applyDefaultSelectedTypeToAllPresets();
     }
 
-    private void onPreferredDevicesForCapturePresetChangedListener(
+    @VisibleForTesting
+    void onPreferredDevicesForCapturePresetChangedListener(
             @MediaRecorder.SystemSource int capturePreset,
             @NonNull List<AudioDeviceAttributes> devices) {
         if (capturePreset == MediaRecorder.AudioSource.MIC) {
@@ -117,12 +121,30 @@
         }
     }
 
+    // TODO(b/355684672): handle edge case where there are two devices with the same type. Only
+    // using a single mSelectedInputDeviceType might not be enough to recognize the correct device.
     public @Nullable MediaDevice getSelectedInputDevice() {
-        return mSelectedInputDevice;
+        for (MediaDevice device : mInputMediaDevices) {
+            if (((InputMediaDevice) device).getAudioDeviceInfoType() == mSelectedInputDeviceType) {
+                return device;
+            }
+        }
+        return null;
     }
 
-    private void dispatchInputDeviceListUpdate() {
-        // Get selected input device.
+    private void applyDefaultSelectedTypeToAllPresets() {
+        mSelectedInputDeviceType = retrieveDefaultSelectedDeviceType();
+        AudioDeviceAttributes deviceAttributes =
+                createInputDeviceAttributes(mSelectedInputDeviceType);
+        setPreferredDeviceForAllPresets(deviceAttributes);
+    }
+
+    private AudioDeviceAttributes createInputDeviceAttributes(@AudioDeviceType int type) {
+        // Address is not used.
+        return new AudioDeviceAttributes(AudioDeviceAttributes.ROLE_INPUT, type, /* address= */ "");
+    }
+
+    private @AudioDeviceType int retrieveDefaultSelectedDeviceType() {
         List<AudioDeviceAttributes> attributesOfSelectedInputDevices =
                 mAudioManager.getDevicesForAttributes(INPUT_ATTRIBUTES);
         int selectedInputDeviceAttributesType;
@@ -138,7 +160,10 @@
             }
             selectedInputDeviceAttributesType = attributesOfSelectedInputDevices.get(0).getType();
         }
+        return selectedInputDeviceAttributesType;
+    }
 
+    private void dispatchInputDeviceListUpdate() {
         // Get all input devices.
         AudioDeviceInfo[] audioDeviceInfos =
                 mAudioManager.getDevices(AudioManager.GET_DEVICES_INPUTS);
@@ -151,11 +176,11 @@
                             info.getType(),
                             getMaxInputGain(),
                             getCurrentInputGain(),
-                            isInputGainFixed());
+                            isInputGainFixed(),
+                            getProductNameFromAudioDeviceInfo(info));
             if (mediaDevice != null) {
-                if (info.getType() == selectedInputDeviceAttributesType) {
+                if (info.getType() == mSelectedInputDeviceType) {
                     mediaDevice.setState(STATE_SELECTED);
-                    mSelectedInputDevice = mediaDevice;
                 }
                 mInputMediaDevices.add(mediaDevice);
             }
@@ -169,13 +194,32 @@
         }
     }
 
+    /**
+     * Gets the product name for the given {@link AudioDeviceInfo}.
+     *
+     * @return The product name for the given {@link AudioDeviceInfo}, or null if a suitable name
+     *     cannot be found.
+     */
+    @Nullable
+    private String getProductNameFromAudioDeviceInfo(AudioDeviceInfo deviceInfo) {
+        CharSequence productName = deviceInfo.getProductName();
+        if (productName == null) {
+            return null;
+        }
+        String productNameString = productName.toString();
+        if (productNameString.isBlank()) {
+            return null;
+        }
+        return productNameString;
+    }
+
     public void selectDevice(@NonNull MediaDevice device) {
-        if (!(device instanceof InputMediaDevice)) {
+        if (!(device instanceof InputMediaDevice inputMediaDevice)) {
             Slog.w(TAG, "This device is not an InputMediaDevice: " + device.getName());
             return;
         }
 
-        if (device.equals(mSelectedInputDevice)) {
+        if (inputMediaDevice.getAudioDeviceInfoType() == mSelectedInputDeviceType) {
             Slog.w(TAG, "This device is already selected: " + device.getName());
             return;
         }
@@ -186,12 +230,11 @@
             return;
         }
 
-        // TODO(b/355684672): apply address for BT devices.
+        // Update mSelectedInputDeviceType directly based on user action.
+        mSelectedInputDeviceType = inputMediaDevice.getAudioDeviceInfoType();
+
         AudioDeviceAttributes deviceAttributes =
-                new AudioDeviceAttributes(
-                        AudioDeviceAttributes.ROLE_INPUT,
-                        ((InputMediaDevice) device).getAudioDeviceInfoType(),
-                        /* address= */ "");
+                createInputDeviceAttributes(inputMediaDevice.getAudioDeviceInfoType());
         try {
             setPreferredDeviceForAllPresets(deviceAttributes);
         } catch (IllegalArgumentException e) {
@@ -212,13 +255,14 @@
 
     public int getMaxInputGain() {
         // TODO (b/357123335): use real input gain implementation.
-        // Using 15 for now since it matches the max index for output.
-        return 15;
+        // Using 100 for now since it matches the maximum input gain index in classic ChromeOS.
+        return 100;
     }
 
     public int getCurrentInputGain() {
         // TODO (b/357123335): use real input gain implementation.
-        return 8;
+        // Show a fixed full gain in UI before it really works per UX requirement.
+        return 100;
     }
 
     public boolean isInputGainFixed() {
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/PhoneMediaDevice.java b/packages/SettingsLib/src/com/android/settingslib/media/PhoneMediaDevice.java
index feaf7fb..b94e906 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/PhoneMediaDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/PhoneMediaDevice.java
@@ -15,6 +15,7 @@
  */
 package com.android.settingslib.media;
 
+import static android.content.pm.PackageManager.FEATURE_PC;
 import static android.media.MediaRoute2Info.TYPE_BUILTIN_SPEAKER;
 import static android.media.MediaRoute2Info.TYPE_DOCK;
 import static android.media.MediaRoute2Info.TYPE_HDMI;
@@ -29,8 +30,6 @@
 import static com.android.settingslib.media.MediaDevice.SelectionBehavior.SELECTION_BEHAVIOR_TRANSFER;
 
 import android.Manifest;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.graphics.drawable.Drawable;
@@ -43,6 +42,8 @@
 import android.util.Log;
 
 import androidx.annotation.VisibleForTesting;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
 
 import com.android.settingslib.R;
 import com.android.settingslib.media.flags.Flags;
@@ -72,7 +73,7 @@
             return context.getString(R.string.media_transfer_this_device_name_tv);
         } else if (isTablet()) {
             return context.getString(R.string.media_transfer_this_device_name_tablet);
-        } else if (inputRoutingEnabledAndIsDesktop()) {
+        } else if (inputRoutingEnabledAndIsDesktop(context)) {
             return context.getString(R.string.media_transfer_this_device_name_desktop);
         } else {
             return context.getString(R.string.media_transfer_this_device_name);
@@ -88,7 +89,7 @@
             case TYPE_WIRED_HEADSET:
             case TYPE_WIRED_HEADPHONES:
                 name =
-                        inputRoutingEnabledAndIsDesktop()
+                        inputRoutingEnabledAndIsDesktop(context)
                                 ? context.getString(R.string.media_transfer_headphone_name)
                                 : context.getString(R.string.media_transfer_wired_headphone_name);
                 break;
@@ -96,7 +97,7 @@
             case TYPE_USB_HEADSET:
             case TYPE_USB_ACCESSORY:
                 name =
-                        inputRoutingEnabledAndIsDesktop()
+                        inputRoutingEnabledAndIsDesktop(context)
                                 ? context.getString(R.string.media_transfer_usb_audio_name)
                                 : context.getString(R.string.media_transfer_wired_headphone_name);
                 break;
@@ -149,14 +150,13 @@
                 .contains("tablet");
     }
 
-    static boolean isDesktop() {
-        return Arrays.asList(SystemProperties.get("ro.build.characteristics").split(","))
-                .contains("desktop");
+    public static boolean isDesktop(@NonNull Context context) {
+        return context.getPackageManager().hasSystemFeature(FEATURE_PC);
     }
 
-    static boolean inputRoutingEnabledAndIsDesktop() {
+    public static boolean inputRoutingEnabledAndIsDesktop(@NonNull Context context) {
         return com.android.media.flags.Flags.enableAudioInputDeviceRoutingAndVolumeControl()
-                && isDesktop();
+                && isDesktop(context);
     }
 
     // MediaRoute2Info.getType was made public on API 34, but exists since API 30.
diff --git a/packages/SettingsLib/src/com/android/settingslib/notification/data/repository/FakeZenModeRepository.kt b/packages/SettingsLib/src/com/android/settingslib/notification/data/repository/FakeZenModeRepository.kt
index 43d7946..23be7ba 100644
--- a/packages/SettingsLib/src/com/android/settingslib/notification/data/repository/FakeZenModeRepository.kt
+++ b/packages/SettingsLib/src/com/android/settingslib/notification/data/repository/FakeZenModeRepository.kt
@@ -78,6 +78,10 @@
         mutableModesFlow.value = (mutableModesFlow.value.filter { it.id != modeId }) + mode
     }
 
+    fun clearModes() {
+        mutableModesFlow.value = listOf()
+    }
+
     fun getMode(id: String): ZenMode? {
         return mutableModesFlow.value.find { it.id == id }
     }
diff --git a/packages/SettingsLib/src/com/android/settingslib/volume/data/repository/AudioSharingRepository.kt b/packages/SettingsLib/src/com/android/settingslib/volume/data/repository/AudioSharingRepository.kt
index 2f8105a..b41e970 100644
--- a/packages/SettingsLib/src/com/android/settingslib/volume/data/repository/AudioSharingRepository.kt
+++ b/packages/SettingsLib/src/com/android/settingslib/volume/data/repository/AudioSharingRepository.kt
@@ -74,6 +74,8 @@
     /** The headset groupId to volume map during audio sharing. */
     val volumeMap: StateFlow<GroupIdToVolumes>
 
+    suspend fun audioSharingAvailable(): Boolean
+
     /** Set the volume of secondary headset during audio sharing. */
     suspend fun setSecondaryVolume(
         @IntRange(from = AUDIO_SHARING_VOLUME_MIN.toLong(), to = AUDIO_SHARING_VOLUME_MAX.toLong())
@@ -216,6 +218,12 @@
         }
             .stateIn(coroutineScope, SharingStarted.WhileSubscribed(), emptyMap())
 
+    override suspend fun audioSharingAvailable(): Boolean {
+        return withContext(backgroundCoroutineContext) {
+            BluetoothUtils.isAudioSharingEnabled()
+        }
+    }
+
     override suspend fun setSecondaryVolume(
         @IntRange(from = AUDIO_SHARING_VOLUME_MIN.toLong(), to = AUDIO_SHARING_VOLUME_MAX.toLong())
         volume: Int
@@ -262,6 +270,8 @@
         MutableStateFlow(BluetoothCsipSetCoordinator.GROUP_ID_INVALID)
     override val volumeMap: StateFlow<GroupIdToVolumes> = MutableStateFlow(emptyMap())
 
+    override suspend fun audioSharingAvailable(): Boolean = false
+
     override suspend fun setSecondaryVolume(
         @IntRange(from = AUDIO_SHARING_VOLUME_MIN.toLong(), to = AUDIO_SHARING_VOLUME_MAX.toLong())
         volume: Int
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/applications/ServiceListingTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/applications/ServiceListingTest.java
index 7ff0988..feef559 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/applications/ServiceListingTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/applications/ServiceListingTest.java
@@ -21,6 +21,7 @@
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyList;
+import static org.mockito.ArgumentMatchers.argThat;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.times;
@@ -29,6 +30,7 @@
 
 import android.content.ComponentName;
 import android.content.Context;
+import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.content.pm.ServiceInfo;
@@ -42,6 +44,7 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
+import org.mockito.ArgumentMatcher;
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.RuntimeEnvironment;
 
@@ -72,19 +75,26 @@
                 .build();
     }
 
+    private ArgumentMatcher<Intent> filterEquals(Intent intent) {
+        return (test) -> {
+            return intent.filterEquals(test);
+        };
+    }
+
     @Test
     public void testValidator() {
         ServiceInfo s1 = new ServiceInfo();
         s1.permission = "testPermission";
         s1.packageName = "pkg";
+        s1.name = "Service1";
         ServiceInfo s2 = new ServiceInfo();
         s2.permission = "testPermission";
         s2.packageName = "pkg2";
+        s2.name = "service2";
         ResolveInfo r1 = new ResolveInfo();
         r1.serviceInfo = s1;
         ResolveInfo r2 = new ResolveInfo();
         r2.serviceInfo = s2;
-
         when(mPm.queryIntentServicesAsUser(any(), anyInt(), anyInt())).thenReturn(
                 ImmutableList.of(r1, r2));
 
@@ -118,9 +128,11 @@
         ServiceInfo s1 = new ServiceInfo();
         s1.permission = "testPermission";
         s1.packageName = "pkg";
+        s1.name = "Service1";
         ServiceInfo s2 = new ServiceInfo();
         s2.permission = "testPermission";
         s2.packageName = "pkg2";
+        s2.name = "service2";
         ResolveInfo r1 = new ResolveInfo();
         r1.serviceInfo = s1;
         ResolveInfo r2 = new ResolveInfo();
@@ -193,4 +205,56 @@
         assertThat(Settings.Secure.getString(RuntimeEnvironment.application.getContentResolver(),
                 TEST_SETTING)).contains(testComponent2.flattenToString());
     }
+
+    @Test
+    public void testHasPermissionWithoutMeetingCurrentRegs() {
+        ServiceInfo s1 = new ServiceInfo();
+        s1.permission = "testPermission";
+        s1.packageName = "pkg";
+        s1.name = "Service1";
+        ServiceInfo s2 = new ServiceInfo();
+        s2.permission = "testPermission";
+        s2.packageName = "pkg2";
+        s2.name = "service2";
+        ResolveInfo r1 = new ResolveInfo();
+        r1.serviceInfo = s1;
+        ResolveInfo r2 = new ResolveInfo();
+        r2.serviceInfo = s2;
+
+        ComponentName approvedComponent = new ComponentName(s2.packageName, s2.name);
+
+        Settings.Secure.putString(
+                mContext.getContentResolver(), TEST_SETTING, approvedComponent.flattenToString());
+
+        when(mPm.queryIntentServicesAsUser(argThat(
+                filterEquals(new Intent(TEST_INTENT))), anyInt(), anyInt()))
+                .thenReturn(ImmutableList.of(r1));
+        when(mPm.queryIntentServicesAsUser(argThat(
+                filterEquals(new Intent().setComponent(approvedComponent))),
+                anyInt(), anyInt()))
+                .thenReturn(ImmutableList.of(r2));
+
+        mServiceListing = new ServiceListing.Builder(mContext)
+                .setTag("testTag")
+                .setSetting(TEST_SETTING)
+                .setNoun("testNoun")
+                .setIntentAction(TEST_INTENT)
+                .setValidator(info -> {
+                    if (info.packageName.equals("pkg")) {
+                        return true;
+                    }
+                    return false;
+                })
+                .setPermission("testPermission")
+                .build();
+        ServiceListing.Callback callback = mock(ServiceListing.Callback.class);
+        mServiceListing.addCallback(callback);
+        mServiceListing.reload();
+
+        verify(mPm, times(2)).queryIntentServicesAsUser(any(), anyInt(), anyInt());
+        ArgumentCaptor<List<ServiceInfo>> captor = ArgumentCaptor.forClass(List.class);
+        verify(callback, times(1)).onServicesReloaded(captor.capture());
+
+        assertThat(captor.getValue()).containsExactlyElementsIn(ImmutableList.of(s2, s1));
+    }
 }
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothEventManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothEventManagerTest.java
index b1489be..22b3150 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothEventManagerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothEventManagerTest.java
@@ -22,6 +22,7 @@
 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;
@@ -36,6 +37,7 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.os.UserHandle;
+import android.os.UserManager;
 import android.platform.test.flag.junit.SetFlagsRule;
 import android.telephony.TelephonyManager;
 
@@ -96,6 +98,8 @@
     private LocalBluetoothProfileManager mLocalProfileManager;
     @Mock
     private BluetoothUtils.ErrorListener mErrorListener;
+    @Mock
+    private LocalBluetoothLeBroadcast mBroadcast;
 
     private Context mContext;
     private Intent mIntent;
@@ -107,7 +111,7 @@
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
-        mContext = RuntimeEnvironment.application;
+        mContext = spy(RuntimeEnvironment.application);
 
         mBluetoothEventManager =
                 new BluetoothEventManager(
@@ -208,28 +212,14 @@
      */
     @Test
     public void dispatchProfileConnectionStateChanged_flagOff_noUpdateFallbackDevice() {
-        ShadowBluetoothAdapter shadowBluetoothAdapter =
-                Shadow.extract(BluetoothAdapter.getDefaultAdapter());
-        shadowBluetoothAdapter.setIsLeAudioBroadcastSourceSupported(
-                BluetoothStatusCodes.FEATURE_SUPPORTED);
-        shadowBluetoothAdapter.setIsLeAudioBroadcastAssistantSupported(
-                BluetoothStatusCodes.FEATURE_SUPPORTED);
-        mSetFlagsRule.disableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
-        LocalBluetoothLeBroadcast broadcast = mock(LocalBluetoothLeBroadcast.class);
-        when(broadcast.isProfileReady()).thenReturn(true);
-        LocalBluetoothLeBroadcastAssistant assistant =
-                mock(LocalBluetoothLeBroadcastAssistant.class);
-        when(assistant.isProfileReady()).thenReturn(true);
-        LocalBluetoothProfileManager profileManager = mock(LocalBluetoothProfileManager.class);
-        when(profileManager.getLeAudioBroadcastProfile()).thenReturn(broadcast);
-        when(profileManager.getLeAudioBroadcastAssistantProfile()).thenReturn(assistant);
-        when(mBtManager.getProfileManager()).thenReturn(profileManager);
+        setUpAudioSharing(/* enableFlag= */ false, /* enableFeature= */ true, /* enableProfile= */
+                true, /* workProfile= */ false);
         mBluetoothEventManager.dispatchProfileConnectionStateChanged(
                 mCachedBluetoothDevice,
                 BluetoothProfile.STATE_DISCONNECTED,
                 BluetoothProfile.LE_AUDIO_BROADCAST_ASSISTANT);
 
-        verify(broadcast, times(0)).updateFallbackActiveDeviceIfNeeded();
+        verify(mBroadcast, times(0)).updateFallbackActiveDeviceIfNeeded();
     }
 
     /**
@@ -239,28 +229,14 @@
      */
     @Test
     public void dispatchProfileConnectionStateChanged_notSupport_noUpdateFallbackDevice() {
-        ShadowBluetoothAdapter shadowBluetoothAdapter =
-                Shadow.extract(BluetoothAdapter.getDefaultAdapter());
-        shadowBluetoothAdapter.setIsLeAudioBroadcastSourceSupported(
-                BluetoothStatusCodes.FEATURE_NOT_SUPPORTED);
-        shadowBluetoothAdapter.setIsLeAudioBroadcastAssistantSupported(
-                BluetoothStatusCodes.FEATURE_SUPPORTED);
-        mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
-        LocalBluetoothLeBroadcast broadcast = mock(LocalBluetoothLeBroadcast.class);
-        when(broadcast.isProfileReady()).thenReturn(true);
-        LocalBluetoothLeBroadcastAssistant assistant =
-                mock(LocalBluetoothLeBroadcastAssistant.class);
-        when(assistant.isProfileReady()).thenReturn(true);
-        LocalBluetoothProfileManager profileManager = mock(LocalBluetoothProfileManager.class);
-        when(profileManager.getLeAudioBroadcastProfile()).thenReturn(broadcast);
-        when(profileManager.getLeAudioBroadcastAssistantProfile()).thenReturn(assistant);
-        when(mBtManager.getProfileManager()).thenReturn(profileManager);
+        setUpAudioSharing(/* enableFlag= */ true, /* enableFeature= */ false, /* enableProfile= */
+                true, /* workProfile= */ false);
         mBluetoothEventManager.dispatchProfileConnectionStateChanged(
                 mCachedBluetoothDevice,
                 BluetoothProfile.STATE_DISCONNECTED,
                 BluetoothProfile.LE_AUDIO_BROADCAST_ASSISTANT);
 
-        verify(broadcast, times(0)).updateFallbackActiveDeviceIfNeeded();
+        verify(mBroadcast, times(0)).updateFallbackActiveDeviceIfNeeded();
     }
 
     /**
@@ -270,28 +246,14 @@
      */
     @Test
     public void dispatchProfileConnectionStateChanged_profileNotReady_noUpdateFallbackDevice() {
-        ShadowBluetoothAdapter shadowBluetoothAdapter =
-                Shadow.extract(BluetoothAdapter.getDefaultAdapter());
-        shadowBluetoothAdapter.setIsLeAudioBroadcastSourceSupported(
-                BluetoothStatusCodes.FEATURE_SUPPORTED);
-        shadowBluetoothAdapter.setIsLeAudioBroadcastAssistantSupported(
-                BluetoothStatusCodes.FEATURE_SUPPORTED);
-        mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
-        LocalBluetoothLeBroadcast broadcast = mock(LocalBluetoothLeBroadcast.class);
-        when(broadcast.isProfileReady()).thenReturn(false);
-        LocalBluetoothLeBroadcastAssistant assistant =
-                mock(LocalBluetoothLeBroadcastAssistant.class);
-        when(assistant.isProfileReady()).thenReturn(true);
-        LocalBluetoothProfileManager profileManager = mock(LocalBluetoothProfileManager.class);
-        when(profileManager.getLeAudioBroadcastProfile()).thenReturn(broadcast);
-        when(profileManager.getLeAudioBroadcastAssistantProfile()).thenReturn(assistant);
-        when(mBtManager.getProfileManager()).thenReturn(profileManager);
+        setUpAudioSharing(/* enableFlag= */ true, /* enableFeature= */ true, /* enableProfile= */
+                false, /* workProfile= */ false);
         mBluetoothEventManager.dispatchProfileConnectionStateChanged(
                 mCachedBluetoothDevice,
                 BluetoothProfile.STATE_DISCONNECTED,
                 BluetoothProfile.LE_AUDIO_BROADCAST_ASSISTANT);
 
-        verify(broadcast, times(0)).updateFallbackActiveDeviceIfNeeded();
+        verify(mBroadcast, times(0)).updateFallbackActiveDeviceIfNeeded();
     }
 
     /**
@@ -301,28 +263,31 @@
      */
     @Test
     public void dispatchProfileConnectionStateChanged_notAssistantProfile_noUpdateFallbackDevice() {
-        ShadowBluetoothAdapter shadowBluetoothAdapter =
-                Shadow.extract(BluetoothAdapter.getDefaultAdapter());
-        shadowBluetoothAdapter.setIsLeAudioBroadcastSourceSupported(
-                BluetoothStatusCodes.FEATURE_SUPPORTED);
-        shadowBluetoothAdapter.setIsLeAudioBroadcastAssistantSupported(
-                BluetoothStatusCodes.FEATURE_SUPPORTED);
-        mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
-        LocalBluetoothLeBroadcast broadcast = mock(LocalBluetoothLeBroadcast.class);
-        when(broadcast.isProfileReady()).thenReturn(true);
-        LocalBluetoothLeBroadcastAssistant assistant =
-                mock(LocalBluetoothLeBroadcastAssistant.class);
-        when(assistant.isProfileReady()).thenReturn(true);
-        LocalBluetoothProfileManager profileManager = mock(LocalBluetoothProfileManager.class);
-        when(profileManager.getLeAudioBroadcastProfile()).thenReturn(broadcast);
-        when(profileManager.getLeAudioBroadcastAssistantProfile()).thenReturn(assistant);
-        when(mBtManager.getProfileManager()).thenReturn(profileManager);
+        setUpAudioSharing(/* enableFlag= */ true, /* enableFeature= */ true, /* enableProfile= */
+                true, /* workProfile= */ false);
         mBluetoothEventManager.dispatchProfileConnectionStateChanged(
                 mCachedBluetoothDevice,
                 BluetoothProfile.STATE_DISCONNECTED,
                 BluetoothProfile.LE_AUDIO);
 
-        verify(broadcast, times(0)).updateFallbackActiveDeviceIfNeeded();
+        verify(mBroadcast, times(0)).updateFallbackActiveDeviceIfNeeded();
+    }
+
+    /**
+     * dispatchProfileConnectionStateChanged should not call {@link
+     * LocalBluetoothLeBroadcast}#updateFallbackActiveDeviceIfNeeded when triggered for
+     * work profile.
+     */
+    @Test
+    public void dispatchProfileConnectionStateChanged_workProfile_noUpdateFallbackDevice() {
+        setUpAudioSharing(/* enableFlag= */ true, /* enableFeature= */ true, /* enableProfile= */
+                true, /* workProfile= */ true);
+        mBluetoothEventManager.dispatchProfileConnectionStateChanged(
+                mCachedBluetoothDevice,
+                BluetoothProfile.STATE_DISCONNECTED,
+                BluetoothProfile.LE_AUDIO_BROADCAST_ASSISTANT);
+
+        verify(mBroadcast).updateFallbackActiveDeviceIfNeeded();
     }
 
     /**
@@ -332,28 +297,40 @@
      */
     @Test
     public void dispatchProfileConnectionStateChanged_audioSharing_updateFallbackDevice() {
-        ShadowBluetoothAdapter shadowBluetoothAdapter =
-                Shadow.extract(BluetoothAdapter.getDefaultAdapter());
-        shadowBluetoothAdapter.setIsLeAudioBroadcastSourceSupported(
-                BluetoothStatusCodes.FEATURE_SUPPORTED);
-        shadowBluetoothAdapter.setIsLeAudioBroadcastAssistantSupported(
-                BluetoothStatusCodes.FEATURE_SUPPORTED);
-        mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
-        LocalBluetoothLeBroadcast broadcast = mock(LocalBluetoothLeBroadcast.class);
-        when(broadcast.isProfileReady()).thenReturn(true);
-        LocalBluetoothLeBroadcastAssistant assistant =
-                mock(LocalBluetoothLeBroadcastAssistant.class);
-        when(assistant.isProfileReady()).thenReturn(true);
-        LocalBluetoothProfileManager profileManager = mock(LocalBluetoothProfileManager.class);
-        when(profileManager.getLeAudioBroadcastProfile()).thenReturn(broadcast);
-        when(profileManager.getLeAudioBroadcastAssistantProfile()).thenReturn(assistant);
-        when(mBtManager.getProfileManager()).thenReturn(profileManager);
+        setUpAudioSharing(/* enableFlag= */ true, /* enableFeature= */ true, /* enableProfile= */
+                true, /* workProfile= */ false);
         mBluetoothEventManager.dispatchProfileConnectionStateChanged(
                 mCachedBluetoothDevice,
                 BluetoothProfile.STATE_DISCONNECTED,
                 BluetoothProfile.LE_AUDIO_BROADCAST_ASSISTANT);
 
-        verify(broadcast).updateFallbackActiveDeviceIfNeeded();
+        verify(mBroadcast).updateFallbackActiveDeviceIfNeeded();
+    }
+
+    private void setUpAudioSharing(boolean enableFlag, boolean enableFeature,
+            boolean enableProfile, boolean workProfile) {
+        if (enableFlag) {
+            mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
+        } else {
+            mSetFlagsRule.disableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
+        }
+        ShadowBluetoothAdapter shadowBluetoothAdapter =
+                Shadow.extract(BluetoothAdapter.getDefaultAdapter());
+        int code = enableFeature ? BluetoothStatusCodes.FEATURE_SUPPORTED
+                : BluetoothStatusCodes.FEATURE_NOT_SUPPORTED;
+        shadowBluetoothAdapter.setIsLeAudioBroadcastSourceSupported(code);
+        shadowBluetoothAdapter.setIsLeAudioBroadcastAssistantSupported(code);
+        when(mBroadcast.isProfileReady()).thenReturn(enableProfile);
+        LocalBluetoothLeBroadcastAssistant assistant =
+                mock(LocalBluetoothLeBroadcastAssistant.class);
+        when(assistant.isProfileReady()).thenReturn(enableProfile);
+        LocalBluetoothProfileManager profileManager = mock(LocalBluetoothProfileManager.class);
+        when(profileManager.getLeAudioBroadcastProfile()).thenReturn(mBroadcast);
+        when(profileManager.getLeAudioBroadcastAssistantProfile()).thenReturn(assistant);
+        when(mBtManager.getProfileManager()).thenReturn(profileManager);
+        UserManager userManager = mock(UserManager.class);
+        when(mContext.getSystemService(UserManager.class)).thenReturn(userManager);
+        when(userManager.isManagedProfile()).thenReturn(workProfile);
     }
 
     @Test
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java
index 0d81494..70cb2ef 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java
@@ -1977,12 +1977,12 @@
     }
 
     @Test
-    public void getConnectionSummary_isBroadcastPrimary_returnActive() {
+    public void getConnectionSummary_isBroadcastPrimary_fallbackDevice_returnActive() {
         when(mBroadcast.isEnabled(any())).thenReturn(true);
         when(mCachedDevice.getDevice()).thenReturn(mDevice);
         Settings.Secure.putInt(
                 mContext.getContentResolver(),
-                "bluetooth_le_broadcast_fallback_active_group_id",
+                BluetoothUtils.getPrimaryGroupIdUriForBroadcast(),
                 1);
 
         List<Long> bisSyncState = new ArrayList<>();
@@ -1992,12 +1992,30 @@
         sourceList.add(mLeBroadcastReceiveState);
         when(mAssistant.getAllSources(any())).thenReturn(sourceList);
 
-        when(mCachedDevice.getGroupId())
-                .thenReturn(
-                        Settings.Secure.getInt(
-                                mContext.getContentResolver(),
-                                "bluetooth_le_broadcast_fallback_active_group_id",
-                                BluetoothCsipSetCoordinator.GROUP_ID_INVALID));
+        when(mCachedDevice.getGroupId()).thenReturn(1);
+
+        assertThat(mCachedDevice.getConnectionSummary(false))
+                .isEqualTo(mContext.getString(R.string.bluetooth_active_no_battery_level));
+    }
+
+    @Test
+    public void getConnectionSummary_isBroadcastPrimary_activeDevice_returnActive() {
+        when(mBroadcast.isEnabled(any())).thenReturn(true);
+        when(mCachedDevice.getDevice()).thenReturn(mDevice);
+        Settings.Secure.putInt(
+                mContext.getContentResolver(),
+                BluetoothUtils.getPrimaryGroupIdUriForBroadcast(),
+                BluetoothCsipSetCoordinator.GROUP_ID_INVALID);
+
+        List<Long> bisSyncState = new ArrayList<>();
+        bisSyncState.add(1L);
+        when(mLeBroadcastReceiveState.getBisSyncState()).thenReturn(bisSyncState);
+        List<BluetoothLeBroadcastReceiveState> sourceList = new ArrayList<>();
+        sourceList.add(mLeBroadcastReceiveState);
+        when(mAssistant.getAllSources(any())).thenReturn(sourceList);
+
+        when(mCachedDevice.getGroupId()).thenReturn(1);
+        when(mCachedDevice.isActiveDevice(BluetoothProfile.LE_AUDIO)).thenReturn(true);
 
         assertThat(mCachedDevice.getConnectionSummary(false))
                 .isEqualTo(mContext.getString(R.string.bluetooth_active_no_battery_level));
@@ -2009,7 +2027,7 @@
         when(mCachedDevice.getDevice()).thenReturn(mDevice);
         Settings.Secure.putInt(
                 mContext.getContentResolver(),
-                "bluetooth_le_broadcast_fallback_active_group_id",
+                BluetoothUtils.getPrimaryGroupIdUriForBroadcast(),
                 1);
 
         List<Long> bisSyncState = new ArrayList<>();
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CsipDeviceManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CsipDeviceManagerTest.java
index b180b69..fd14d1f 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CsipDeviceManagerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CsipDeviceManagerTest.java
@@ -39,6 +39,7 @@
 import android.content.Context;
 import android.os.Looper;
 import android.os.Parcel;
+import android.os.UserManager;
 import android.platform.test.flag.junit.SetFlagsRule;
 
 import com.android.settingslib.flags.Flags;
@@ -104,6 +105,8 @@
     private LocalBluetoothLeBroadcast mBroadcast;
     @Mock
     private LocalBluetoothLeBroadcastAssistant mAssistant;
+    @Mock
+    private UserManager mUserManager;
 
     private ShadowBluetoothAdapter mShadowBluetoothAdapter;
     private CachedBluetoothDevice mCachedDevice1;
@@ -128,7 +131,7 @@
     public void setUp() {
         MockitoAnnotations.initMocks(this);
 
-        mContext = RuntimeEnvironment.application;
+        mContext = spy(RuntimeEnvironment.application);
         mShadowBluetoothAdapter = Shadow.extract(BluetoothAdapter.getDefaultAdapter());
         mShadowBluetoothAdapter.setEnabled(true);
         mShadowBluetoothAdapter.setIsLeAudioBroadcastSourceSupported(
@@ -356,6 +359,37 @@
     }
 
     @Test
+    public void
+            addMemberDevicesIntoMainDevice_preferredDeviceIsMainAndTwoMain_workProfile_doNothing() {
+        // Condition: The preferredDevice is main and there is another main device in top list
+        // Expected Result: return true and there is the preferredDevice in top list
+        CachedBluetoothDevice preferredDevice = mCachedDevice1;
+        mCachedDevice1.getMemberDevice().clear();
+        mCachedDevices.clear();
+        mCachedDevices.add(preferredDevice);
+        mCachedDevices.add(mCachedDevice2);
+        mCachedDevices.add(mCachedDevice3);
+        mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
+        when(mBroadcast.isEnabled(null)).thenReturn(true);
+        BluetoothLeBroadcastMetadata metadata = Mockito.mock(BluetoothLeBroadcastMetadata.class);
+        when(mBroadcast.getLatestBluetoothLeBroadcastMetadata()).thenReturn(metadata);
+        BluetoothLeBroadcastReceiveState state = Mockito.mock(
+                BluetoothLeBroadcastReceiveState.class);
+        when(state.getBisSyncState()).thenReturn(ImmutableList.of(1L));
+        when(mAssistant.getAllSources(mDevice2)).thenReturn(ImmutableList.of(state));
+        when(mContext.getSystemService(UserManager.class)).thenReturn(mUserManager);
+        when(mUserManager.isManagedProfile()).thenReturn(true);
+
+        assertThat(mCsipDeviceManager.addMemberDevicesIntoMainDevice(GROUP1, preferredDevice))
+                .isTrue();
+        assertThat(mCachedDevices.contains(preferredDevice)).isTrue();
+        assertThat(mCachedDevices.contains(mCachedDevice2)).isFalse();
+        assertThat(mCachedDevices.contains(mCachedDevice3)).isTrue();
+        assertThat(preferredDevice.getMemberDevice()).contains(mCachedDevice2);
+        verify(mAssistant, never()).addSource(mDevice1, metadata, /* isGroupOp= */ false);
+    }
+
+    @Test
     public void addMemberDevicesIntoMainDevice_preferredDeviceIsMainAndTwoMain_syncSource() {
         // Condition: The preferredDevice is main and there is another main device in top list
         // Expected Result: return true and there is the preferredDevice in top list
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/devicesettings/ActionSwitchPreferenceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/devicesettings/ActionSwitchPreferenceTest.java
index 354d0f6..7148618 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/devicesettings/ActionSwitchPreferenceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/devicesettings/ActionSwitchPreferenceTest.java
@@ -50,11 +50,15 @@
 
     @Test
     public void build_withAllFields_successfully() {
+        DeviceSettingIntentAction action =
+                new DeviceSettingIntentAction.Builder()
+                        .setIntent(new Intent("intent_action"))
+                        .build();
         ActionSwitchPreference unused =
                 new ActionSwitchPreference.Builder()
                         .setTitle("title")
                         .setSummary("summary")
-                        .setIntent(new Intent("intent_action"))
+                        .setAction(action)
                         .setIcon(Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888))
                         .setHasSwitch(true)
                         .setChecked(true)
@@ -65,14 +69,17 @@
 
     @Test
     public void getMethods() {
-        Intent intent = new Intent("intent_action");
+        DeviceSettingIntentAction action =
+                new DeviceSettingIntentAction.Builder()
+                        .setIntent(new Intent("intent_action"))
+                        .build();
         Bitmap icon = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888);
-        ActionSwitchPreference preference = builder().setIcon(icon).setIntent(intent).build();
+        ActionSwitchPreference preference = builder().setIcon(icon).setAction(action).build();
 
         assertThat(preference.getTitle()).isEqualTo("title");
         assertThat(preference.getSummary()).isEqualTo("summary");
         assertThat(preference.getIcon()).isSameInstanceAs(icon);
-        assertThat(preference.getIntent()).isSameInstanceAs(intent);
+        assertThat(preference.getAction()).isSameInstanceAs(action);
         assertThat(preference.hasSwitch()).isTrue();
         assertThat(preference.getChecked()).isTrue();
         assertThat(preference.isAllowedChangingState()).isTrue();
@@ -81,16 +88,20 @@
 
     @Test
     public void parcelOperation() {
-        Intent intent = new Intent("intent_action");
+        DeviceSettingIntentAction action =
+                new DeviceSettingIntentAction.Builder()
+                        .setIntent(new Intent("intent_action"))
+                        .build();
         Bitmap icon = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888);
-        ActionSwitchPreference preference = builder().setIcon(icon).setIntent(intent).build();
+        ActionSwitchPreference preference = builder().setIcon(icon).setAction(action).build();
 
         ActionSwitchPreference fromParcel = writeAndRead(preference);
 
         assertThat(fromParcel.getTitle()).isEqualTo(preference.getTitle());
         assertThat(fromParcel.getSummary()).isEqualTo(preference.getSummary());
         assertThat(fromParcel.getIcon().sameAs(preference.getIcon())).isTrue();
-        assertThat(fromParcel.getIntent().getAction()).isSameInstanceAs("intent_action");
+        assertThat(((DeviceSettingIntentAction) fromParcel.getAction()).getIntent().getAction())
+                .isEqualTo("intent_action");
         assertThat(fromParcel.hasSwitch()).isEqualTo(preference.hasSwitch());
         assertThat(fromParcel.getChecked()).isEqualTo(preference.getChecked());
         assertThat(fromParcel.isAllowedChangingState())
@@ -102,14 +113,15 @@
     @Test
     public void parcelOperation_noIntent() {
         Bitmap icon = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888);
-        ActionSwitchPreference preference = builder().setIcon(icon).setIntent(null).build();
+        ActionSwitchPreference preference = builder().setIcon(icon).setAction(null).build();
 
         ActionSwitchPreference fromParcel = writeAndRead(preference);
 
         assertThat(fromParcel.getTitle()).isEqualTo(preference.getTitle());
         assertThat(fromParcel.getSummary()).isEqualTo(preference.getSummary());
         assertThat(fromParcel.getIcon().sameAs(preference.getIcon())).isTrue();
-        assertThat(preference.getIntent()).isNull();
+        assertThat(preference.getAction().getActionType())
+                .isEqualTo(DeviceSettingActionType.DEVICE_SETTING_ACTION_TYPE_UNKNOWN);
         assertThat(fromParcel.hasSwitch()).isEqualTo(preference.hasSwitch());
         assertThat(fromParcel.getChecked()).isEqualTo(preference.getChecked());
         assertThat(fromParcel.isAllowedChangingState())
@@ -120,15 +132,19 @@
 
     @Test
     public void parcelOperation_noIcon() {
-        Intent intent = new Intent("intent_action");
-        ActionSwitchPreference preference = builder().setIcon(null).setIntent(intent).build();
+        DeviceSettingIntentAction action =
+                new DeviceSettingIntentAction.Builder()
+                        .setIntent(new Intent("intent_action"))
+                        .build();
+        ActionSwitchPreference preference = builder().setIcon(null).setAction(action).build();
 
         ActionSwitchPreference fromParcel = writeAndRead(preference);
 
         assertThat(fromParcel.getTitle()).isEqualTo(preference.getTitle());
         assertThat(fromParcel.getSummary()).isEqualTo(preference.getSummary());
         assertThat(fromParcel.getIcon()).isNull();
-        assertThat(fromParcel.getIntent().getAction()).isSameInstanceAs("intent_action");
+        assertThat(((DeviceSettingIntentAction) fromParcel.getAction()).getIntent().getAction())
+                .isEqualTo("intent_action");
         assertThat(fromParcel.hasSwitch()).isEqualTo(preference.hasSwitch());
         assertThat(fromParcel.getChecked()).isEqualTo(preference.getChecked());
         assertThat(fromParcel.isAllowedChangingState())
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/devicesettings/DeviceSettingIntentActionTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/devicesettings/DeviceSettingIntentActionTest.java
new file mode 100644
index 0000000..d33db4f
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/devicesettings/DeviceSettingIntentActionTest.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.bluetooth.devicesettings;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.Parcel;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+
+@RunWith(RobolectricTestRunner.class)
+public final class DeviceSettingIntentActionTest {
+
+    @Test
+    public void getMethods() {
+        DeviceSettingIntentAction action =
+                new DeviceSettingIntentAction.Builder()
+                        .setIntent(new Intent("intent_action"))
+                        .setExtras(buildBundle("key1", "value1"))
+                        .build();
+
+        assertThat(action.getIntent().getAction()).isEqualTo("intent_action");
+        assertThat(action.getExtras().getString("key1")).isEqualTo("value1");
+    }
+
+    @Test
+    public void parcelOperation() {
+        DeviceSettingIntentAction action =
+                new DeviceSettingIntentAction.Builder()
+                        .setIntent(new Intent("intent_action"))
+                        .setExtras(buildBundle("key1", "value1"))
+                        .build();
+
+        DeviceSettingIntentAction fromParcel = writeAndRead(action);
+
+        assertThat(fromParcel.getIntent().getAction()).isEqualTo(action.getIntent().getAction());
+        assertThat(fromParcel.getExtras().getString("key1"))
+                .isEqualTo(action.getExtras().getString("key1"));
+    }
+
+    private Bundle buildBundle(String key, String value) {
+        Bundle bundle = new Bundle();
+        bundle.putString(key, value);
+        return bundle;
+    }
+
+    private DeviceSettingIntentAction writeAndRead(DeviceSettingIntentAction preference) {
+        Parcel parcel = Parcel.obtain();
+        preference.writeToParcel(parcel, 0);
+        parcel.setDataPosition(0);
+        DeviceSettingIntentAction fromParcel =
+                DeviceSettingIntentAction.CREATOR.createFromParcel(parcel);
+        return fromParcel;
+    }
+}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/devicesettings/DeviceSettingPendingIntentActionTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/devicesettings/DeviceSettingPendingIntentActionTest.java
new file mode 100644
index 0000000..3c35147
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/devicesettings/DeviceSettingPendingIntentActionTest.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.bluetooth.devicesettings;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.app.PendingIntent;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.Parcel;
+
+import androidx.test.core.app.ApplicationProvider;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+
+@RunWith(RobolectricTestRunner.class)
+public final class DeviceSettingPendingIntentActionTest {
+
+    private Context mContext = ApplicationProvider.getApplicationContext();
+
+    @Test
+    public void getMethods() {
+        DeviceSettingPendingIntentAction action =
+                new DeviceSettingPendingIntentAction.Builder()
+                        .setPendingIntent(
+                                PendingIntent.getBroadcast(mContext, 0, new Intent("action"), 0))
+                        .setExtras(buildBundle("key1", "value1"))
+                        .build();
+
+        assertThat(action.getPendingIntent()).isSameInstanceAs(action.getPendingIntent());
+        assertThat(action.getExtras().getString("key1")).isEqualTo("value1");
+    }
+
+    @Test
+    public void parcelOperation() {
+        DeviceSettingPendingIntentAction action =
+                new DeviceSettingPendingIntentAction.Builder()
+                        .setPendingIntent(
+                                PendingIntent.getBroadcast(mContext, 0, new Intent("action"), 0))
+                        .setExtras(buildBundle("key1", "value1"))
+                        .build();
+
+        DeviceSettingPendingIntentAction fromParcel = writeAndRead(action);
+
+        assertThat(action.getPendingIntent().getIntent())
+                .isEqualTo(action.getPendingIntent().getIntent());
+        assertThat(fromParcel.getExtras().getString("key1"))
+                .isEqualTo(action.getExtras().getString("key1"));
+    }
+
+    private Bundle buildBundle(String key, String value) {
+        Bundle bundle = new Bundle();
+        bundle.putString(key, value);
+        return bundle;
+    }
+
+    private DeviceSettingPendingIntentAction writeAndRead(
+            DeviceSettingPendingIntentAction preference) {
+        Parcel parcel = Parcel.obtain();
+        preference.writeToParcel(parcel, 0);
+        parcel.setDataPosition(0);
+        DeviceSettingPendingIntentAction fromParcel =
+                DeviceSettingPendingIntentAction.CREATOR.createFromParcel(parcel);
+        return fromParcel;
+    }
+}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InputMediaDeviceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InputMediaDeviceTest.java
index 30e4637..6c1cb70 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InputMediaDeviceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InputMediaDeviceTest.java
@@ -41,6 +41,9 @@
     private final int MAX_VOLUME = 1;
     private final int CURRENT_VOLUME = 0;
     private final boolean IS_VOLUME_FIXED = true;
+    private static final String PRODUCT_NAME_BUILTIN_MIC = "Built-in Mic";
+    private static final String PRODUCT_NAME_WIRED_HEADSET = "My Wired Headset";
+    private static final String PRODUCT_NAME_USB_HEADSET = "My USB Headset";
 
     @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
 
@@ -60,7 +63,8 @@
                         AudioDeviceInfo.TYPE_BUILTIN_MIC,
                         MAX_VOLUME,
                         CURRENT_VOLUME,
-                        IS_VOLUME_FIXED);
+                        IS_VOLUME_FIXED,
+                        PRODUCT_NAME_BUILTIN_MIC);
         assertThat(builtinMediaDevice).isNotNull();
         assertThat(builtinMediaDevice.getDrawableResId()).isEqualTo(R.drawable.ic_media_microphone);
     }
@@ -74,7 +78,8 @@
                         AudioDeviceInfo.TYPE_BUILTIN_MIC,
                         MAX_VOLUME,
                         CURRENT_VOLUME,
-                        IS_VOLUME_FIXED);
+                        IS_VOLUME_FIXED,
+                        PRODUCT_NAME_BUILTIN_MIC);
         assertThat(builtinMediaDevice).isNotNull();
         assertThat(builtinMediaDevice.getName())
                 .isEqualTo(mContext.getString(R.string.media_transfer_this_device_name_desktop));
@@ -89,7 +94,8 @@
                         AudioDeviceInfo.TYPE_WIRED_HEADSET,
                         MAX_VOLUME,
                         CURRENT_VOLUME,
-                        IS_VOLUME_FIXED);
+                        IS_VOLUME_FIXED,
+                        PRODUCT_NAME_WIRED_HEADSET);
         assertThat(wiredMediaDevice).isNotNull();
         assertThat(wiredMediaDevice.getName())
                 .isEqualTo(mContext.getString(R.string.media_transfer_wired_device_mic_name));
@@ -104,7 +110,23 @@
                         AudioDeviceInfo.TYPE_USB_HEADSET,
                         MAX_VOLUME,
                         CURRENT_VOLUME,
-                        IS_VOLUME_FIXED);
+                        IS_VOLUME_FIXED,
+                        PRODUCT_NAME_USB_HEADSET);
+        assertThat(usbMediaDevice).isNotNull();
+        assertThat(usbMediaDevice.getName()).isEqualTo(PRODUCT_NAME_USB_HEADSET);
+    }
+
+    @Test
+    public void getName_returnCorrectName_usbHeadset_nullProductName() {
+        InputMediaDevice usbMediaDevice =
+                InputMediaDevice.create(
+                        mContext,
+                        String.valueOf(USB_HEADSET_ID),
+                        AudioDeviceInfo.TYPE_USB_HEADSET,
+                        MAX_VOLUME,
+                        CURRENT_VOLUME,
+                        IS_VOLUME_FIXED,
+                        null);
         assertThat(usbMediaDevice).isNotNull();
         assertThat(usbMediaDevice.getName())
                 .isEqualTo(mContext.getString(R.string.media_transfer_usb_device_mic_name));
@@ -119,7 +141,8 @@
                         AudioDeviceInfo.TYPE_BLUETOOTH_SCO,
                         MAX_VOLUME,
                         CURRENT_VOLUME,
-                        IS_VOLUME_FIXED);
+                        IS_VOLUME_FIXED,
+                        null);
         assertThat(btMediaDevice).isNotNull();
         assertThat(btMediaDevice.getName())
                 .isEqualTo(mContext.getString(R.string.media_transfer_bt_device_mic_name));
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InputRouteManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InputRouteManagerTest.java
index 16c0c1c..782cee2 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InputRouteManagerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InputRouteManagerTest.java
@@ -21,6 +21,7 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.mockito.Mockito.atLeast;
 import static org.mockito.Mockito.atLeastOnce;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.spy;
@@ -55,13 +56,95 @@
     private static final int INPUT_USB_DEVICE_ID = 3;
     private static final int INPUT_USB_HEADSET_ID = 4;
     private static final int INPUT_USB_ACCESSORY_ID = 5;
+    private static final int HDMI_ID = 6;
     private static final int MAX_VOLUME = 1;
     private static final int CURRENT_VOLUME = 0;
     private static final boolean VOLUME_FIXED_TRUE = true;
+    private static final String PRODUCT_NAME_BUILTIN_MIC = "Built-in Mic";
+    private static final String PRODUCT_NAME_WIRED_HEADSET = "My Wired Headset";
+    private static final String PRODUCT_NAME_USB_HEADSET = "My USB Headset";
+    private static final String PRODUCT_NAME_USB_DEVICE = "My USB Device";
+    private static final String PRODUCT_NAME_USB_ACCESSORY = "My USB Accessory";
+    private static final String PRODUCT_NAME_HDMI_DEVICE = "HDMI device";
 
     private final Context mContext = spy(RuntimeEnvironment.application);
     private InputRouteManager mInputRouteManager;
 
+    private AudioDeviceInfo mockBuiltinMicInfo() {
+        final AudioDeviceInfo info = mock(AudioDeviceInfo.class);
+        when(info.getType()).thenReturn(AudioDeviceInfo.TYPE_BUILTIN_MIC);
+        when(info.getId()).thenReturn(BUILTIN_MIC_ID);
+        when(info.getAddress()).thenReturn("");
+        when(info.getProductName()).thenReturn(PRODUCT_NAME_BUILTIN_MIC);
+        return info;
+    }
+
+    private AudioDeviceInfo mockWiredHeadsetInfo() {
+        final AudioDeviceInfo info = mock(AudioDeviceInfo.class);
+        when(info.getType()).thenReturn(AudioDeviceInfo.TYPE_WIRED_HEADSET);
+        when(info.getId()).thenReturn(INPUT_WIRED_HEADSET_ID);
+        when(info.getAddress()).thenReturn("");
+        when(info.getProductName()).thenReturn(PRODUCT_NAME_WIRED_HEADSET);
+        return info;
+    }
+
+    private AudioDeviceInfo mockUsbDeviceInfo() {
+        final AudioDeviceInfo info = mock(AudioDeviceInfo.class);
+        when(info.getType()).thenReturn(AudioDeviceInfo.TYPE_USB_DEVICE);
+        when(info.getId()).thenReturn(INPUT_USB_DEVICE_ID);
+        when(info.getAddress()).thenReturn("");
+        when(info.getProductName()).thenReturn(PRODUCT_NAME_USB_DEVICE);
+        return info;
+    }
+
+    private AudioDeviceInfo mockUsbHeadsetInfo() {
+        final AudioDeviceInfo info = mock(AudioDeviceInfo.class);
+        when(info.getType()).thenReturn(AudioDeviceInfo.TYPE_USB_HEADSET);
+        when(info.getId()).thenReturn(INPUT_USB_HEADSET_ID);
+        when(info.getAddress()).thenReturn("");
+        when(info.getProductName()).thenReturn(PRODUCT_NAME_USB_HEADSET);
+        return info;
+    }
+
+    private AudioDeviceInfo mockUsbAccessoryInfo() {
+        final AudioDeviceInfo info = mock(AudioDeviceInfo.class);
+        when(info.getType()).thenReturn(AudioDeviceInfo.TYPE_USB_ACCESSORY);
+        when(info.getId()).thenReturn(INPUT_USB_ACCESSORY_ID);
+        when(info.getAddress()).thenReturn("");
+        when(info.getProductName()).thenReturn(PRODUCT_NAME_USB_ACCESSORY);
+        return info;
+    }
+
+    private AudioDeviceInfo mockHdmiInfo() {
+        final AudioDeviceInfo info = mock(AudioDeviceInfo.class);
+        when(info.getType()).thenReturn(AudioDeviceInfo.TYPE_HDMI);
+        when(info.getId()).thenReturn(HDMI_ID);
+        when(info.getAddress()).thenReturn("");
+        when(info.getProductName()).thenReturn(PRODUCT_NAME_HDMI_DEVICE);
+        return info;
+    }
+
+    private AudioDeviceAttributes getBuiltinMicDeviceAttributes() {
+        return new AudioDeviceAttributes(
+                AudioDeviceAttributes.ROLE_INPUT,
+                AudioDeviceInfo.TYPE_BUILTIN_MIC,
+                /* address= */ "");
+    }
+
+    private AudioDeviceAttributes getWiredHeadsetDeviceAttributes() {
+        return new AudioDeviceAttributes(
+                AudioDeviceAttributes.ROLE_INPUT,
+                AudioDeviceInfo.TYPE_WIRED_HEADSET,
+                /* address= */ "");
+    }
+
+    private void onPreferredDevicesForCapturePresetChanged(InputRouteManager inputRouteManager) {
+        final List<AudioDeviceAttributes> audioDeviceAttributesList =
+                new ArrayList<AudioDeviceAttributes>();
+        inputRouteManager.onPreferredDevicesForCapturePresetChangedListener(
+                MediaRecorder.AudioSource.MIC, audioDeviceAttributesList);
+    }
+
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
@@ -72,31 +155,15 @@
 
     @Test
     public void onAudioDevicesAdded_shouldUpdateInputMediaDevice() {
-        final AudioDeviceInfo info1 = mock(AudioDeviceInfo.class);
-        when(info1.getType()).thenReturn(AudioDeviceInfo.TYPE_BUILTIN_MIC);
-        when(info1.getId()).thenReturn(BUILTIN_MIC_ID);
-
-        final AudioDeviceInfo info2 = mock(AudioDeviceInfo.class);
-        when(info2.getType()).thenReturn(AudioDeviceInfo.TYPE_WIRED_HEADSET);
-        when(info2.getId()).thenReturn(INPUT_WIRED_HEADSET_ID);
-
-        final AudioDeviceInfo info3 = mock(AudioDeviceInfo.class);
-        when(info3.getType()).thenReturn(AudioDeviceInfo.TYPE_USB_DEVICE);
-        when(info3.getId()).thenReturn(INPUT_USB_DEVICE_ID);
-
-        final AudioDeviceInfo info4 = mock(AudioDeviceInfo.class);
-        when(info4.getType()).thenReturn(AudioDeviceInfo.TYPE_USB_HEADSET);
-        when(info4.getId()).thenReturn(INPUT_USB_HEADSET_ID);
-
-        final AudioDeviceInfo info5 = mock(AudioDeviceInfo.class);
-        when(info5.getType()).thenReturn(AudioDeviceInfo.TYPE_USB_ACCESSORY);
-        when(info5.getId()).thenReturn(INPUT_USB_ACCESSORY_ID);
-
-        final AudioDeviceInfo unsupportedInfo = mock(AudioDeviceInfo.class);
-        when(unsupportedInfo.getType()).thenReturn(AudioDeviceInfo.TYPE_HDMI);
-
         final AudioManager audioManager = mock(AudioManager.class);
-        AudioDeviceInfo[] devices = {info1, info2, info3, info4, info5, unsupportedInfo};
+        AudioDeviceInfo[] devices = {
+            mockBuiltinMicInfo(),
+            mockWiredHeadsetInfo(),
+            mockUsbDeviceInfo(),
+            mockUsbHeadsetInfo(),
+            mockUsbAccessoryInfo(),
+            mockHdmiInfo()
+        };
         when(audioManager.getDevices(AudioManager.GET_DEVICES_INPUTS)).thenReturn(devices);
 
         InputRouteManager inputRouteManager = new InputRouteManager(mContext, audioManager);
@@ -104,8 +171,9 @@
         assertThat(inputRouteManager.mInputMediaDevices).isEmpty();
 
         inputRouteManager.mAudioDeviceCallback.onAudioDevicesAdded(devices);
+        onPreferredDevicesForCapturePresetChanged(inputRouteManager);
 
-        // The unsupported info should be filtered out.
+        // The unsupported (hdmi) info should be filtered out.
         assertThat(inputRouteManager.mInputMediaDevices).hasSize(devices.length - 1);
         assertThat(inputRouteManager.mInputMediaDevices.get(0).getId())
                 .isEqualTo(String.valueOf(BUILTIN_MIC_ID));
@@ -130,34 +198,25 @@
         final MediaDevice device = mock(MediaDevice.class);
         inputRouteManager.mInputMediaDevices.add(device);
 
-        final AudioDeviceInfo info = mock(AudioDeviceInfo.class);
-        when(info.getType()).thenReturn(AudioDeviceInfo.TYPE_WIRED_HEADSET);
-        inputRouteManager.mAudioDeviceCallback.onAudioDevicesRemoved(new AudioDeviceInfo[] {info});
+        inputRouteManager.mAudioDeviceCallback.onAudioDevicesRemoved(
+                new AudioDeviceInfo[] {mockWiredHeadsetInfo()});
+        onPreferredDevicesForCapturePresetChanged(inputRouteManager);
 
         assertThat(inputRouteManager.mInputMediaDevices).isEmpty();
     }
 
     @Test
     public void getSelectedInputDevice_returnOneFromAudioManager() {
-        final AudioDeviceInfo info1 = mock(AudioDeviceInfo.class);
-        when(info1.getType()).thenReturn(AudioDeviceInfo.TYPE_WIRED_HEADSET);
-        when(info1.getId()).thenReturn(INPUT_WIRED_HEADSET_ID);
-
-        final AudioDeviceInfo info2 = mock(AudioDeviceInfo.class);
-        when(info2.getType()).thenReturn(AudioDeviceInfo.TYPE_BUILTIN_MIC);
-        when(info2.getId()).thenReturn(BUILTIN_MIC_ID);
-
         final AudioManager audioManager = mock(AudioManager.class);
-        AudioDeviceInfo[] devices = {info1, info2};
+        AudioDeviceInfo[] devices = {mockWiredHeadsetInfo(), mockBuiltinMicInfo()};
         when(audioManager.getDevices(AudioManager.GET_DEVICES_INPUTS)).thenReturn(devices);
 
         // Mock audioManager.getDevicesForAttributes returns exactly one audioDeviceAttributes.
-        AudioDeviceAttributes audioDeviceAttributes = new AudioDeviceAttributes(info1);
         when(audioManager.getDevicesForAttributes(INPUT_ATTRIBUTES))
-                .thenReturn(Collections.singletonList(audioDeviceAttributes));
+                .thenReturn(Collections.singletonList(getWiredHeadsetDeviceAttributes()));
 
         InputRouteManager inputRouteManager = new InputRouteManager(mContext, audioManager);
-        inputRouteManager.mAudioDeviceCallback.onAudioDevicesAdded(devices);
+        onPreferredDevicesForCapturePresetChanged(inputRouteManager);
 
         // The selected input device has the same type as the one returned from AudioManager.
         InputMediaDevice selectedInputDevice =
@@ -168,29 +227,19 @@
 
     @Test
     public void getSelectedInputDevice_returnMoreThanOneFromAudioManager() {
-        final AudioDeviceInfo info1 = mock(AudioDeviceInfo.class);
-        when(info1.getType()).thenReturn(AudioDeviceInfo.TYPE_WIRED_HEADSET);
-        when(info1.getId()).thenReturn(INPUT_WIRED_HEADSET_ID);
-
-        final AudioDeviceInfo info2 = mock(AudioDeviceInfo.class);
-        when(info2.getType()).thenReturn(AudioDeviceInfo.TYPE_BUILTIN_MIC);
-        when(info2.getId()).thenReturn(BUILTIN_MIC_ID);
-
         final AudioManager audioManager = mock(AudioManager.class);
-        AudioDeviceInfo[] devices = {info1, info2};
+        AudioDeviceInfo[] devices = {mockWiredHeadsetInfo(), mockBuiltinMicInfo()};
         when(audioManager.getDevices(AudioManager.GET_DEVICES_INPUTS)).thenReturn(devices);
 
         // Mock audioManager.getDevicesForAttributes returns more than one audioDeviceAttributes.
-        AudioDeviceAttributes audioDeviceAttributes1 = new AudioDeviceAttributes(info1);
-        AudioDeviceAttributes audioDeviceAttributes2 = new AudioDeviceAttributes(info2);
         List<AudioDeviceAttributes> attributesOfSelectedInputDevices = new ArrayList<>();
-        attributesOfSelectedInputDevices.add(audioDeviceAttributes1);
-        attributesOfSelectedInputDevices.add(audioDeviceAttributes2);
+        attributesOfSelectedInputDevices.add(getWiredHeadsetDeviceAttributes());
+        attributesOfSelectedInputDevices.add(getBuiltinMicDeviceAttributes());
         when(audioManager.getDevicesForAttributes(INPUT_ATTRIBUTES))
                 .thenReturn(attributesOfSelectedInputDevices);
 
         InputRouteManager inputRouteManager = new InputRouteManager(mContext, audioManager);
-        inputRouteManager.mAudioDeviceCallback.onAudioDevicesAdded(devices);
+        onPreferredDevicesForCapturePresetChanged(inputRouteManager);
 
         // The selected input device has the same type as the first one returned from AudioManager.
         InputMediaDevice selectedInputDevice =
@@ -201,25 +250,17 @@
 
     @Test
     public void getSelectedInputDevice_returnEmptyFromAudioManager() {
-        final AudioDeviceInfo info1 = mock(AudioDeviceInfo.class);
-        when(info1.getType()).thenReturn(AudioDeviceInfo.TYPE_WIRED_HEADSET);
-        when(info1.getId()).thenReturn(INPUT_WIRED_HEADSET_ID);
-
-        final AudioDeviceInfo info2 = mock(AudioDeviceInfo.class);
-        when(info2.getType()).thenReturn(AudioDeviceInfo.TYPE_BUILTIN_MIC);
-        when(info2.getId()).thenReturn(BUILTIN_MIC_ID);
-
         final AudioManager audioManager = mock(AudioManager.class);
-        AudioDeviceInfo[] devices = {info1, info2};
+        AudioDeviceInfo[] devices = {mockWiredHeadsetInfo(), mockBuiltinMicInfo()};
         when(audioManager.getDevices(AudioManager.GET_DEVICES_INPUTS)).thenReturn(devices);
 
         // Mock audioManager.getDevicesForAttributes returns empty list of audioDeviceAttributes.
-        List<AudioDeviceAttributes> attributesOfSelectedInputDevices = new ArrayList<>();
+        List<AudioDeviceAttributes> emptyAttributesOfSelectedInputDevices = new ArrayList<>();
         when(audioManager.getDevicesForAttributes(INPUT_ATTRIBUTES))
-                .thenReturn(attributesOfSelectedInputDevices);
+                .thenReturn(emptyAttributesOfSelectedInputDevices);
 
         InputRouteManager inputRouteManager = new InputRouteManager(mContext, audioManager);
-        inputRouteManager.mAudioDeviceCallback.onAudioDevicesAdded(devices);
+        onPreferredDevicesForCapturePresetChanged(inputRouteManager);
 
         // The selected input device has default type AudioDeviceInfo.TYPE_BUILTIN_MIC.
         InputMediaDevice selectedInputDevice =
@@ -232,39 +273,133 @@
     public void selectDevice() {
         final AudioManager audioManager = mock(AudioManager.class);
         InputRouteManager inputRouteManager = new InputRouteManager(mContext, audioManager);
-        final MediaDevice inputMediaDevice =
+        final MediaDevice builtinMicDevice =
                 InputMediaDevice.create(
                         mContext,
                         String.valueOf(BUILTIN_MIC_ID),
                         AudioDeviceInfo.TYPE_BUILTIN_MIC,
                         MAX_VOLUME,
                         CURRENT_VOLUME,
-                        VOLUME_FIXED_TRUE);
-        inputRouteManager.selectDevice(inputMediaDevice);
+                        VOLUME_FIXED_TRUE,
+                        PRODUCT_NAME_BUILTIN_MIC);
+        inputRouteManager.selectDevice(builtinMicDevice);
 
-        AudioDeviceAttributes deviceAttributes =
-                new AudioDeviceAttributes(
-                        AudioDeviceAttributes.ROLE_INPUT,
-                        AudioDeviceInfo.TYPE_BUILTIN_MIC,
-                        /* address= */ "");
         for (@MediaRecorder.Source int preset : PRESETS) {
             verify(audioManager, atLeastOnce())
-                    .setPreferredDeviceForCapturePreset(preset, deviceAttributes);
+                    .setPreferredDeviceForCapturePreset(preset, getBuiltinMicDeviceAttributes());
+        }
+    }
+
+    @Test
+    public void onInitiation_shouldApplyDefaultSelectedDeviceToAllPresets() {
+        final AudioManager audioManager = mock(AudioManager.class);
+        new InputRouteManager(mContext, audioManager);
+
+        verify(audioManager, atLeastOnce()).getDevicesForAttributes(INPUT_ATTRIBUTES);
+        for (@MediaRecorder.Source int preset : PRESETS) {
+            verify(audioManager, atLeastOnce())
+                    .setPreferredDeviceForCapturePreset(preset, getBuiltinMicDeviceAttributes());
+        }
+    }
+
+    @Test
+    public void onAudioDevicesAdded_shouldApplyDefaultSelectedDeviceToAllPresets() {
+        final AudioManager audioManager = mock(AudioManager.class);
+        AudioDeviceAttributes wiredHeadsetDeviceAttributes = getWiredHeadsetDeviceAttributes();
+        when(audioManager.getDevicesForAttributes(INPUT_ATTRIBUTES))
+                .thenReturn(Collections.singletonList(wiredHeadsetDeviceAttributes));
+
+        InputRouteManager inputRouteManager = new InputRouteManager(mContext, audioManager);
+        AudioDeviceInfo[] devices = {mockWiredHeadsetInfo()};
+        inputRouteManager.mAudioDeviceCallback.onAudioDevicesAdded(devices);
+
+        // Called twice, one after initiation, the other after onAudioDevicesAdded call.
+        verify(audioManager, atLeast(2)).getDevicesForAttributes(INPUT_ATTRIBUTES);
+        for (@MediaRecorder.Source int preset : PRESETS) {
+            verify(audioManager, atLeast(2))
+                    .setPreferredDeviceForCapturePreset(preset, wiredHeadsetDeviceAttributes);
+        }
+    }
+
+    @Test
+    public void onAudioDevicesRemoved_shouldApplyDefaultSelectedDeviceToAllPresets() {
+        final AudioManager audioManager = mock(AudioManager.class);
+        InputRouteManager inputRouteManager = new InputRouteManager(mContext, audioManager);
+        AudioDeviceInfo[] devices = {mockWiredHeadsetInfo()};
+        inputRouteManager.mAudioDeviceCallback.onAudioDevicesRemoved(devices);
+
+        // Called twice, one after initiation, the other after onAudioDevicesRemoved call.
+        verify(audioManager, atLeast(2)).getDevicesForAttributes(INPUT_ATTRIBUTES);
+        for (@MediaRecorder.Source int preset : PRESETS) {
+            verify(audioManager, atLeast(2))
+                    .setPreferredDeviceForCapturePreset(preset, getBuiltinMicDeviceAttributes());
         }
     }
 
     @Test
     public void getMaxInputGain_returnMaxInputGain() {
-        assertThat(mInputRouteManager.getMaxInputGain()).isEqualTo(15);
+        assertThat(mInputRouteManager.getMaxInputGain()).isEqualTo(100);
     }
 
     @Test
     public void getCurrentInputGain_returnCurrentInputGain() {
-        assertThat(mInputRouteManager.getCurrentInputGain()).isEqualTo(8);
+        assertThat(mInputRouteManager.getCurrentInputGain()).isEqualTo(100);
     }
 
     @Test
     public void isInputGainFixed() {
         assertThat(mInputRouteManager.isInputGainFixed()).isTrue();
     }
+
+    @Test
+    public void onAudioDevicesAdded_shouldSetProductNameCorrectly() {
+        final AudioDeviceInfo info1 = mockWiredHeadsetInfo();
+        String firstProductName = "My first headset";
+        when(info1.getProductName()).thenReturn(firstProductName);
+        InputMediaDevice inputMediaDevice1 = createInputMediaDeviceFromDeviceInfo(info1);
+
+        final AudioDeviceInfo info2 = mockWiredHeadsetInfo();
+        String secondProductName = "My second headset";
+        when(info2.getProductName()).thenReturn(secondProductName);
+        InputMediaDevice inputMediaDevice2 = createInputMediaDeviceFromDeviceInfo(info2);
+
+        final AudioDeviceInfo infoWithNullProductName = mockWiredHeadsetInfo();
+        when(infoWithNullProductName.getProductName()).thenReturn(null);
+        InputMediaDevice inputMediaDevice3 =
+                createInputMediaDeviceFromDeviceInfo(infoWithNullProductName);
+
+        final AudioDeviceInfo infoWithBlankProductName = mockWiredHeadsetInfo();
+        when(infoWithBlankProductName.getProductName()).thenReturn("");
+        InputMediaDevice inputMediaDevice4 =
+                createInputMediaDeviceFromDeviceInfo(infoWithBlankProductName);
+
+        final AudioManager audioManager = mock(AudioManager.class);
+        AudioDeviceInfo[] devices = {
+            info1, info2, infoWithNullProductName, infoWithBlankProductName
+        };
+        when(audioManager.getDevices(AudioManager.GET_DEVICES_INPUTS)).thenReturn(devices);
+
+        InputRouteManager inputRouteManager = new InputRouteManager(mContext, audioManager);
+
+        assertThat(inputRouteManager.mInputMediaDevices).isEmpty();
+
+        inputRouteManager.mAudioDeviceCallback.onAudioDevicesAdded(devices);
+        onPreferredDevicesForCapturePresetChanged(inputRouteManager);
+
+        assertThat(inputRouteManager.mInputMediaDevices)
+                .containsExactly(
+                        inputMediaDevice1, inputMediaDevice2, inputMediaDevice3, inputMediaDevice4)
+                .inOrder();
+    }
+
+    private InputMediaDevice createInputMediaDeviceFromDeviceInfo(AudioDeviceInfo info) {
+        return InputMediaDevice.create(
+                mContext,
+                String.valueOf(info.getId()),
+                info.getType(),
+                MAX_VOLUME,
+                CURRENT_VOLUME,
+                VOLUME_FIXED_TRUE,
+                info.getProductName() == null ? null : info.getProductName().toString());
+    }
 }
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/WifiUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/WifiUtilsTest.java
index 5293011..d8b6707 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/WifiUtilsTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/WifiUtilsTest.java
@@ -207,20 +207,6 @@
     }
 
     @Test
-    public void getHotspotIconResource_deviceTypeExists_shouldNotNull() {
-        assertThat(WifiUtils.getHotspotIconResource(NetworkProviderInfo.DEVICE_TYPE_PHONE))
-                .isNotNull();
-        assertThat(WifiUtils.getHotspotIconResource(NetworkProviderInfo.DEVICE_TYPE_TABLET))
-                .isNotNull();
-        assertThat(WifiUtils.getHotspotIconResource(NetworkProviderInfo.DEVICE_TYPE_LAPTOP))
-                .isNotNull();
-        assertThat(WifiUtils.getHotspotIconResource(NetworkProviderInfo.DEVICE_TYPE_WATCH))
-                .isNotNull();
-        assertThat(WifiUtils.getHotspotIconResource(NetworkProviderInfo.DEVICE_TYPE_AUTO))
-                .isNotNull();
-    }
-
-    @Test
     public void testInternetIconInjector_getIcon_returnsCorrectValues() {
         WifiUtils.InternetIconInjector iconInjector = new WifiUtils.InternetIconInjector(mContext);
 
diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/SystemSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/SystemSettings.java
index 2cdd0ae..3530e0f 100644
--- a/packages/SettingsProvider/src/android/provider/settings/backup/SystemSettings.java
+++ b/packages/SettingsProvider/src/android/provider/settings/backup/SystemSettings.java
@@ -106,6 +106,8 @@
                 Settings.System.UNREAD_NOTIFICATION_DOT_INDICATOR,
                 Settings.System.AUTO_LAUNCH_MEDIA_CONTROLS,
                 Settings.System.LOCALE_PREFERENCES,
+                Settings.System.MOUSE_REVERSE_VERTICAL_SCROLLING,
+                Settings.System.MOUSE_SWAP_PRIMARY_BUTTON,
                 Settings.System.TOUCHPAD_POINTER_SPEED,
                 Settings.System.TOUCHPAD_NATURAL_SCROLLING,
                 Settings.System.TOUCHPAD_TAP_TO_CLICK,
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java
index 2823277..509b88b 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java
@@ -221,6 +221,8 @@
                         POINTER_ICON_VECTOR_STYLE_STROKE_END));
         VALIDATORS.put(System.POINTER_SCALE,
                 new InclusiveFloatRangeValidator(DEFAULT_POINTER_SCALE, LARGE_POINTER_SCALE));
+        VALIDATORS.put(System.MOUSE_REVERSE_VERTICAL_SCROLLING, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(System.MOUSE_SWAP_PRIMARY_BUTTON, BOOLEAN_VALIDATOR);
         VALIDATORS.put(System.TOUCHPAD_POINTER_SPEED, new InclusiveIntegerRangeValidator(-7, 7));
         VALIDATORS.put(System.TOUCHPAD_NATURAL_SCROLLING, BOOLEAN_VALIDATOR);
         VALIDATORS.put(System.TOUCHPAD_TAP_TO_CLICK, BOOLEAN_VALIDATOR);
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 456fedf..408ed1e 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -743,12 +743,6 @@
     <uses-permission android:name="android.permission.READ_SAFETY_CENTER_STATUS" />
     <uses-permission android:name="android.permission.MANAGE_SAFETY_CENTER" />
 
-    <!-- Permissions required for CTS test - CtsVirtualDevicesTestCases -->
-    <uses-permission android:name="android.permission.CREATE_VIRTUAL_DEVICE" />
-    <uses-permission android:name="android.permission.ADD_TRUSTED_DISPLAY" />
-    <uses-permission android:name="android.permission.ADD_ALWAYS_UNLOCKED_DISPLAY" />
-
-
     <!-- Permission required for CTS test - Notification test suite -->
     <uses-permission android:name="android.permission.REVOKE_POST_NOTIFICATIONS_WITHOUT_KILL" />
 
diff --git a/packages/Shell/res/values-kn/strings.xml b/packages/Shell/res/values-kn/strings.xml
index 56448f7..18d0f34 100644
--- a/packages/Shell/res/values-kn/strings.xml
+++ b/packages/Shell/res/values-kn/strings.xml
@@ -28,7 +28,7 @@
     <string name="bugreport_finished_pending_screenshot_text" product="tv" msgid="2343263822812016950">"ಸ್ಕ್ರೀನ್‌ಶಾಟ್‌ ಇಲ್ಲದೇ ಬಗ್ ವರದಿ ಹಂಚಿಕೊಳ್ಳಲು ಆಯ್ಕೆಮಾಡಿ, ಅಥವಾ ಸ್ಕ್ರೀನ್‌ಶಾಟ್‌ ಪೂರ್ತಿಯಾಗುವ ತನಕ ಕಾಯಿರಿ"</string>
     <string name="bugreport_finished_pending_screenshot_text" product="watch" msgid="1474435374470177193">"ಸ್ಕ್ರೀನ್‌ಶಾಟ್‌ ಇಲ್ಲದೇ ನಿಮ್ಮ ಬಗ್ ವರದಿಯನ್ನು ಹಂಚಿಕೊಳ್ಳಲು ಟ್ಯಾಪ್ ಮಾಡಿ ಅಥವಾ ಸ್ಕ್ರೀನ್‌ಶಾಟ್‌ ಪೂರ್ತಿಯಾಗುವವರೆಗೂ ನಿರೀಕ್ಷಿಸಿ"</string>
     <string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"ಸ್ಕ್ರೀನ್‌ಶಾಟ್‌ ಇಲ್ಲದೇ ನಿಮ್ಮ ಬಗ್ ವರದಿಯನ್ನು ಹಂಚಿಕೊಳ್ಳಲು ಟ್ಯಾಪ್ ಮಾಡಿ ಅಥವಾ ಸ್ಕ್ರೀನ್‌ಶಾಟ್‌ ಪೂರ್ತಿಯಾಗುವವರೆಗೂ ನಿರೀಕ್ಷಿಸಿ"</string>
-    <string name="bugreport_confirm" msgid="5917407234515812495">"ನೀವು ಸೂಕ್ಷ್ಮ ಎಂದು ಪರಿಗಣಿಸಿರುವ ಯಾವುದೇ ಡೇಟಾ ಒಳಗೊಂಡಿರುವ ಸಿಸ್ಟಂನ ಹಲವಾರು ಲಾಗ್ ಫೈಲ್‌ಗಳಿಂದ ಡೇಟಾವನ್ನು ದೋಷದ ವರದಿಗಳು ಒಳಗೊಂಡಿವೆ (ಉದಾಹರಣೆಗೆ ಅಪ್ಲಿಕೇಶನ್-ಬಳಕೆ ಮತ್ತು ಸ್ಥಳ ಮಾಹಿತಿ). ನೀವು ನಂಬಿಕೆ ಇರಿಸಿರುವ ಜನರು ಮತ್ತು ಅಪ್ಲಿಕೇಶನ್‌ಗಳೊಂದಿಗೆ ಮಾತ್ರ ದೋಷದ ವರದಿಗಳನ್ನು ಹಂಚಿಕೊಳ್ಳಿ."</string>
+    <string name="bugreport_confirm" msgid="5917407234515812495">"ನೀವು ಸೂಕ್ಷ್ಮ ಎಂದು ಪರಿಗಣಿಸಿರುವ ಯಾವುದೇ ಡೇಟಾ ಒಳಗೊಂಡಿರುವ ಸಿಸ್ಟಂನ ಹಲವಾರು ಲಾಗ್ ಫೈಲ್‌ಗಳಿಂದ ಡೇಟಾವನ್ನು ದೋಷದ ವರದಿಗಳು ಒಳಗೊಂಡಿವೆ (ಉದಾಹರಣೆಗೆ ಆ್ಯಪ್-ಬಳಕೆ ಮತ್ತು ಸ್ಥಳ ಮಾಹಿತಿ). ನೀವು ನಂಬಿಕೆ ಇರಿಸಿರುವ ಜನರು ಮತ್ತು ಆ್ಯಪ್‌ಗಳೊಂದಿಗೆ ಮಾತ್ರ ದೋಷದ ವರದಿಗಳನ್ನು ಹಂಚಿಕೊಳ್ಳಿ."</string>
     <string name="bugreport_confirm_dont_repeat" msgid="6179945398364357318">"ಮತ್ತೊಮ್ಮೆ ತೋರಿಸಬೇಡ"</string>
     <string name="bugreport_storage_title" msgid="5332488144740527109">"ದೋಷ ವರದಿಗಳು"</string>
     <string name="bugreport_unreadable_text" msgid="586517851044535486">"ಬಗ್‌ ವರದಿ ಫೈಲ್‌‌ ಅನ್ನು ಓದಲು ಸಾಧ್ಯವಾಗುತ್ತಿಲ್ಲ"</string>
diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp
index bd7067b..2863531 100644
--- a/packages/SystemUI/Android.bp
+++ b/packages/SystemUI/Android.bp
@@ -425,8 +425,8 @@
         "tests/src/**/systemui/media/controls/domain/pipeline/LegacyMediaDataManagerImplTest.kt",
         "tests/src/**/systemui/shared/system/RemoteTransitionTest.java",
         "tests/src/**/systemui/navigationbar/NavigationBarControllerImplTest.java",
-        "tests/src/**/systemui/bluetooth/qsdialog/AudioSharingInteractorTest.kt",
-        "tests/src/**/systemui/bluetooth/qsdialog/DeviceItemActionInteractorTest.kt",
+        "tests/src/**/systemui/bluetooth/qsdialog/AudioSharingButtonViewModelTest.kt",
+        "tests/src/**/systemui/bluetooth/qsdialog/AudioSharingDeviceItemActionInteractorTest.kt",
         "tests/src/**/systemui/notetask/quickaffordance/NoteTaskQuickAffordanceConfigTest.kt",
         "tests/src/**/systemui/notetask/LaunchNotesRoleSettingsTrampolineActivityTest.kt",
         "tests/src/**/systemui/notetask/shortcut/LaunchNoteTaskActivityTest.kt",
@@ -802,6 +802,7 @@
         "SystemUICustomizationTestUtils",
         "androidx.compose.runtime_runtime",
         "kosmos",
+        "testables",
         "androidx.test.rules",
     ],
     libs: [
@@ -1022,6 +1023,7 @@
     defaults: [
         "platform_app_defaults",
         "SystemUI_optimized_defaults",
+        "wmshell_defaults",
     ],
     static_libs: [
         "SystemUI-core",
diff --git a/packages/SystemUI/TEST_MAPPING b/packages/SystemUI/TEST_MAPPING
index 07a1e63..380344a 100644
--- a/packages/SystemUI/TEST_MAPPING
+++ b/packages/SystemUI/TEST_MAPPING
@@ -148,5 +148,10 @@
     {
       "name": "SystemUIGoogleRobo2RNGTests"
     }
+  ],
+  "imports": [
+    {
+      "path": "cts/tests/tests/multiuser"
+    }
   ]
 }
diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values-fa/strings.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values-fa/strings.xml
index 49d8f69..cf6f012 100644
--- a/packages/SystemUI/accessibility/accessibilitymenu/res/values-fa/strings.xml
+++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values-fa/strings.xml
@@ -26,6 +26,6 @@
     <string name="accessibility_menu_large_buttons_title" msgid="8978499601044961736">"دکمه‌های بزرگ"</string>
     <string name="accessibility_menu_large_buttons_summary" msgid="236873938502785311">"افزایش اندازه «دکمه‌های منوی دسترس‌پذیری»"</string>
     <string name="pref_help_title" msgid="6871558837025010641">"راهنما"</string>
-    <string name="brightness_percentage_label" msgid="7391554573977867369">"روشنایی <xliff:g id="PERCENTAGE">%1$s</xliff:g> %%"</string>
-    <string name="music_volume_percentage_label" msgid="398635599662604706">"بلندی صدای موسیقی <xliff:g id="PERCENTAGE">%1$s</xliff:g> %%"</string>
+    <string name="brightness_percentage_label" msgid="7391554573977867369">"‏روشنایی ‎%%<xliff:g id="PERCENTAGE">%1$s</xliff:g>"</string>
+    <string name="music_volume_percentage_label" msgid="398635599662604706">"‏بلندی صدای موسیقی ‎%%<xliff:g id="PERCENTAGE">%1$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/aconfig/systemui.aconfig b/packages/SystemUI/aconfig/systemui.aconfig
index c6238e8..a21a805 100644
--- a/packages/SystemUI/aconfig/systemui.aconfig
+++ b/packages/SystemUI/aconfig/systemui.aconfig
@@ -813,16 +813,6 @@
 }
 
 flag {
-    name: "register_zen_mode_content_observer_background"
-    namespace: "systemui"
-    description: "Decide whether to register zen mode content observers in the background thread."
-    bug: "324515627"
-    metadata {
-        purpose: PURPOSE_BUGFIX
-    }
-}
-
-flag {
     name: "clipboard_noninteractive_on_lockscreen"
     namespace: "systemui"
     description: "Prevents the interactive clipboard UI from appearing when device is locked"
@@ -1483,3 +1473,11 @@
        purpose: PURPOSE_BUGFIX
    }
 }
+
+flag {
+   name: "magic_portrait_wallpapers"
+   namespace: "systemui"
+   description: "Magic Portrait related changes in systemui"
+   bug: "370863642"
+}
+
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityTransitionAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityTransitionAnimator.kt
index d025275..93a99bd 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityTransitionAnimator.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityTransitionAnimator.kt
@@ -136,6 +136,23 @@
             )
 
         /**
+         * The timings when animating a View into an app using a spring animator.
+         *
+         * Important: since springs don't have fixed durations, these timings represent fractions of
+         * the progress between the spring's initial value and its final value.
+         *
+         * TODO(b/372858592): make this a separate class explicitly using percentages.
+         */
+        val SPRING_TIMINGS =
+            TransitionAnimator.Timings(
+                totalDuration = 1000L,
+                contentBeforeFadeOutDelay = 0L,
+                contentBeforeFadeOutDuration = 800L,
+                contentAfterFadeInDelay = 850L,
+                contentAfterFadeInDuration = 135L,
+            )
+
+        /**
          * The timings when animating a Dialog into an app. We need to wait at least 200ms before
          * showing the app (which is under the dialog window) so that the dialog window dim is fully
          * faded out, to avoid flicker.
@@ -152,6 +169,13 @@
                 contentAfterFadeInInterpolator = PathInterpolator(0f, 0f, 0.6f, 1f),
             )
 
+        /** The interpolators when animating a View into an app using a spring animator. */
+        val SPRING_INTERPOLATORS =
+            INTERPOLATORS.copy(
+                contentBeforeFadeOutInterpolator = Interpolators.DECELERATE_1_5,
+                contentAfterFadeInInterpolator = Interpolators.SLOW_OUT_LINEAR_IN,
+            )
+
         // TODO(b/288507023): Remove this flag.
         @JvmField val DEBUG_TRANSITION_ANIMATION = Build.IS_DEBUGGABLE
 
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/TransitionAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/TransitionAnimator.kt
index fc4cf1d..1d8ff77 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/TransitionAnimator.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/TransitionAnimator.kt
@@ -23,16 +23,24 @@
 import android.graphics.PorterDuff
 import android.graphics.PorterDuffXfermode
 import android.graphics.drawable.GradientDrawable
+import android.util.FloatProperty
 import android.util.Log
 import android.util.MathUtils
 import android.view.View
 import android.view.ViewGroup
+import android.view.ViewGroupOverlay
+import android.view.ViewOverlay
 import android.view.animation.Interpolator
 import android.window.WindowAnimationState
-import androidx.annotation.VisibleForTesting
 import com.android.app.animation.Interpolators.LINEAR
+import com.android.app.animation.MathUtils.max
+import com.android.internal.annotations.VisibleForTesting
+import com.android.internal.dynamicanimation.animation.SpringAnimation
+import com.android.internal.dynamicanimation.animation.SpringForce
 import com.android.systemui.shared.Flags.returnAnimationFrameworkLibrary
 import java.util.concurrent.Executor
+import kotlin.math.abs
+import kotlin.math.min
 import kotlin.math.roundToInt
 
 private const val TAG = "TransitionAnimator"
@@ -42,11 +50,27 @@
     private val mainExecutor: Executor,
     private val timings: Timings,
     private val interpolators: Interpolators,
+
+    /** [springTimings] and [springInterpolators] must either both be null or both not null. */
+    private val springTimings: Timings? = null,
+    private val springInterpolators: Interpolators? = null,
+    private val springParams: SpringParams = DEFAULT_SPRING_PARAMS,
 ) {
     companion object {
         internal const val DEBUG = false
         private val SRC_MODE = PorterDuffXfermode(PorterDuff.Mode.SRC)
 
+        /** Default parameters for the multi-spring animator. */
+        private val DEFAULT_SPRING_PARAMS =
+            SpringParams(
+                centerXStiffness = 450f,
+                centerXDampingRatio = 0.965f,
+                centerYStiffness = 400f,
+                centerYDampingRatio = 0.95f,
+                scaleStiffness = 500f,
+                scaleDampingRatio = 0.99f,
+            )
+
         /**
          * Given the [linearProgress] of a transition animation, return the linear progress of the
          * sub-animation starting [delay] ms after the transition animation and that lasts
@@ -84,11 +108,32 @@
                 it.bottomCornerRadius = (bottomLeftRadius + bottomRightRadius) / 2
                 it.topCornerRadius = (topLeftRadius + topRightRadius) / 2
             }
+
+        /** Builds a [FloatProperty] for updating the defined [property] using a spring. */
+        private fun buildProperty(
+            property: SpringProperty,
+            updateProgress: (SpringState) -> Unit,
+        ): FloatProperty<SpringState> {
+            return object : FloatProperty<SpringState>(property.name) {
+                override fun get(state: SpringState): Float {
+                    return property.get(state)
+                }
+
+                override fun setValue(state: SpringState, value: Float) {
+                    property.setValue(state, value)
+                    updateProgress(state)
+                }
+            }
+        }
     }
 
     private val transitionContainerLocation = IntArray(2)
     private val cornerRadii = FloatArray(8)
 
+    init {
+        check((springTimings == null) == (springInterpolators == null))
+    }
+
     /**
      * A controller that takes care of applying the animation to an expanding view.
      *
@@ -196,11 +241,111 @@
         var visible: Boolean = true
     }
 
+    /** Encapsulated the state of a multi-spring animation. */
+    internal class SpringState(
+        // Animated values.
+        var centerX: Float,
+        var centerY: Float,
+        var scale: Float = 0f,
+
+        // Cached values.
+        var previousCenterX: Float = -1f,
+        var previousCenterY: Float = -1f,
+        var previousScale: Float = -1f,
+
+        // Completion flags.
+        var isCenterXDone: Boolean = false,
+        var isCenterYDone: Boolean = false,
+        var isScaleDone: Boolean = false,
+    ) {
+        /** Whether all springs composing the animation have settled in the final position. */
+        val isDone
+            get() = isCenterXDone && isCenterYDone && isScaleDone
+    }
+
+    /** Supported [SpringState] properties with getters and setters to update them. */
+    private enum class SpringProperty {
+        CENTER_X {
+            override fun get(state: SpringState): Float {
+                return state.centerX
+            }
+
+            override fun setValue(state: SpringState, value: Float) {
+                state.centerX = value
+            }
+        },
+        CENTER_Y {
+            override fun get(state: SpringState): Float {
+                return state.centerY
+            }
+
+            override fun setValue(state: SpringState, value: Float) {
+                state.centerY = value
+            }
+        },
+        SCALE {
+            override fun get(state: SpringState): Float {
+                return state.scale
+            }
+
+            override fun setValue(state: SpringState, value: Float) {
+                state.scale = value
+            }
+        };
+
+        /** Extracts the current value of the underlying property from [state]. */
+        abstract fun get(state: SpringState): Float
+
+        /** Update's the [value] of the underlying property inside [state]. */
+        abstract fun setValue(state: SpringState, value: Float)
+    }
+
     interface Animation {
+        /** Start the animation. */
+        fun start()
+
         /** Cancel the animation. */
         fun cancel()
     }
 
+    @VisibleForTesting
+    class InterpolatedAnimation(@get:VisibleForTesting val animator: Animator) : Animation {
+        override fun start() {
+            animator.start()
+        }
+
+        override fun cancel() {
+            animator.cancel()
+        }
+    }
+
+    @VisibleForTesting
+    class MultiSpringAnimation
+    internal constructor(
+        @get:VisibleForTesting val springX: SpringAnimation,
+        @get:VisibleForTesting val springY: SpringAnimation,
+        @get:VisibleForTesting val springScale: SpringAnimation,
+        private val springState: SpringState,
+        private val onAnimationStart: Runnable,
+    ) : Animation {
+        @get:VisibleForTesting
+        val isDone
+            get() = springState.isDone
+
+        override fun start() {
+            onAnimationStart.run()
+            springX.start()
+            springY.start()
+            springScale.start()
+        }
+
+        override fun cancel() {
+            springX.cancel()
+            springY.cancel()
+            springScale.cancel()
+        }
+    }
+
     /** The timings (durations and delays) used by this animator. */
     data class Timings(
         /** The total duration of the animation. */
@@ -240,6 +385,21 @@
         val contentAfterFadeInInterpolator: Interpolator,
     )
 
+    /** The parameters (stiffnesses and damping ratios) used by the multi-spring animator. */
+    data class SpringParams(
+        // Parameters for the X position spring.
+        val centerXStiffness: Float,
+        val centerXDampingRatio: Float,
+
+        // Parameters for the Y position spring.
+        val centerYStiffness: Float,
+        val centerYDampingRatio: Float,
+
+        // Parameters for the scale spring.
+        val scaleStiffness: Float,
+        val scaleDampingRatio: Float,
+    )
+
     /**
      * Start a transition animation controlled by [controller] towards [endState]. An intermediary
      * layer with [windowBackgroundColor] will fade in then (optionally) fade out above the
@@ -250,6 +410,9 @@
      * the animation (if ![Controller.isLaunching]), and will have SRC blending mode (ultimately
      * punching a hole in the [transition container][Controller.transitionContainer]) iff [drawHole]
      * is true.
+     *
+     * If [useSpring] is true, a multi-spring animation will be used instead of the default
+     * interpolators.
      */
     fun startAnimation(
         controller: Controller,
@@ -257,8 +420,9 @@
         windowBackgroundColor: Int,
         fadeWindowBackgroundLayer: Boolean = true,
         drawHole: Boolean = false,
+        useSpring: Boolean = false,
     ): Animation {
-        if (!controller.isLaunching) checkReturnAnimationFrameworkFlag()
+        if (!controller.isLaunching || useSpring) checkReturnAnimationFrameworkFlag()
 
         // We add an extra layer with the same color as the dialog/app splash screen background
         // color, which is usually the same color of the app background. We first fade in this layer
@@ -270,33 +434,91 @@
                 alpha = 0
             }
 
-        val animator =
-            createAnimator(
+        return createAnimation(
                 controller,
+                controller.createAnimatorState(),
                 endState,
                 windowBackgroundLayer,
                 fadeWindowBackgroundLayer,
                 drawHole,
+                useSpring,
             )
-        animator.start()
-
-        return object : Animation {
-            override fun cancel() {
-                animator.cancel()
-            }
-        }
+            .apply { start() }
     }
 
     @VisibleForTesting
-    fun createAnimator(
+    fun createAnimation(
         controller: Controller,
+        startState: State,
         endState: State,
         windowBackgroundLayer: GradientDrawable,
         fadeWindowBackgroundLayer: Boolean = true,
+        useSpring: Boolean = false,
         drawHole: Boolean = false,
-    ): ValueAnimator {
-        val state = controller.createAnimatorState()
+    ): Animation {
+        val transitionContainer = controller.transitionContainer
+        val transitionContainerOverlay = transitionContainer.overlay
+        val openingWindowSyncView = controller.openingWindowSyncView
+        val openingWindowSyncViewOverlay = openingWindowSyncView?.overlay
 
+        // Whether we should move the [windowBackgroundLayer] into the overlay of
+        // [Controller.openingWindowSyncView] once the opening app window starts to be visible, or
+        // from it once the closing app window stops being visible.
+        // This is necessary as a one-off sync so we can avoid syncing at every frame, especially
+        // in complex interactions like launching an activity from a dialog. See
+        // b/214961273#comment2 for more details.
+        val moveBackgroundLayerWhenAppVisibilityChanges =
+            openingWindowSyncView != null &&
+                openingWindowSyncView.viewRootImpl != controller.transitionContainer.viewRootImpl
+
+        return if (useSpring && springTimings != null && springInterpolators != null) {
+            createSpringAnimation(
+                controller,
+                startState,
+                endState,
+                windowBackgroundLayer,
+                transitionContainer,
+                transitionContainerOverlay,
+                openingWindowSyncView,
+                openingWindowSyncViewOverlay,
+                fadeWindowBackgroundLayer,
+                drawHole,
+                moveBackgroundLayerWhenAppVisibilityChanges,
+            )
+        } else {
+            createInterpolatedAnimation(
+                controller,
+                startState,
+                endState,
+                windowBackgroundLayer,
+                transitionContainer,
+                transitionContainerOverlay,
+                openingWindowSyncView,
+                openingWindowSyncViewOverlay,
+                fadeWindowBackgroundLayer,
+                drawHole,
+                moveBackgroundLayerWhenAppVisibilityChanges,
+            )
+        }
+    }
+
+    /**
+     * Creates an interpolator-based animator that uses [timings] and [interpolators] to calculate
+     * the new bounds and corner radiuses at each frame.
+     */
+    private fun createInterpolatedAnimation(
+        controller: Controller,
+        state: State,
+        endState: State,
+        windowBackgroundLayer: GradientDrawable,
+        transitionContainer: View,
+        transitionContainerOverlay: ViewGroupOverlay,
+        openingWindowSyncView: View? = null,
+        openingWindowSyncViewOverlay: ViewOverlay? = null,
+        fadeWindowBackgroundLayer: Boolean = true,
+        drawHole: Boolean = false,
+        moveBackgroundLayerWhenAppVisibilityChanges: Boolean = false,
+    ): Animation {
         // Start state.
         val startTop = state.top
         val startBottom = state.bottom
@@ -333,45 +555,24 @@
             }
         }
 
-        val transitionContainer = controller.transitionContainer
         val isExpandingFullyAbove = isExpandingFullyAbove(transitionContainer, endState)
+        var movedBackgroundLayer = false
 
         // Update state.
         val animator = ValueAnimator.ofFloat(0f, 1f)
         animator.duration = timings.totalDuration
         animator.interpolator = LINEAR
 
-        // Whether we should move the [windowBackgroundLayer] into the overlay of
-        // [Controller.openingWindowSyncView] once the opening app window starts to be visible, or
-        // from it once the closing app window stops being visible.
-        // This is necessary as a one-off sync so we can avoid syncing at every frame, especially
-        // in complex interactions like launching an activity from a dialog. See
-        // b/214961273#comment2 for more details.
-        val openingWindowSyncView = controller.openingWindowSyncView
-        val openingWindowSyncViewOverlay = openingWindowSyncView?.overlay
-        val moveBackgroundLayerWhenAppVisibilityChanges =
-            openingWindowSyncView != null &&
-                openingWindowSyncView.viewRootImpl != controller.transitionContainer.viewRootImpl
-
-        val transitionContainerOverlay = transitionContainer.overlay
-        var movedBackgroundLayer = false
-
         animator.addListener(
             object : AnimatorListenerAdapter() {
                 override fun onAnimationStart(animation: Animator, isReverse: Boolean) {
-                    if (DEBUG) {
-                        Log.d(TAG, "Animation started")
-                    }
-                    controller.onTransitionAnimationStart(isExpandingFullyAbove)
-
-                    // Add the drawable to the transition container overlay. Overlays always draw
-                    // drawables after views, so we know that it will be drawn above any view added
-                    // by the controller.
-                    if (controller.isLaunching || openingWindowSyncViewOverlay == null) {
-                        transitionContainerOverlay.add(windowBackgroundLayer)
-                    } else {
-                        openingWindowSyncViewOverlay.add(windowBackgroundLayer)
-                    }
+                    onAnimationStart(
+                        controller,
+                        isExpandingFullyAbove,
+                        windowBackgroundLayer,
+                        transitionContainerOverlay,
+                        openingWindowSyncViewOverlay,
+                    )
                 }
 
                 override fun onAnimationEnd(animation: Animator) {
@@ -413,63 +614,20 @@
             state.bottomCornerRadius =
                 MathUtils.lerp(startBottomCornerRadius, endBottomCornerRadius, progress)
 
-            state.visible =
-                if (controller.isLaunching) {
-                    // The expanding view can/should be hidden once it is completely covered by the
-                    // opening window.
-                    getProgress(
-                        timings,
-                        linearProgress,
-                        timings.contentBeforeFadeOutDelay,
-                        timings.contentBeforeFadeOutDuration,
-                    ) < 1
-                } else {
-                    getProgress(
-                        timings,
-                        linearProgress,
-                        timings.contentAfterFadeInDelay,
-                        timings.contentAfterFadeInDuration,
-                    ) > 0
-                }
+            state.visible = checkVisibility(timings, linearProgress, controller.isLaunching)
 
-            if (
-                controller.isLaunching &&
-                    moveBackgroundLayerWhenAppVisibilityChanges &&
-                    !state.visible &&
-                    !movedBackgroundLayer
-            ) {
-                // The expanding view is not visible, so the opening app is visible. If this is
-                // the first frame when it happens, trigger a one-off sync and move the
-                // background layer in its new container.
-                movedBackgroundLayer = true
-
-                transitionContainerOverlay.remove(windowBackgroundLayer)
-                openingWindowSyncViewOverlay!!.add(windowBackgroundLayer)
-
-                ViewRootSync.synchronizeNextDraw(
-                    transitionContainer,
-                    openingWindowSyncView,
-                    then = {},
-                )
-            } else if (
-                !controller.isLaunching &&
-                    moveBackgroundLayerWhenAppVisibilityChanges &&
-                    state.visible &&
-                    !movedBackgroundLayer
-            ) {
-                // The contracting view is now visible, so the closing app is not. If this is
-                // the first frame when it happens, trigger a one-off sync and move the
-                // background layer in its new container.
-                movedBackgroundLayer = true
-
-                openingWindowSyncViewOverlay!!.remove(windowBackgroundLayer)
-                transitionContainerOverlay.add(windowBackgroundLayer)
-
-                ViewRootSync.synchronizeNextDraw(
-                    openingWindowSyncView,
-                    transitionContainer,
-                    then = {},
-                )
+            if (!movedBackgroundLayer) {
+                movedBackgroundLayer =
+                    maybeMoveBackgroundLayer(
+                        controller,
+                        state,
+                        windowBackgroundLayer,
+                        transitionContainer,
+                        transitionContainerOverlay,
+                        openingWindowSyncView,
+                        openingWindowSyncViewOverlay,
+                        moveBackgroundLayerWhenAppVisibilityChanges,
+                    )
             }
 
             val container =
@@ -478,7 +636,6 @@
                 } else {
                     controller.transitionContainer
                 }
-
             applyStateToWindowBackgroundLayer(
                 windowBackgroundLayer,
                 state,
@@ -487,11 +644,342 @@
                 fadeWindowBackgroundLayer,
                 drawHole,
                 controller.isLaunching,
+                useSpring = false,
             )
+
             controller.onTransitionAnimationProgress(state, progress, linearProgress)
         }
 
-        return animator
+        return InterpolatedAnimation(animator)
+    }
+
+    /**
+     * Creates a compound animator made up of three springs: one for the center x position, one for
+     * the center-y position, and one for the overall scale.
+     *
+     * This animator uses [springTimings] and [springInterpolators] for opacity, based on the scale
+     * progress.
+     */
+    private fun createSpringAnimation(
+        controller: Controller,
+        startState: State,
+        endState: State,
+        windowBackgroundLayer: GradientDrawable,
+        transitionContainer: View,
+        transitionContainerOverlay: ViewGroupOverlay,
+        openingWindowSyncView: View?,
+        openingWindowSyncViewOverlay: ViewOverlay?,
+        fadeWindowBackgroundLayer: Boolean = true,
+        drawHole: Boolean = false,
+        moveBackgroundLayerWhenAppVisibilityChanges: Boolean = false,
+    ): Animation {
+        var springX: SpringAnimation? = null
+        var springY: SpringAnimation? = null
+        var targetX = endState.centerX
+        var targetY = endState.centerY
+
+        var movedBackgroundLayer = false
+
+        fun maybeUpdateEndState() {
+            if (endState.centerX != targetX && endState.centerY != targetY) {
+                targetX = endState.centerX
+                targetY = endState.centerY
+
+                springX?.animateToFinalPosition(targetX)
+                springY?.animateToFinalPosition(targetY)
+            }
+        }
+
+        fun updateProgress(state: SpringState) {
+            if (
+                (!state.isCenterXDone && state.centerX == state.previousCenterX) ||
+                    (!state.isCenterYDone && state.centerY == state.previousCenterY) ||
+                    (!state.isScaleDone && state.scale == state.previousScale)
+            ) {
+                // Because all three springs use the same update method, we only actually update
+                // when all values have changed, avoiding two redundant calls per frame.
+                return
+            }
+
+            // Update the latest values for the check above.
+            state.previousCenterX = state.centerX
+            state.previousCenterY = state.centerY
+            state.previousScale = state.scale
+
+            // Current scale-based values, that will be used to find the new animation bounds.
+            val width =
+                MathUtils.lerp(startState.width.toFloat(), endState.width.toFloat(), state.scale)
+            val height =
+                MathUtils.lerp(startState.height.toFloat(), endState.height.toFloat(), state.scale)
+
+            val newState =
+                State(
+                        left = (state.centerX - width / 2).toInt(),
+                        top = (state.centerY - height / 2).toInt(),
+                        right = (state.centerX + width / 2).toInt(),
+                        bottom = (state.centerY + height / 2).toInt(),
+                        topCornerRadius =
+                            MathUtils.lerp(
+                                startState.topCornerRadius,
+                                endState.topCornerRadius,
+                                state.scale,
+                            ),
+                        bottomCornerRadius =
+                            MathUtils.lerp(
+                                startState.bottomCornerRadius,
+                                endState.bottomCornerRadius,
+                                state.scale,
+                            ),
+                    )
+                    .apply {
+                        visible = checkVisibility(timings, state.scale, controller.isLaunching)
+                    }
+
+            if (!movedBackgroundLayer) {
+                movedBackgroundLayer =
+                    maybeMoveBackgroundLayer(
+                        controller,
+                        newState,
+                        windowBackgroundLayer,
+                        transitionContainer,
+                        transitionContainerOverlay,
+                        openingWindowSyncView,
+                        openingWindowSyncViewOverlay,
+                        moveBackgroundLayerWhenAppVisibilityChanges,
+                    )
+            }
+
+            val container =
+                if (movedBackgroundLayer) {
+                    openingWindowSyncView!!
+                } else {
+                    controller.transitionContainer
+                }
+            applyStateToWindowBackgroundLayer(
+                windowBackgroundLayer,
+                newState,
+                state.scale,
+                container,
+                fadeWindowBackgroundLayer,
+                drawHole,
+                isLaunching = false,
+                useSpring = true,
+            )
+
+            controller.onTransitionAnimationProgress(newState, state.scale, state.scale)
+
+            maybeUpdateEndState()
+        }
+
+        val springState = SpringState(centerX = startState.centerX, centerY = startState.centerY)
+        val isExpandingFullyAbove = isExpandingFullyAbove(transitionContainer, endState)
+
+        /** End listener for each spring, which only does the end work if all springs are done. */
+        fun onAnimationEnd() {
+            if (!springState.isDone) return
+            onAnimationEnd(
+                controller,
+                isExpandingFullyAbove,
+                windowBackgroundLayer,
+                transitionContainerOverlay,
+                openingWindowSyncViewOverlay,
+                moveBackgroundLayerWhenAppVisibilityChanges,
+            )
+        }
+
+        springX =
+            SpringAnimation(
+                    springState,
+                    buildProperty(SpringProperty.CENTER_X) { state -> updateProgress(state) },
+                )
+                .apply {
+                    spring =
+                        SpringForce(endState.centerX).apply {
+                            stiffness = springParams.centerXStiffness
+                            dampingRatio = springParams.centerXDampingRatio
+                        }
+
+                    setStartValue(startState.centerX)
+                    setMinValue(min(startState.centerX, endState.centerX))
+                    setMaxValue(max(startState.centerX, endState.centerX))
+
+                    addEndListener { _, _, _, _ ->
+                        springState.isCenterXDone = true
+                        onAnimationEnd()
+                    }
+                }
+        springY =
+            SpringAnimation(
+                    springState,
+                    buildProperty(SpringProperty.CENTER_Y) { state -> updateProgress(state) },
+                )
+                .apply {
+                    spring =
+                        SpringForce(endState.centerY).apply {
+                            stiffness = springParams.centerYStiffness
+                            dampingRatio = springParams.centerYDampingRatio
+                        }
+
+                    setStartValue(startState.centerY)
+                    setMinValue(min(startState.centerY, endState.centerY))
+                    setMaxValue(max(startState.centerY, endState.centerY))
+
+                    addEndListener { _, _, _, _ ->
+                        springState.isCenterYDone = true
+                        onAnimationEnd()
+                    }
+                }
+        val springScale =
+            SpringAnimation(
+                    springState,
+                    buildProperty(SpringProperty.SCALE) { state -> updateProgress(state) },
+                )
+                .apply {
+                    spring =
+                        SpringForce(1f).apply {
+                            stiffness = springParams.scaleStiffness
+                            dampingRatio = springParams.scaleDampingRatio
+                        }
+
+                    setStartValue(0f)
+                    setMaxValue(1f)
+                    setMinimumVisibleChange(abs(1f / startState.height))
+
+                    addEndListener { _, _, _, _ ->
+                        springState.isScaleDone = true
+                        onAnimationEnd()
+                    }
+                }
+
+        return MultiSpringAnimation(springX, springY, springScale, springState) {
+            onAnimationStart(
+                controller,
+                isExpandingFullyAbove,
+                windowBackgroundLayer,
+                transitionContainerOverlay,
+                openingWindowSyncViewOverlay,
+            )
+        }
+    }
+
+    private fun onAnimationStart(
+        controller: Controller,
+        isExpandingFullyAbove: Boolean,
+        windowBackgroundLayer: GradientDrawable,
+        transitionContainerOverlay: ViewGroupOverlay,
+        openingWindowSyncViewOverlay: ViewOverlay?,
+    ) {
+        if (DEBUG) {
+            Log.d(TAG, "Animation started")
+        }
+        controller.onTransitionAnimationStart(isExpandingFullyAbove)
+
+        // Add the drawable to the transition container overlay. Overlays always draw
+        // drawables after views, so we know that it will be drawn above any view added
+        // by the controller.
+        if (controller.isLaunching || openingWindowSyncViewOverlay == null) {
+            transitionContainerOverlay.add(windowBackgroundLayer)
+        } else {
+            openingWindowSyncViewOverlay.add(windowBackgroundLayer)
+        }
+    }
+
+    private fun onAnimationEnd(
+        controller: Controller,
+        isExpandingFullyAbove: Boolean,
+        windowBackgroundLayer: GradientDrawable,
+        transitionContainerOverlay: ViewGroupOverlay,
+        openingWindowSyncViewOverlay: ViewOverlay?,
+        moveBackgroundLayerWhenAppVisibilityChanges: Boolean,
+    ) {
+        if (DEBUG) {
+            Log.d(TAG, "Animation ended")
+        }
+
+        // TODO(b/330672236): Post this to the main thread instead so that it does not
+        // flicker with Flexiglass enabled.
+        controller.onTransitionAnimationEnd(isExpandingFullyAbove)
+        transitionContainerOverlay.remove(windowBackgroundLayer)
+
+        if (moveBackgroundLayerWhenAppVisibilityChanges && controller.isLaunching) {
+            openingWindowSyncViewOverlay?.remove(windowBackgroundLayer)
+        }
+    }
+
+    /** Returns whether is the controller's view should be visible with the given [timings]. */
+    private fun checkVisibility(timings: Timings, progress: Float, isLaunching: Boolean): Boolean {
+        return if (isLaunching) {
+            // The expanding view can/should be hidden once it is completely covered by the opening
+            // window.
+            getProgress(
+                timings,
+                progress,
+                timings.contentBeforeFadeOutDelay,
+                timings.contentBeforeFadeOutDuration,
+            ) < 1
+        } else {
+            // The shrinking view can/should be hidden while it is completely covered by the closing
+            // window.
+            getProgress(
+                timings,
+                progress,
+                timings.contentAfterFadeInDelay,
+                timings.contentAfterFadeInDuration,
+            ) > 0
+        }
+    }
+
+    /**
+     * If necessary, moves the background layer from the view container's overlay to the window sync
+     * view overlay, or vice versa.
+     *
+     * @return true if the background layer vwas moved, false otherwise.
+     */
+    private fun maybeMoveBackgroundLayer(
+        controller: Controller,
+        state: State,
+        windowBackgroundLayer: GradientDrawable,
+        transitionContainer: View,
+        transitionContainerOverlay: ViewGroupOverlay,
+        openingWindowSyncView: View?,
+        openingWindowSyncViewOverlay: ViewOverlay?,
+        moveBackgroundLayerWhenAppVisibilityChanges: Boolean,
+    ): Boolean {
+        if (
+            controller.isLaunching && moveBackgroundLayerWhenAppVisibilityChanges && !state.visible
+        ) {
+            // The expanding view is not visible, so the opening app is visible. If this is the
+            // first frame when it happens, trigger a one-off sync and move the background layer
+            // in its new container.
+            transitionContainerOverlay.remove(windowBackgroundLayer)
+            openingWindowSyncViewOverlay!!.add(windowBackgroundLayer)
+
+            ViewRootSync.synchronizeNextDraw(
+                transitionContainer,
+                openingWindowSyncView!!,
+                then = {},
+            )
+
+            return true
+        } else if (
+            !controller.isLaunching && moveBackgroundLayerWhenAppVisibilityChanges && state.visible
+        ) {
+            // The contracting view is now visible, so the closing app is not. If this is the first
+            // frame when it happens, trigger a one-off sync and move the background layer in its
+            // new container.
+            openingWindowSyncViewOverlay!!.remove(windowBackgroundLayer)
+            transitionContainerOverlay.add(windowBackgroundLayer)
+
+            ViewRootSync.synchronizeNextDraw(
+                openingWindowSyncView!!,
+                transitionContainer,
+                then = {},
+            )
+
+            return true
+        }
+
+        return false
     }
 
     /** Return whether we are expanding fully above the [transitionContainer]. */
@@ -511,6 +999,7 @@
         fadeWindowBackgroundLayer: Boolean,
         drawHole: Boolean,
         isLaunching: Boolean,
+        useSpring: Boolean,
     ) {
         // Update position.
         transitionContainer.getLocationOnScreen(transitionContainerLocation)
@@ -532,8 +1021,19 @@
         cornerRadii[7] = state.bottomCornerRadius
         drawable.cornerRadii = cornerRadii
 
-        // We first fade in the background layer to hide the expanding view, then fade it out
-        // with SRC mode to draw a hole punch in the status bar and reveal the opening window.
+        val timings: Timings
+        val interpolators: Interpolators
+        if (useSpring) {
+            timings = springTimings!!
+            interpolators = springInterpolators!!
+        } else {
+            timings = this.timings
+            interpolators = this.interpolators
+        }
+
+        // We first fade in the background layer to hide the expanding view, then fade it out with
+        // SRC mode to draw a hole punch in the status bar and reveal the opening window (if
+        // needed). If !isLaunching, the reverse happens.
         val fadeInProgress =
             getProgress(
                 timings,
@@ -541,6 +1041,13 @@
                 timings.contentBeforeFadeOutDelay,
                 timings.contentBeforeFadeOutDuration,
             )
+        val fadeOutProgress =
+            getProgress(
+                timings,
+                linearProgress,
+                timings.contentAfterFadeInDelay,
+                timings.contentAfterFadeInDuration,
+            )
 
         if (isLaunching) {
             if (fadeInProgress < 1) {
@@ -548,13 +1055,6 @@
                     interpolators.contentBeforeFadeOutInterpolator.getInterpolation(fadeInProgress)
                 drawable.alpha = (alpha * 0xFF).roundToInt()
             } else if (fadeWindowBackgroundLayer) {
-                val fadeOutProgress =
-                    getProgress(
-                        timings,
-                        linearProgress,
-                        timings.contentAfterFadeInDelay,
-                        timings.contentAfterFadeInDuration,
-                    )
                 val alpha =
                     1 -
                         interpolators.contentAfterFadeInInterpolator.getInterpolation(
@@ -578,13 +1078,6 @@
                     drawable.setXfermode(SRC_MODE)
                 }
             } else {
-                val fadeOutProgress =
-                    getProgress(
-                        timings,
-                        linearProgress,
-                        timings.contentAfterFadeInDelay,
-                        timings.contentAfterFadeInDuration,
-                    )
                 val alpha =
                     1 -
                         interpolators.contentAfterFadeInInterpolator.getInterpolation(
diff --git a/packages/SystemUI/compose/core/src/com/android/compose/activity/EdgeToEdgeActivitContent.kt b/packages/SystemUI/compose/core/src/com/android/compose/activity/EdgeToEdgeActivitContent.kt
deleted file mode 100644
index 97c8076..0000000
--- a/packages/SystemUI/compose/core/src/com/android/compose/activity/EdgeToEdgeActivitContent.kt
+++ /dev/null
@@ -1,61 +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.compose.activity
-
-import androidx.compose.foundation.background
-import androidx.compose.foundation.isSystemInDarkTheme
-import androidx.compose.foundation.layout.Box
-import androidx.compose.foundation.layout.fillMaxSize
-import androidx.compose.material3.LocalContentColor
-import androidx.compose.material3.MaterialTheme
-import androidx.compose.material3.contentColorFor
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.CompositionLocalProvider
-import androidx.compose.runtime.DisposableEffect
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.graphics.Color
-import com.android.compose.rememberSystemUiController
-import com.android.compose.theme.PlatformTheme
-
-/** Scaffolding for an edge-to-edge activity content. */
-@Composable
-fun EdgeToEdgeActivityContent(
-    modifier: Modifier = Modifier,
-    content: @Composable () -> Unit,
-) {
-    // Make the status and navigation bars transparent, ensuring that the status bar icons are dark
-    // when the theme is light and vice-versa.
-    val systemUiController = rememberSystemUiController()
-    val isDarkTheme = isSystemInDarkTheme()
-    val useDarkIcons = !isDarkTheme
-    DisposableEffect(systemUiController, useDarkIcons) {
-        systemUiController.setSystemBarsColor(
-            color = Color.Transparent,
-            darkIcons = useDarkIcons,
-        )
-        onDispose {}
-    }
-
-    PlatformTheme(isDarkTheme) {
-        val backgroundColor = MaterialTheme.colorScheme.background
-        Box(modifier.fillMaxSize().background(backgroundColor)) {
-            CompositionLocalProvider(LocalContentColor provides contentColorFor(backgroundColor)) {
-                content()
-            }
-        }
-    }
-}
diff --git a/packages/SystemUI/compose/core/src/com/android/compose/animation/Easings.kt b/packages/SystemUI/compose/core/src/com/android/compose/animation/Easings.kt
index 4fe9f89..dc6e0ce 100644
--- a/packages/SystemUI/compose/core/src/com/android/compose/animation/Easings.kt
+++ b/packages/SystemUI/compose/core/src/com/android/compose/animation/Easings.kt
@@ -16,6 +16,7 @@
 
 package com.android.compose.animation
 
+import androidx.compose.animation.core.CubicBezierEasing
 import androidx.compose.animation.core.Easing
 import androidx.core.animation.Interpolator
 import com.android.app.animation.InterpolatorsAndroidX
@@ -59,6 +60,17 @@
     /** The linear interpolator. */
     val Linear = fromInterpolator(InterpolatorsAndroidX.LINEAR)
 
+    /**
+     * Use this easing for animating progress values coming from the back callback to get the
+     * predictive-back-typical decelerate motion.
+     *
+     * This easing is similar to [StandardDecelerate] but has a slight acceleration phase at the
+     * start.
+     *
+     * See also [InterpolatorsAndroidX.BACK_GESTURE].
+     */
+    val PredictiveBack = CubicBezierEasing(0.1f, 0.1f, 0f, 1f)
+
     /** The default legacy interpolator as defined in Material 1. Also known as FAST_OUT_SLOW_IN. */
     val Legacy = fromInterpolator(InterpolatorsAndroidX.LEGACY)
 
diff --git a/packages/SystemUI/compose/core/src/com/android/compose/theme/AndroidColorScheme.kt b/packages/SystemUI/compose/core/src/com/android/compose/theme/AndroidColorScheme.kt
index b28655b..1256641 100644
--- a/packages/SystemUI/compose/core/src/com/android/compose/theme/AndroidColorScheme.kt
+++ b/packages/SystemUI/compose/core/src/com/android/compose/theme/AndroidColorScheme.kt
@@ -16,8 +16,9 @@
 
 package com.android.compose.theme
 
-import android.annotation.ColorInt
 import android.content.Context
+import androidx.annotation.ColorRes
+import androidx.compose.runtime.Immutable
 import androidx.compose.runtime.staticCompositionLocalOf
 import androidx.compose.ui.graphics.Color
 import com.android.internal.R
@@ -34,94 +35,45 @@
 /**
  * The Android color scheme.
  *
- * Important: Use M3 colors from MaterialTheme.colorScheme whenever possible instead. In the future,
- * most of the colors in this class will be removed in favor of their M3 counterpart.
+ * This scheme contains the Material3 colors that are not available on
+ * [androidx.compose.material3.MaterialTheme]. For other colors (e.g. primary), use
+ * `MaterialTheme.colorScheme` instead.
  */
-class AndroidColorScheme(context: Context) {
-    val onSecondaryFixedVariant = getColor(context, R.attr.materialColorOnSecondaryFixedVariant)
-    val onTertiaryFixedVariant = getColor(context, R.attr.materialColorOnTertiaryFixedVariant)
-    val surfaceContainerLowest = getColor(context, R.attr.materialColorSurfaceContainerLowest)
-    val onPrimaryFixedVariant = getColor(context, R.attr.materialColorOnPrimaryFixedVariant)
-    val onSecondaryContainer = getColor(context, R.attr.materialColorOnSecondaryContainer)
-    val onTertiaryContainer = getColor(context, R.attr.materialColorOnTertiaryContainer)
-    val surfaceContainerLow = getColor(context, R.attr.materialColorSurfaceContainerLow)
-    val onPrimaryContainer = getColor(context, R.attr.materialColorOnPrimaryContainer)
-    val secondaryFixedDim = getColor(context, R.attr.materialColorSecondaryFixedDim)
-    val onErrorContainer = getColor(context, R.attr.materialColorOnErrorContainer)
-    val onSecondaryFixed = getColor(context, R.attr.materialColorOnSecondaryFixed)
-    val onSurfaceInverse = getColor(context, R.attr.materialColorOnSurfaceInverse)
-    val tertiaryFixedDim = getColor(context, R.attr.materialColorTertiaryFixedDim)
-    val onTertiaryFixed = getColor(context, R.attr.materialColorOnTertiaryFixed)
-    val primaryFixedDim = getColor(context, R.attr.materialColorPrimaryFixedDim)
-    val secondaryContainer = getColor(context, R.attr.materialColorSecondaryContainer)
-    val errorContainer = getColor(context, R.attr.materialColorErrorContainer)
-    val onPrimaryFixed = getColor(context, R.attr.materialColorOnPrimaryFixed)
-    val primaryInverse = getColor(context, R.attr.materialColorPrimaryInverse)
-    val secondaryFixed = getColor(context, R.attr.materialColorSecondaryFixed)
-    val surfaceInverse = getColor(context, R.attr.materialColorSurfaceInverse)
-    val surfaceVariant = getColor(context, R.attr.materialColorSurfaceVariant)
-    val tertiaryContainer = getColor(context, R.attr.materialColorTertiaryContainer)
-    val tertiaryFixed = getColor(context, R.attr.materialColorTertiaryFixed)
-    val primaryContainer = getColor(context, R.attr.materialColorPrimaryContainer)
-    val onBackground = getColor(context, R.attr.materialColorOnBackground)
-    val primaryFixed = getColor(context, R.attr.materialColorPrimaryFixed)
-    val onSecondary = getColor(context, R.attr.materialColorOnSecondary)
-    val onTertiary = getColor(context, R.attr.materialColorOnTertiary)
-    val surfaceDim = getColor(context, R.attr.materialColorSurfaceDim)
-    val surfaceBright = getColor(context, R.attr.materialColorSurfaceBright)
-    val error = getColor(context, R.attr.materialColorError)
-    val onError = getColor(context, R.attr.materialColorOnError)
-    val surface = getColor(context, R.attr.materialColorSurface)
-    val surfaceContainerHigh = getColor(context, R.attr.materialColorSurfaceContainerHigh)
-    val surfaceContainerHighest = getColor(context, R.attr.materialColorSurfaceContainerHighest)
-    val onSurfaceVariant = getColor(context, R.attr.materialColorOnSurfaceVariant)
-    val outline = getColor(context, R.attr.materialColorOutline)
-    val outlineVariant = getColor(context, R.attr.materialColorOutlineVariant)
-    val onPrimary = getColor(context, R.attr.materialColorOnPrimary)
-    val onSurface = getColor(context, R.attr.materialColorOnSurface)
-    val surfaceContainer = getColor(context, R.attr.materialColorSurfaceContainer)
-    val primary = getColor(context, R.attr.materialColorPrimary)
-    val secondary = getColor(context, R.attr.materialColorSecondary)
-    val tertiary = getColor(context, R.attr.materialColorTertiary)
-
-    @Deprecated("Use the new android tokens: go/sysui-colors")
-    val deprecated = DeprecatedValues(context)
-
-    class DeprecatedValues(context: Context) {
-        val colorPrimary = getColor(context, R.attr.colorPrimary)
-        val colorPrimaryDark = getColor(context, R.attr.colorPrimaryDark)
-        val colorAccent = getColor(context, R.attr.colorAccent)
-        val colorAccentPrimary = getColor(context, R.attr.colorAccentPrimary)
-        val colorAccentSecondary = getColor(context, R.attr.colorAccentSecondary)
-        val colorAccentTertiary = getColor(context, R.attr.colorAccentTertiary)
-        val colorAccentPrimaryVariant = getColor(context, R.attr.colorAccentPrimaryVariant)
-        val colorAccentSecondaryVariant = getColor(context, R.attr.colorAccentSecondaryVariant)
-        val colorAccentTertiaryVariant = getColor(context, R.attr.colorAccentTertiaryVariant)
-        val colorSurface = getColor(context, R.attr.colorSurface)
-        val colorSurfaceHighlight = getColor(context, R.attr.colorSurfaceHighlight)
-        val colorSurfaceVariant = getColor(context, R.attr.colorSurfaceVariant)
-        val colorSurfaceHeader = getColor(context, R.attr.colorSurfaceHeader)
-        val colorError = getColor(context, R.attr.colorError)
-        val colorBackground = getColor(context, R.attr.colorBackground)
-        val colorBackgroundFloating = getColor(context, R.attr.colorBackgroundFloating)
-        val panelColorBackground = getColor(context, R.attr.panelColorBackground)
-        val textColorPrimary = getColor(context, R.attr.textColorPrimary)
-        val textColorSecondary = getColor(context, R.attr.textColorSecondary)
-        val textColorTertiary = getColor(context, R.attr.textColorTertiary)
-        val textColorPrimaryInverse = getColor(context, R.attr.textColorPrimaryInverse)
-        val textColorSecondaryInverse = getColor(context, R.attr.textColorSecondaryInverse)
-        val textColorTertiaryInverse = getColor(context, R.attr.textColorTertiaryInverse)
-        val textColorOnAccent = getColor(context, R.attr.textColorOnAccent)
-        val colorForeground = getColor(context, R.attr.colorForeground)
-        val colorForegroundInverse = getColor(context, R.attr.colorForegroundInverse)
-    }
-
+@Immutable
+class AndroidColorScheme(
+    val primaryFixed: Color,
+    val primaryFixedDim: Color,
+    val onPrimaryFixed: Color,
+    val onPrimaryFixedVariant: Color,
+    val secondaryFixed: Color,
+    val secondaryFixedDim: Color,
+    val onSecondaryFixed: Color,
+    val onSecondaryFixedVariant: Color,
+    val tertiaryFixed: Color,
+    val tertiaryFixedDim: Color,
+    val onTertiaryFixed: Color,
+    val onTertiaryFixedVariant: Color,
+) {
     companion object {
-        fun getColor(context: Context, attr: Int): Color {
-            val ta = context.obtainStyledAttributes(intArrayOf(attr))
-            @ColorInt val color = ta.getColor(0, 0)
-            ta.recycle()
-            return Color(color)
+        internal fun color(context: Context, @ColorRes id: Int): Color {
+            return Color(context.resources.getColor(id, context.theme))
+        }
+
+        operator fun invoke(context: Context): AndroidColorScheme {
+            return AndroidColorScheme(
+                primaryFixed = color(context, R.color.system_primary_fixed),
+                primaryFixedDim = color(context, R.color.system_primary_fixed_dim),
+                onPrimaryFixed = color(context, R.color.system_on_primary_fixed),
+                onPrimaryFixedVariant = color(context, R.color.system_on_primary_fixed_variant),
+                secondaryFixed = color(context, R.color.system_secondary_fixed),
+                secondaryFixedDim = color(context, R.color.system_secondary_fixed_dim),
+                onSecondaryFixed = color(context, R.color.system_on_secondary_fixed),
+                onSecondaryFixedVariant = color(context, R.color.system_on_secondary_fixed_variant),
+                tertiaryFixed = color(context, R.color.system_tertiary_fixed),
+                tertiaryFixedDim = color(context, R.color.system_tertiary_fixed_dim),
+                onTertiaryFixed = color(context, R.color.system_on_tertiary_fixed),
+                onTertiaryFixedVariant = color(context, R.color.system_on_tertiary_fixed_variant),
+            )
         }
     }
 }
diff --git a/packages/SystemUI/compose/core/src/com/android/compose/theme/Color.kt b/packages/SystemUI/compose/core/src/com/android/compose/theme/Color.kt
index 5dbaff6..a499447 100644
--- a/packages/SystemUI/compose/core/src/com/android/compose/theme/Color.kt
+++ b/packages/SystemUI/compose/core/src/com/android/compose/theme/Color.kt
@@ -17,6 +17,8 @@
 package com.android.compose.theme
 
 import android.annotation.AttrRes
+import android.annotation.ColorInt
+import android.content.Context
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.ReadOnlyComposable
 import androidx.compose.ui.graphics.Color
@@ -26,5 +28,13 @@
 @Composable
 @ReadOnlyComposable
 fun colorAttr(@AttrRes attribute: Int): Color {
-    return AndroidColorScheme.getColor(LocalContext.current, attribute)
+    return colorAttr(LocalContext.current, attribute)
+}
+
+/** Return the [Color] from the given [attribute]. */
+fun colorAttr(context: Context, @AttrRes attr: Int): Color {
+    val ta = context.obtainStyledAttributes(intArrayOf(attr))
+    @ColorInt val color = ta.getColor(0, 0)
+    ta.recycle()
+    return Color(color)
 }
diff --git a/packages/SystemUI/compose/core/src/com/android/compose/theme/PlatformTheme.kt b/packages/SystemUI/compose/core/src/com/android/compose/theme/PlatformTheme.kt
index 0661870..d31d7aa 100644
--- a/packages/SystemUI/compose/core/src/com/android/compose/theme/PlatformTheme.kt
+++ b/packages/SystemUI/compose/core/src/com/android/compose/theme/PlatformTheme.kt
@@ -16,7 +16,9 @@
 
 package com.android.compose.theme
 
+import android.content.Context
 import androidx.compose.foundation.isSystemInDarkTheme
+import androidx.compose.material3.ColorScheme
 import androidx.compose.material3.MaterialTheme
 import androidx.compose.material3.dynamicDarkColorScheme
 import androidx.compose.material3.dynamicLightColorScheme
@@ -24,6 +26,7 @@
 import androidx.compose.runtime.CompositionLocalProvider
 import androidx.compose.runtime.remember
 import androidx.compose.ui.platform.LocalContext
+import com.android.compose.theme.AndroidColorScheme.Companion.color
 import com.android.compose.theme.typography.TypeScaleTokens
 import com.android.compose.theme.typography.TypefaceNames
 import com.android.compose.theme.typography.TypefaceTokens
@@ -31,23 +34,15 @@
 import com.android.compose.theme.typography.platformTypography
 import com.android.compose.windowsizeclass.LocalWindowSizeClass
 import com.android.compose.windowsizeclass.calculateWindowSizeClass
+import com.android.internal.R
 
 /** The Material 3 theme that should wrap all Platform Composables. */
 @Composable
-fun PlatformTheme(
-    isDarkTheme: Boolean = isSystemInDarkTheme(),
-    content: @Composable () -> Unit,
-) {
+fun PlatformTheme(isDarkTheme: Boolean = isSystemInDarkTheme(), content: @Composable () -> Unit) {
     val context = LocalContext.current
 
-    // TODO(b/230605885): Define our color scheme.
-    val colorScheme =
-        if (isDarkTheme) {
-            dynamicDarkColorScheme(context)
-        } else {
-            dynamicLightColorScheme(context)
-        }
-    val androidColorScheme = AndroidColorScheme(context)
+    val colorScheme = remember(context, isDarkTheme) { platformColorScheme(isDarkTheme, context) }
+    val androidColorScheme = remember(context) { AndroidColorScheme(context) }
     val typefaceNames = remember(context) { TypefaceNames.get(context) }
     val typography =
         remember(typefaceNames) {
@@ -55,12 +50,31 @@
         }
     val windowSizeClass = calculateWindowSizeClass()
 
-    MaterialTheme(colorScheme, typography = typography) {
+    MaterialTheme(colorScheme = colorScheme, typography = typography) {
         CompositionLocalProvider(
             LocalAndroidColorScheme provides androidColorScheme,
             LocalWindowSizeClass provides windowSizeClass,
-        ) {
-            content()
-        }
+            content = content,
+        )
+    }
+}
+
+private fun platformColorScheme(isDarkTheme: Boolean, context: Context): ColorScheme {
+    return if (isDarkTheme) {
+        dynamicDarkColorScheme(context)
+            .copy(
+                error = color(context, R.color.system_error_dark),
+                onError = color(context, R.color.system_on_error_dark),
+                errorContainer = color(context, R.color.system_error_container_dark),
+                onErrorContainer = color(context, R.color.system_on_error_container_dark),
+            )
+    } else {
+        dynamicLightColorScheme(context)
+            .copy(
+                error = color(context, R.color.system_error_light),
+                onError = color(context, R.color.system_on_error_light),
+                errorContainer = color(context, R.color.system_error_container_light),
+                onErrorContainer = color(context, R.color.system_on_error_container_light),
+            )
     }
 }
diff --git a/packages/SystemUI/compose/core/tests/Android.bp b/packages/SystemUI/compose/core/tests/Android.bp
index 6e7a142..6a824d8 100644
--- a/packages/SystemUI/compose/core/tests/Android.bp
+++ b/packages/SystemUI/compose/core/tests/Android.bp
@@ -27,7 +27,6 @@
     name: "PlatformComposeCoreTests",
     manifest: "AndroidManifest.xml",
     test_suites: ["device-tests"],
-    sdk_version: "current",
     certificate: "platform",
 
     srcs: [
diff --git a/packages/SystemUI/compose/core/tests/AndroidManifest.xml b/packages/SystemUI/compose/core/tests/AndroidManifest.xml
index 1016340..28f80d4 100644
--- a/packages/SystemUI/compose/core/tests/AndroidManifest.xml
+++ b/packages/SystemUI/compose/core/tests/AndroidManifest.xml
@@ -19,6 +19,11 @@
 
     <application>
         <uses-library android:name="android.test.runner" />
+
+        <activity
+            android:name="androidx.activity.ComponentActivity"
+            android:theme="@android:style/Theme.DeviceDefault.DayNight"
+            android:exported="true" />
     </application>
 
     <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
diff --git a/packages/SystemUI/compose/core/tests/src/com/android/compose/theme/PlatformThemeTest.kt b/packages/SystemUI/compose/core/tests/src/com/android/compose/theme/PlatformThemeTest.kt
new file mode 100644
index 0000000..de021a0
--- /dev/null
+++ b/packages/SystemUI/compose/core/tests/src/com/android/compose/theme/PlatformThemeTest.kt
@@ -0,0 +1,208 @@
+/*
+ * 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.compose.theme
+
+import android.content.Context
+import androidx.annotation.AttrRes
+import androidx.compose.material3.ColorScheme
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Text
+import androidx.compose.runtime.LaunchedEffect
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.test.assertIsDisplayed
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.compose.ui.test.onNodeWithText
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.internal.R
+import com.google.common.truth.Truth.assertThat
+import com.google.common.truth.Truth.assertWithMessage
+import org.junit.Assert.assertThrows
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+class PlatformThemeTest {
+    @get:Rule val composeRule = createComposeRule()
+
+    @Test
+    fun testThemeShowsContent() {
+        composeRule.setContent { PlatformTheme { Text("foo") } }
+
+        composeRule.onNodeWithText("foo").assertIsDisplayed()
+    }
+
+    @Test
+    fun testAndroidColorsAreAvailableInsideTheme() {
+        composeRule.setContent {
+            PlatformTheme { Text("foo", color = LocalAndroidColorScheme.current.primaryFixed) }
+        }
+
+        composeRule.onNodeWithText("foo").assertIsDisplayed()
+    }
+
+    @Test
+    fun testAccessingAndroidColorsWithoutThemeThrows() {
+        assertThrows(IllegalStateException::class.java) {
+            composeRule.setContent {
+                Text("foo", color = LocalAndroidColorScheme.current.primaryFixed)
+            }
+        }
+    }
+
+    @Test
+    fun testMaterialColorsMatchAttributeValue() {
+        val colorValues = mutableListOf<ColorValue>()
+
+        fun onLaunch(colorScheme: ColorScheme, context: Context) {
+            fun addValue(name: String, materialValue: Color, @AttrRes attr: Int) {
+                colorValues.add(ColorValue(name, materialValue, colorAttr(context, attr)))
+            }
+
+            addValue("primary", colorScheme.primary, R.attr.materialColorPrimary)
+            addValue("onPrimary", colorScheme.onPrimary, R.attr.materialColorOnPrimary)
+            addValue(
+                "primaryContainer",
+                colorScheme.primaryContainer,
+                R.attr.materialColorPrimaryContainer,
+            )
+            addValue(
+                "onPrimaryContainer",
+                colorScheme.onPrimaryContainer,
+                R.attr.materialColorOnPrimaryContainer,
+            )
+            addValue(
+                "inversePrimary",
+                colorScheme.inversePrimary,
+                R.attr.materialColorPrimaryInverse,
+            )
+            addValue("secondary", colorScheme.secondary, R.attr.materialColorSecondary)
+            addValue("onSecondary", colorScheme.onSecondary, R.attr.materialColorOnSecondary)
+            addValue(
+                "secondaryContainer",
+                colorScheme.secondaryContainer,
+                R.attr.materialColorSecondaryContainer,
+            )
+            addValue(
+                "onSecondaryContainer",
+                colorScheme.onSecondaryContainer,
+                R.attr.materialColorOnSecondaryContainer,
+            )
+            addValue("tertiary", colorScheme.tertiary, R.attr.materialColorTertiary)
+            addValue("onTertiary", colorScheme.onTertiary, R.attr.materialColorOnTertiary)
+            addValue(
+                "tertiaryContainer",
+                colorScheme.tertiaryContainer,
+                R.attr.materialColorTertiaryContainer,
+            )
+            addValue(
+                "onTertiaryContainer",
+                colorScheme.onTertiaryContainer,
+                R.attr.materialColorOnTertiaryContainer,
+            )
+            addValue("onBackground", colorScheme.onBackground, R.attr.materialColorOnBackground)
+            addValue("surface", colorScheme.surface, R.attr.materialColorSurface)
+            addValue("onSurface", colorScheme.onSurface, R.attr.materialColorOnSurface)
+            addValue(
+                "surfaceVariant",
+                colorScheme.surfaceVariant,
+                R.attr.materialColorSurfaceVariant,
+            )
+            addValue(
+                "onSurfaceVariant",
+                colorScheme.onSurfaceVariant,
+                R.attr.materialColorOnSurfaceVariant,
+            )
+            addValue(
+                "inverseSurface",
+                colorScheme.inverseSurface,
+                R.attr.materialColorSurfaceInverse,
+            )
+            addValue(
+                "inverseOnSurface",
+                colorScheme.inverseOnSurface,
+                R.attr.materialColorOnSurfaceInverse,
+            )
+            addValue("error", colorScheme.error, R.attr.materialColorError)
+            addValue("onError", colorScheme.onError, R.attr.materialColorOnError)
+            addValue(
+                "errorContainer",
+                colorScheme.errorContainer,
+                R.attr.materialColorErrorContainer,
+            )
+            addValue(
+                "onErrorContainer",
+                colorScheme.onErrorContainer,
+                R.attr.materialColorOnErrorContainer,
+            )
+            addValue("outline", colorScheme.outline, R.attr.materialColorOutline)
+            addValue(
+                "outlineVariant",
+                colorScheme.outlineVariant,
+                R.attr.materialColorOutlineVariant,
+            )
+            addValue("surfaceBright", colorScheme.surfaceBright, R.attr.materialColorSurfaceBright)
+            addValue("surfaceDim", colorScheme.surfaceDim, R.attr.materialColorSurfaceDim)
+            addValue(
+                "surfaceContainer",
+                colorScheme.surfaceContainer,
+                R.attr.materialColorSurfaceContainer,
+            )
+            addValue(
+                "surfaceContainerHigh",
+                colorScheme.surfaceContainerHigh,
+                R.attr.materialColorSurfaceContainerHigh,
+            )
+            addValue(
+                "surfaceContainerHighest",
+                colorScheme.surfaceContainerHighest,
+                R.attr.materialColorSurfaceContainerHighest,
+            )
+            addValue(
+                "surfaceContainerLow",
+                colorScheme.surfaceContainerLow,
+                R.attr.materialColorSurfaceContainerLow,
+            )
+            addValue(
+                "surfaceContainerLowest",
+                colorScheme.surfaceContainerLowest,
+                R.attr.materialColorSurfaceContainerLowest,
+            )
+        }
+
+        composeRule.setContent {
+            PlatformTheme {
+                val colorScheme = MaterialTheme.colorScheme
+                val context = LocalContext.current
+
+                LaunchedEffect(Unit) { onLaunch(colorScheme, context) }
+            }
+        }
+
+        assertThat(colorValues).hasSize(33)
+        colorValues.forEach { colorValue ->
+            assertWithMessage(
+                    "MaterialTheme.colorScheme.${colorValue.name} matches attribute color"
+                )
+                .that(colorValue.materialValue)
+                .isEqualTo(colorValue.attrValue)
+        }
+    }
+
+    private data class ColorValue(val name: String, val materialValue: Color, val attrValue: Color)
+}
diff --git a/packages/SystemUI/compose/core/tests/src/com/android/compose/theme/SystemUIThemeTest.kt b/packages/SystemUI/compose/core/tests/src/com/android/compose/theme/SystemUIThemeTest.kt
deleted file mode 100644
index fe34017..0000000
--- a/packages/SystemUI/compose/core/tests/src/com/android/compose/theme/SystemUIThemeTest.kt
+++ /dev/null
@@ -1,59 +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.compose.theme
-
-import androidx.compose.material3.Text
-import androidx.compose.ui.test.assertIsDisplayed
-import androidx.compose.ui.test.junit4.createComposeRule
-import androidx.compose.ui.test.onNodeWithText
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import org.junit.Assert.assertThrows
-import org.junit.Rule
-import org.junit.Test
-import org.junit.runner.RunWith
-
-@RunWith(AndroidJUnit4::class)
-class SystemUIThemeTest {
-    @get:Rule val composeRule = createComposeRule()
-
-    @Test
-    fun testThemeShowsContent() {
-        composeRule.setContent { PlatformTheme { Text("foo") } }
-
-        composeRule.onNodeWithText("foo").assertIsDisplayed()
-    }
-
-    @Test
-    fun testAndroidColorsAreAvailableInsideTheme() {
-        composeRule.setContent {
-            PlatformTheme {
-                Text("foo", color = LocalAndroidColorScheme.current.deprecated.colorAccent)
-            }
-        }
-
-        composeRule.onNodeWithText("foo").assertIsDisplayed()
-    }
-
-    @Test
-    fun testAccessingAndroidColorsWithoutThemeThrows() {
-        assertThrows(IllegalStateException::class.java) {
-            composeRule.setContent {
-                Text("foo", color = LocalAndroidColorScheme.current.deprecated.colorAccent)
-            }
-        }
-    }
-}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerContent.kt b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerContent.kt
index bf8f6ce..7dc2901 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerContent.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerContent.kt
@@ -522,13 +522,7 @@
     val currentSceneKey =
         if (isSplitAroundTheFold) SceneKeys.SplitSceneKey else SceneKeys.ContiguousSceneKey
 
-    val state = remember {
-        MutableSceneTransitionLayoutState(
-            currentSceneKey,
-            SceneTransitions,
-            enableInterruptions = false,
-        )
-    }
+    val state = remember { MutableSceneTransitionLayoutState(currentSceneKey, SceneTransitions) }
 
     // Update state whenever currentSceneKey has changed.
     LaunchedEffect(state, currentSceneKey) {
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt
index 557257d..6d30398 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt
@@ -13,6 +13,7 @@
 import androidx.compose.foundation.layout.Box
 import androidx.compose.foundation.layout.BoxScope
 import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.material3.MaterialTheme
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.DisposableEffect
 import androidx.compose.runtime.getValue
@@ -44,8 +45,6 @@
 import com.android.compose.animation.scene.SwipeDirection
 import com.android.compose.animation.scene.observableTransitionState
 import com.android.compose.animation.scene.transitions
-import com.android.compose.theme.LocalAndroidColorScheme
-import com.android.internal.R.attr.focusable
 import com.android.systemui.communal.shared.model.CommunalBackgroundType
 import com.android.systemui.communal.shared.model.CommunalScenes
 import com.android.systemui.communal.shared.model.CommunalTransitionKeys
@@ -162,7 +161,6 @@
             initialScene = currentSceneKey,
             canChangeScene = { _ -> viewModel.canChangeScene() },
             transitions = sceneTransitions,
-            enableInterruptions = false,
         )
     }
 
@@ -271,7 +269,7 @@
 /** Experimental hub background, static linear gradient */
 @Composable
 private fun BoxScope.StaticLinearGradient() {
-    val colors = LocalAndroidColorScheme.current
+    val colors = MaterialTheme.colorScheme
     Box(
         Modifier.matchParentSize()
             .background(
@@ -284,7 +282,7 @@
 /** Experimental hub background, animated linear gradient */
 @Composable
 private fun BoxScope.AnimatedLinearGradient() {
-    val colors = LocalAndroidColorScheme.current
+    val colors = MaterialTheme.colorScheme
     Box(
         Modifier.matchParentSize()
             .background(colors.primary)
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContent.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContent.kt
index 6fca178..9392b1a 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContent.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContent.kt
@@ -19,12 +19,12 @@
 import androidx.compose.foundation.layout.Box
 import androidx.compose.foundation.layout.fillMaxSize
 import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.material3.MaterialTheme
 import androidx.compose.runtime.Composable
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.layout.Layout
 import androidx.compose.ui.unit.IntRect
 import com.android.compose.animation.scene.SceneScope
-import com.android.compose.theme.LocalAndroidColorScheme
 import com.android.systemui.communal.smartspace.SmartspaceInteractionHandler
 import com.android.systemui.communal.ui.compose.section.AmbientStatusBarSection
 import com.android.systemui.communal.ui.compose.section.CommunalPopupSection
@@ -71,7 +71,7 @@
                     }
                     with(lockSection) {
                         LockIcon(
-                            overrideColor = LocalAndroidColorScheme.current.onPrimaryContainer,
+                            overrideColor = MaterialTheme.colorScheme.onPrimaryContainer,
                             modifier = Modifier.element(Communal.Elements.LockIcon)
                         )
                     }
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
index bcd3337..96c47cc 100644
--- 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
@@ -148,6 +148,7 @@
 import androidx.compose.ui.text.style.TextAlign
 import androidx.compose.ui.unit.Density
 import androidx.compose.ui.unit.Dp
+import androidx.compose.ui.unit.DpSize
 import androidx.compose.ui.unit.IntSize
 import androidx.compose.ui.unit.LayoutDirection
 import androidx.compose.ui.unit.dp
@@ -160,11 +161,11 @@
 import androidx.window.layout.WindowMetricsCalculator
 import com.android.compose.animation.Easings.Emphasized
 import com.android.compose.modifiers.thenIf
-import com.android.compose.theme.LocalAndroidColorScheme
 import com.android.compose.ui.graphics.painter.rememberDrawablePainter
 import com.android.internal.R.dimen.system_app_widget_background_radius
 import com.android.systemui.Flags
 import com.android.systemui.Flags.communalTimerFlickerFix
+import com.android.systemui.Flags.communalWidgetResizing
 import com.android.systemui.communal.domain.model.CommunalContentModel
 import com.android.systemui.communal.shared.model.CommunalContentSize
 import com.android.systemui.communal.shared.model.CommunalScenes
@@ -176,6 +177,7 @@
 import com.android.systemui.communal.ui.viewmodel.BaseCommunalViewModel
 import com.android.systemui.communal.ui.viewmodel.CommunalEditModeViewModel
 import com.android.systemui.communal.ui.viewmodel.CommunalViewModel
+import com.android.systemui.communal.ui.viewmodel.ResizeInfo
 import com.android.systemui.communal.util.DensityUtils.Companion.adjustedDp
 import com.android.systemui.communal.widgets.SmartspaceAppWidgetHostView
 import com.android.systemui.communal.widgets.WidgetConfigurator
@@ -470,7 +472,7 @@
             if (showBottomSheet) {
                 val scope = rememberCoroutineScope()
                 val sheetState = rememberModalBottomSheetState()
-                val colors = LocalAndroidColorScheme.current
+                val colors = MaterialTheme.colorScheme
 
                 ModalBottomSheet(
                     onDismissRequest = viewModel::onDisclaimerDismissed,
@@ -498,7 +500,7 @@
 
 @Composable
 private fun DisclaimerBottomSheetContent(onButtonClicked: () -> Unit) {
-    val colors = LocalAndroidColorScheme.current
+    val colors = MaterialTheme.colorScheme
 
     Column(
         modifier = Modifier.fillMaxWidth().padding(horizontal = 32.dp, vertical = 24.dp),
@@ -639,6 +641,38 @@
     }
 }
 
+@Composable
+private fun ResizableItemFrameWrapper(
+    key: String,
+    gridState: LazyGridState,
+    minItemSpan: Int,
+    gridContentPadding: PaddingValues,
+    verticalArrangement: Arrangement.Vertical,
+    enabled: Boolean,
+    modifier: Modifier = Modifier,
+    alpha: () -> Float = { 1f },
+    onResize: (info: ResizeInfo) -> Unit = {},
+    content: @Composable (modifier: Modifier) -> Unit,
+) {
+    if (!communalWidgetResizing()) {
+        content(modifier)
+    } else {
+        ResizableItemFrame(
+            key = key,
+            gridState = gridState,
+            minItemSpan = minItemSpan,
+            gridContentPadding = gridContentPadding,
+            verticalArrangement = verticalArrangement,
+            enabled = enabled,
+            alpha = alpha,
+            modifier = modifier,
+            onResize = onResize,
+        ) {
+            content(Modifier)
+        }
+    }
+}
+
 @OptIn(ExperimentalFoundationApi::class)
 @Composable
 private fun BoxScope.CommunalHubLazyGrid(
@@ -695,13 +729,14 @@
         gridModifier = gridModifier.height(hubDimensions.GridHeight)
     }
 
+    val itemArrangement = Arrangement.spacedBy(Dimensions.ItemSpacing)
     LazyHorizontalGrid(
         modifier = gridModifier,
         state = gridState,
         rows = GridCells.Fixed(CommunalContentSize.FULL.span),
         contentPadding = contentPadding,
-        horizontalArrangement = Arrangement.spacedBy(Dimensions.ItemSpacing),
-        verticalArrangement = Arrangement.spacedBy(Dimensions.ItemSpacing),
+        horizontalArrangement = itemArrangement,
+        verticalArrangement = itemArrangement,
     ) {
         itemsIndexed(
             items = list,
@@ -710,35 +745,54 @@
             span = { _, item -> GridItemSpan(item.size.span) },
         ) { index, item ->
             val size = SizeF(Dimensions.CardWidth.value, item.size.dp().value)
-            val cardModifier = Modifier.requiredSize(width = size.width.dp, height = size.height.dp)
+            val selected = item.key == selectedKey.value
+            val dpSize = DpSize(size.width.dp, size.height.dp)
+
             if (viewModel.isEditMode && dragDropState != null) {
-                val selected = item.key == selectedKey.value
-                DraggableItem(
+                val outlineAlpha by
+                    animateFloatAsState(
+                        targetValue = if (selected) 1f else 0f,
+                        animationSpec = spring(stiffness = Spring.StiffnessMediumLow),
+                        label = "Widget resizing outline alpha",
+                    )
+                ResizableItemFrameWrapper(
+                    key = item.key,
+                    gridState = gridState,
+                    minItemSpan = CommunalContentSize.HALF.span,
+                    gridContentPadding = contentPadding,
+                    verticalArrangement = itemArrangement,
+                    enabled = selected,
+                    alpha = { outlineAlpha },
                     modifier =
-                        if (dragDropState.draggingItemIndex == index) {
-                            Modifier
-                        } else {
+                        Modifier.requiredSize(dpSize).thenIf(
+                            dragDropState.draggingItemIndex != index
+                        ) {
                             Modifier.animateItem(
                                 placementSpec = spring(stiffness = Spring.StiffnessMediumLow)
                             )
                         },
-                    dragDropState = dragDropState,
-                    selected = selected,
-                    enabled = item.isWidgetContent(),
-                    index = index,
-                ) { isDragging ->
-                    CommunalContent(
-                        modifier = cardModifier,
-                        model = item,
-                        viewModel = viewModel,
-                        size = size,
-                        selected = selected && !isDragging,
-                        widgetConfigurator = widgetConfigurator,
+                    onResize = { resizeInfo -> contentListState.resize(index, resizeInfo) },
+                ) { modifier ->
+                    DraggableItem(
+                        modifier = modifier,
+                        dragDropState = dragDropState,
+                        selected = selected,
+                        enabled = item.isWidgetContent(),
                         index = index,
-                        contentListState = contentListState,
-                        interactionHandler = interactionHandler,
-                        widgetSection = widgetSection,
-                    )
+                    ) { isDragging ->
+                        CommunalContent(
+                            modifier = Modifier.fillMaxSize(),
+                            model = item,
+                            viewModel = viewModel,
+                            size = size,
+                            selected = selected && !isDragging,
+                            widgetConfigurator = widgetConfigurator,
+                            index = index,
+                            contentListState = contentListState,
+                            interactionHandler = interactionHandler,
+                            widgetSection = widgetSection,
+                        )
+                    }
                 }
             } else {
                 CommunalContent(
@@ -746,7 +800,7 @@
                     viewModel = viewModel,
                     size = size,
                     selected = false,
-                    modifier = cardModifier.animateItem(),
+                    modifier = Modifier.requiredSize(dpSize).animateItem(),
                     index = index,
                     contentListState = contentListState,
                     interactionHandler = interactionHandler,
@@ -762,7 +816,7 @@
  */
 @Composable
 private fun EmptyStateCta(contentPadding: PaddingValues, viewModel: BaseCommunalViewModel) {
-    val colors = LocalAndroidColorScheme.current
+    val colors = MaterialTheme.colorScheme
     Card(
         modifier = Modifier.height(hubDimensions.GridHeight).padding(contentPadding),
         colors = CardDefaults.cardColors(containerColor = Color.Transparent),
@@ -908,7 +962,7 @@
     modifier: Modifier = Modifier,
     content: @Composable RowScope.() -> Unit,
 ) {
-    val colors = LocalAndroidColorScheme.current
+    val colors = MaterialTheme.colorScheme
     AnimatedVisibility(
         visible = isPrimary,
         modifier = modifier,
@@ -955,7 +1009,7 @@
 
 @Composable
 private fun filledButtonColors(): ButtonColors {
-    val colors = LocalAndroidColorScheme.current
+    val colors = MaterialTheme.colorScheme
     return ButtonDefaults.buttonColors(
         containerColor = colors.primary,
         contentColor = colors.onPrimary,
@@ -1003,7 +1057,7 @@
 /** Creates an empty card used to highlight a particular spot on the grid. */
 @Composable
 fun HighlightedItem(modifier: Modifier = Modifier, alpha: Float = 1.0f) {
-    val brush = SolidColor(LocalAndroidColorScheme.current.primary)
+    val brush = SolidColor(MaterialTheme.colorScheme.primary)
     Box(
         modifier =
             // drawBehind lets us draw outside the bounds of the widgets so that we don't need to
@@ -1030,7 +1084,7 @@
     viewModel: BaseCommunalViewModel,
     modifier: Modifier = Modifier,
 ) {
-    val colors = LocalAndroidColorScheme.current
+    val colors = MaterialTheme.colorScheme
     Card(
         modifier = modifier,
         colors =
@@ -1246,7 +1300,7 @@
     modifier: Modifier = Modifier,
     widgetConfigurator: WidgetConfigurator,
 ) {
-    val colors = LocalAndroidColorScheme.current
+    val colors = MaterialTheme.colorScheme
     val scope = rememberCoroutineScope()
 
     AnimatedVisibility(
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/ContentListState.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/ContentListState.kt
index 1137357..6e30575 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/ContentListState.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/ContentListState.kt
@@ -21,8 +21,12 @@
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.remember
 import androidx.compose.runtime.toMutableStateList
+import com.android.systemui.Flags.communalWidgetResizing
 import com.android.systemui.communal.domain.model.CommunalContentModel
+import com.android.systemui.communal.shared.model.CommunalContentSize
 import com.android.systemui.communal.ui.viewmodel.BaseCommunalViewModel
+import com.android.systemui.communal.ui.viewmodel.DragHandle
+import com.android.systemui.communal.ui.viewmodel.ResizeInfo
 import com.android.systemui.communal.widgets.WidgetConfigurator
 
 @Composable
@@ -35,15 +39,11 @@
         ContentListState(
             communalContent,
             { componentName, user, rank ->
-                viewModel.onAddWidget(
-                    componentName,
-                    user,
-                    rank,
-                    widgetConfigurator,
-                )
+                viewModel.onAddWidget(componentName, user, rank, widgetConfigurator)
             },
             viewModel::onDeleteWidget,
             viewModel::onReorderWidgets,
+            viewModel::onResizeWidget,
         )
     }
 }
@@ -59,6 +59,7 @@
     private val onAddWidget: (componentName: ComponentName, user: UserHandle, rank: Int) -> Unit,
     private val onDeleteWidget: (id: Int, componentName: ComponentName, rank: Int) -> Unit,
     private val onReorderWidgets: (widgetIdToRankMap: Map<Int, Int>) -> Unit,
+    private val onResizeWidget: (id: Int, spanY: Int, widgetIdToRankMap: Map<Int, Int>) -> Unit,
 ) {
     var list = communalContent.toMutableStateList()
         private set
@@ -77,6 +78,36 @@
         }
     }
 
+    /** Resize a widget, possibly re-ordering widgets if needed. */
+    fun resize(index: Int, resizeInfo: ResizeInfo) {
+        val item = list[index]
+        val currentSpan = item.size.span
+        val newSpan = currentSpan + resizeInfo.spans
+        // Only widgets can be resized
+        if (
+            !communalWidgetResizing() ||
+                currentSpan == newSpan ||
+                item !is CommunalContentModel.WidgetContent.Widget
+        ) {
+            return
+        }
+        list[index] = item.copy(size = CommunalContentSize.toSize(newSpan))
+        val prevItem = list.getOrNull(index - 1)
+        // Check if we have to update indices of items to accommodate the resize.
+        val widgetIdToRankMap: Map<Int, Int> =
+            if (
+                resizeInfo.isExpanding &&
+                    resizeInfo.fromHandle == DragHandle.TOP &&
+                    prevItem is CommunalContentModel.WidgetContent.Widget
+            ) {
+                onMove(index - 1, index)
+                mapOf(prevItem.appWidgetId to index, item.appWidgetId to index - 1)
+            } else {
+                emptyMap()
+            }
+        onResizeWidget(item.appWidgetId, newSpan, widgetIdToRankMap)
+    }
+
     /**
      * Persists the new order with all the movements happened during drag operations & the new
      * widget drop (if applicable).
@@ -91,7 +122,7 @@
     fun onSaveList(
         newItemComponentName: ComponentName? = null,
         newItemUser: UserHandle? = null,
-        newItemIndex: Int? = null
+        newItemIndex: Int? = null,
     ) {
         // New widget added to the grid. Other widgets are shifted as needed at the database level.
         if (newItemComponentName != null && newItemUser != null && newItemIndex != null) {
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/EnableWidgetDialog.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/EnableWidgetDialog.kt
index df11206..b2407fa 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/EnableWidgetDialog.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/EnableWidgetDialog.kt
@@ -41,7 +41,6 @@
 import androidx.compose.ui.res.stringResource
 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.statusbar.phone.ComponentSystemUIDialog
 import com.android.systemui.statusbar.phone.SystemUIDialogFactory
@@ -93,7 +92,7 @@
     Box(
         Modifier.fillMaxWidth()
             .padding(top = 18.dp, bottom = 8.dp)
-            .background(LocalAndroidColorScheme.current.surfaceBright, RoundedCornerShape(28.dp))
+            .background(MaterialTheme.colorScheme.surfaceBright, RoundedCornerShape(28.dp))
     ) {
         Column(
             modifier = Modifier.fillMaxWidth(),
@@ -106,7 +105,7 @@
                 Text(
                     text = title,
                     style = MaterialTheme.typography.titleMedium,
-                    color = LocalAndroidColorScheme.current.onSurface,
+                    color = MaterialTheme.colorScheme.onSurface,
                     textAlign = TextAlign.Center,
                     maxLines = 1,
                 )
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/GridDragDropState.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/GridDragDropState.kt
index 20ee131..101385f 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/GridDragDropState.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/GridDragDropState.kt
@@ -42,6 +42,7 @@
 import androidx.compose.ui.unit.LayoutDirection
 import androidx.compose.ui.unit.toOffset
 import androidx.compose.ui.unit.toSize
+import com.android.systemui.Flags.communalWidgetResizing
 import com.android.systemui.communal.ui.compose.extensions.firstItemAtOffset
 import com.android.systemui.communal.ui.compose.extensions.plus
 import com.android.systemui.communal.ui.viewmodel.BaseCommunalViewModel
@@ -65,7 +66,7 @@
                 state = gridState,
                 contentListState = contentListState,
                 scope = scope,
-                updateDragPositionForRemove = updateDragPositionForRemove
+                updateDragPositionForRemove = updateDragPositionForRemove,
             )
         }
     LaunchedEffect(state) {
@@ -90,7 +91,7 @@
     private val state: LazyGridState,
     private val contentListState: ContentListState,
     private val scope: CoroutineScope,
-    private val updateDragPositionForRemove: (offset: Offset) -> Boolean
+    private val updateDragPositionForRemove: (offset: Offset) -> Boolean,
 ) {
     var draggingItemIndex by mutableStateOf<Int?>(null)
         private set
@@ -122,12 +123,12 @@
         offset: Offset,
         screenWidth: Int,
         layoutDirection: LayoutDirection,
-        contentOffset: Offset
+        contentOffset: Offset,
     ): Boolean {
         val normalizedOffset =
             Offset(
                 if (layoutDirection == LayoutDirection.Ltr) offset.x else screenWidth - offset.x,
-                offset.y
+                offset.y,
             )
         state.layoutInfo.visibleItemsInfo
             .filter { item -> contentListState.isItemEditable(item.index) }
@@ -248,7 +249,7 @@
                             offset,
                             screenWidth,
                             layoutDirection,
-                            contentOffset
+                            contentOffset,
                         )
                     ) {
                         viewModel.onReorderWidgetStart()
@@ -261,7 +262,7 @@
                 onDragCancel = {
                     dragDropState.onDragInterrupted()
                     viewModel.onReorderWidgetCancel()
-                }
+                },
             )
         }
     )
@@ -276,7 +277,7 @@
     enabled: Boolean,
     selected: Boolean,
     modifier: Modifier = Modifier,
-    content: @Composable (isDragging: Boolean) -> Unit
+    content: @Composable (isDragging: Boolean) -> Unit,
 ) {
     if (!enabled) {
         return content(false)
@@ -286,7 +287,7 @@
     val itemAlpha: Float by
         animateFloatAsState(
             targetValue = if (dragDropState.isDraggingToRemove) 0.5f else 1f,
-            label = "DraggableItemAlpha"
+            label = "DraggableItemAlpha",
         )
     val direction = LocalLayoutDirection.current
     val draggingModifier =
@@ -303,12 +304,17 @@
 
     // Animate the highlight alpha manually as alpha modifier (and AnimatedVisibility) clips the
     // widget to bounds, which cuts off the highlight as we are drawing outside the widget bounds.
+    val highlightSelected = !communalWidgetResizing() && selected
     val alpha by
         animateFloatAsState(
             targetValue =
-                if ((dragging || selected) && !dragDropState.isDraggingToRemove) 1f else 0f,
+                if ((dragging || highlightSelected) && !dragDropState.isDraggingToRemove) {
+                    1f
+                } else {
+                    0f
+                },
             animationSpec = spring(stiffness = Spring.StiffnessMediumLow),
-            label = "Widget outline alpha"
+            label = "Widget outline alpha",
         )
 
     Box(modifier) {
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/ResizeableItemFrame.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/ResizeableItemFrame.kt
index fda46b8..97ad4f1 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/ResizeableItemFrame.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/ResizeableItemFrame.kt
@@ -28,8 +28,11 @@
 import androidx.compose.foundation.layout.fillMaxWidth
 import androidx.compose.foundation.layout.height
 import androidx.compose.foundation.lazy.grid.LazyGridState
+import androidx.compose.material3.MaterialTheme
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.LaunchedEffect
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.rememberUpdatedState
 import androidx.compose.runtime.snapshotFlow
 import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
@@ -45,19 +48,17 @@
 import androidx.compose.ui.unit.Dp
 import androidx.compose.ui.unit.dp
 import androidx.compose.ui.util.fastIsFinite
-import com.android.compose.theme.LocalAndroidColorScheme
 import com.android.systemui.communal.ui.viewmodel.DragHandle
 import com.android.systemui.communal.ui.viewmodel.ResizeInfo
 import com.android.systemui.communal.ui.viewmodel.ResizeableItemFrameViewModel
 import com.android.systemui.lifecycle.rememberViewModel
 import kotlinx.coroutines.flow.collectLatest
 import kotlinx.coroutines.flow.combine
-import kotlinx.coroutines.flow.filterNotNull
 
 @Composable
 private fun UpdateGridLayoutInfo(
     viewModel: ResizeableItemFrameViewModel,
-    index: Int,
+    key: String,
     gridState: LazyGridState,
     minItemSpan: Int,
     gridContentPadding: PaddingValues,
@@ -67,7 +68,7 @@
     LaunchedEffect(
         density,
         viewModel,
-        index,
+        key,
         gridState,
         minItemSpan,
         gridContentPadding,
@@ -85,9 +86,8 @@
                 snapshotFlow { gridState.layoutInfo.maxSpan },
                 snapshotFlow { gridState.layoutInfo.viewportSize.height },
                 snapshotFlow {
-                        gridState.layoutInfo.visibleItemsInfo.firstOrNull { it.index == index }
-                    }
-                    .filterNotNull(),
+                    gridState.layoutInfo.visibleItemsInfo.firstOrNull { it.key == key }
+                },
                 ::Triple,
             )
             .collectLatest { (maxItemSpan, viewportHeightPx, itemInfo) ->
@@ -97,8 +97,8 @@
                     viewportHeightPx,
                     maxItemSpan,
                     minItemSpan,
-                    itemInfo.row,
-                    itemInfo.span,
+                    itemInfo?.row,
+                    itemInfo?.span,
                 )
             }
     }
@@ -161,7 +161,7 @@
  */
 @Composable
 fun ResizableItemFrame(
-    index: Int,
+    key: String,
     gridState: LazyGridState,
     minItemSpan: Int,
     gridContentPadding: PaddingValues,
@@ -169,7 +169,7 @@
     modifier: Modifier = Modifier,
     enabled: Boolean = true,
     outlinePadding: Dp = 8.dp,
-    outlineColor: Color = LocalAndroidColorScheme.current.primary,
+    outlineColor: Color = MaterialTheme.colorScheme.primary,
     cornerRadius: Dp = 37.dp,
     strokeWidth: Dp = 3.dp,
     alpha: () -> Float = { 1f },
@@ -177,6 +177,7 @@
     content: @Composable () -> Unit,
 ) {
     val brush = SolidColor(outlineColor)
+    val onResizeUpdated by rememberUpdatedState(onResize)
     val viewModel =
         rememberViewModel(traceName = "ResizeableItemFrame.viewModel") {
             ResizeableItemFrameViewModel()
@@ -230,13 +231,15 @@
 
             UpdateGridLayoutInfo(
                 viewModel,
-                index,
+                key,
                 gridState,
                 minItemSpan,
                 gridContentPadding,
                 verticalArrangement,
             )
-            LaunchedEffect(viewModel) { viewModel.resizeInfo.collectLatest(onResize) }
+            LaunchedEffect(viewModel) {
+                viewModel.resizeInfo.collectLatest { info -> onResizeUpdated(info) }
+            }
         }
     }
 }
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/section/CommunalPopupSection.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/section/CommunalPopupSection.kt
index b4c1a2e..868e136 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/section/CommunalPopupSection.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/section/CommunalPopupSection.kt
@@ -55,7 +55,6 @@
 import androidx.compose.ui.unit.dp
 import androidx.compose.ui.window.Popup
 import androidx.lifecycle.compose.collectAsStateWithLifecycle
-import com.android.compose.theme.LocalAndroidColorScheme
 import com.android.systemui.communal.ui.viewmodel.CommunalViewModel
 import com.android.systemui.communal.ui.viewmodel.PopupType
 import com.android.systemui.res.R
@@ -112,7 +111,7 @@
             offset = IntOffset(0, 40),
             onDismissRequest = onDismissRequest,
         ) {
-            val colors = LocalAndroidColorScheme.current
+            val colors = MaterialTheme.colorScheme
             Button(
                 modifier =
                     Modifier.height(56.dp)
@@ -182,7 +181,7 @@
             offset = IntOffset(0, 40),
             onDismissRequest = onDismissRequest
         ) {
-            val colors = LocalAndroidColorScheme.current
+            val colors = MaterialTheme.colorScheme
             Row(
                 modifier =
                     Modifier.height(56.dp)
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/TopAreaSection.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/TopAreaSection.kt
index 97d89a2..afa92f2 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/TopAreaSection.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/TopAreaSection.kt
@@ -83,11 +83,7 @@
             }
 
         val state = remember {
-            MutableSceneTransitionLayoutState(
-                currentScene,
-                ClockTransition.defaultClockTransitions,
-                enableInterruptions = false,
-            )
+            MutableSceneTransitionLayoutState(currentScene, ClockTransition.defaultClockTransitions)
         }
 
         // Update state whenever currentSceneKey has changed.
@@ -102,7 +98,7 @@
                 scene(splitShadeLargeClockScene) {
                     LargeClockWithSmartSpace(
                         smartSpacePaddingTop = smartSpacePaddingTop,
-                        shouldOffSetClockToOneHalf = !hasCustomPositionUpdatedAnimation
+                        shouldOffSetClockToOneHalf = !hasCustomPositionUpdatedAnimation,
                     )
                 }
 
@@ -114,21 +110,15 @@
                 }
 
                 scene(smallClockScene) {
-                    SmallClockWithSmartSpace(
-                        smartSpacePaddingTop = smartSpacePaddingTop,
-                    )
+                    SmallClockWithSmartSpace(smartSpacePaddingTop = smartSpacePaddingTop)
                 }
 
                 scene(largeClockScene) {
-                    LargeClockWithSmartSpace(
-                        smartSpacePaddingTop = smartSpacePaddingTop,
-                    )
+                    LargeClockWithSmartSpace(smartSpacePaddingTop = smartSpacePaddingTop)
                 }
 
                 scene(WeatherClockScenes.largeClockScene) {
-                    WeatherLargeClockWithSmartSpace(
-                        smartSpacePaddingTop = smartSpacePaddingTop,
-                    )
+                    WeatherLargeClockWithSmartSpace(smartSpacePaddingTop = smartSpacePaddingTop)
                 }
 
                 scene(WeatherClockScenes.splitShadeLargeClockScene) {
@@ -154,7 +144,7 @@
                 SmallClock(
                     burnInParams = burnIn.parameters,
                     onTopChanged = burnIn.onSmallClockTopChanged,
-                    modifier = Modifier.wrapContentSize()
+                    modifier = Modifier.wrapContentSize(),
                 )
             }
             with(smartSpaceSection) {
@@ -202,7 +192,7 @@
                                     y = 0,
                                 )
                             }
-                        }
+                        },
                 )
             }
         }
@@ -226,10 +216,7 @@
         Column(modifier = modifier) {
             val currentClock = currentClockState.value ?: return@Column
             with(weatherClockSection) {
-                Time(
-                    clock = currentClock,
-                    burnInParams = burnIn.parameters,
-                )
+                Time(clock = currentClock, burnInParams = burnIn.parameters)
             }
             val density = LocalDensity.current
             val context = LocalContext.current
@@ -242,7 +229,7 @@
                     modifier =
                         Modifier.heightIn(
                             min = getDimen(context, "enhanced_smartspace_height", density)
-                        )
+                        ),
                 )
             }
             with(weatherClockSection) {
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/media/controls/ui/composable/MediaCarousel.kt b/packages/SystemUI/compose/features/src/com/android/systemui/media/controls/ui/composable/MediaCarousel.kt
index 3d8ca1e..b5d7839 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/media/controls/ui/composable/MediaCarousel.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/media/controls/ui/composable/MediaCarousel.kt
@@ -34,7 +34,6 @@
 import com.android.compose.animation.scene.MovableElementKey
 import com.android.compose.animation.scene.SceneScope
 import com.android.compose.windowsizeclass.LocalWindowSizeClass
-import com.android.internal.R.attr.layout
 import com.android.systemui.media.controls.ui.composable.MediaCarouselStateLoader.stateForMediaCarouselContent
 import com.android.systemui.media.controls.ui.controller.MediaCarouselController
 import com.android.systemui.media.controls.ui.view.MediaHost
@@ -60,12 +59,12 @@
     carouselController: MediaCarouselController,
     offsetProvider: (() -> IntOffset)? = null,
     usingCollapsedLandscapeMedia: Boolean = false,
+    isInSplitShade: Boolean = false,
 ) {
     if (!isVisible || carouselController.isLockedAndHidden()) {
         return
     }
-
-    val carouselState = remember { { stateForMediaCarouselContent() } }
+    val carouselState = remember { { stateForMediaCarouselContent(isInSplitShade) } }
     val isCollapsed = usingCollapsedLandscapeMedia && isLandscape()
     val mediaHeight =
         if (isCollapsed && mediaHost.expansion == MediaHostState.COLLAPSED) {
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/media/controls/ui/composable/MediaCarouselStateLoader.kt b/packages/SystemUI/compose/features/src/com/android/systemui/media/controls/ui/composable/MediaCarouselStateLoader.kt
index 4a0136c..bad7405 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/media/controls/ui/composable/MediaCarouselStateLoader.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/media/controls/ui/composable/MediaCarouselStateLoader.kt
@@ -43,10 +43,13 @@
 
     /** Returns the corresponding media location for the given [scene] */
     @MediaLocation
-    private fun getMediaLocation(scene: SceneKey): Int {
+    private fun getMediaLocation(scene: SceneKey, isSplitShade: Boolean): Int {
         return when (scene) {
             Scenes.QuickSettings -> MediaHierarchyManager.LOCATION_QS
-            Scenes.Shade -> MediaHierarchyManager.LOCATION_QQS
+            Scenes.Shade -> {
+                if (isSplitShade) MediaHierarchyManager.LOCATION_QS
+                else MediaHierarchyManager.LOCATION_QQS
+            }
             Scenes.Lockscreen -> MediaHierarchyManager.LOCATION_LOCKSCREEN
             Scenes.Communal -> MediaHierarchyManager.LOCATION_COMMUNAL_HUB
             else -> MediaHierarchyManager.LOCATION_UNKNOWN
@@ -97,11 +100,11 @@
     }
 
     /** Returns the state of media carousel */
-    fun SceneScope.stateForMediaCarouselContent(): State {
+    fun SceneScope.stateForMediaCarouselContent(isInSplitShade: Boolean): State {
         return when (val transitionState = layoutState.transitionState) {
             is TransitionState.Idle -> {
                 if (MediaContentPicker.contents.contains(transitionState.currentScene)) {
-                    State.Idle(getMediaLocation(transitionState.currentScene))
+                    State.Idle(getMediaLocation(transitionState.currentScene, isInSplitShade))
                 } else {
                     State.Gone
                 }
@@ -114,14 +117,14 @@
                     ) {
                         State.InProgress(
                             min(progress, 1.0F),
-                            getMediaLocation(fromScene),
-                            getMediaLocation(toScene),
+                            getMediaLocation(fromScene, isInSplitShade),
+                            getMediaLocation(toScene, isInSplitShade),
                         )
                     } else if (MediaContentPicker.contents.contains(toScene)) {
                         State.InProgress(
                             transitionProgress = 1.0F,
                             startLocation = MediaHierarchyManager.LOCATION_UNKNOWN,
-                            getMediaLocation(toScene),
+                            getMediaLocation(toScene, isInSplitShade),
                         )
                     } else {
                         State.Gone
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 b808044..4f1acdc 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
@@ -46,7 +46,7 @@
 import androidx.compose.ui.text.style.TextAlign
 import androidx.compose.ui.unit.dp
 import androidx.lifecycle.compose.collectAsStateWithLifecycle
-import com.android.compose.theme.LocalAndroidColorScheme
+import com.android.compose.theme.colorAttr
 import com.android.systemui.compose.modifiers.sysuiResTag
 import com.android.systemui.people.ui.viewmodel.PeopleTileViewModel
 import com.android.systemui.people.ui.viewmodel.PeopleViewModel
@@ -60,10 +60,7 @@
  *   the Activity/Fragment/View hosting this Composable once a result is available.
  */
 @Composable
-fun PeopleScreen(
-    viewModel: PeopleViewModel,
-    onResult: (PeopleViewModel.Result) -> Unit,
-) {
+fun PeopleScreen(viewModel: PeopleViewModel, onResult: (PeopleViewModel.Result) -> Unit) {
     val priorityTiles by viewModel.priorityTiles.collectAsStateWithLifecycle()
     val recentTiles by viewModel.recentTiles.collectAsStateWithLifecycle()
 
@@ -79,10 +76,9 @@
 
     // Make sure to use the Android colors and not the default Material3 colors to have the exact
     // same colors as the View implementation.
-    val androidColors = LocalAndroidColorScheme.current.deprecated
     Surface(
-        color = androidColors.colorBackground,
-        contentColor = androidColors.textColorPrimary,
+        color = colorAttr(com.android.internal.R.attr.colorBackground),
+        contentColor = colorAttr(com.android.internal.R.attr.textColorPrimary),
         modifier = Modifier.fillMaxSize(),
     ) {
         if (priorityTiles.isNotEmpty() || recentTiles.isNotEmpty()) {
@@ -99,9 +95,7 @@
     recentTiles: List<PeopleTileViewModel>,
     onTileClicked: (PeopleTileViewModel) -> Unit,
 ) {
-    Column(
-        Modifier.sysuiResTag("top_level_with_conversations"),
-    ) {
+    Column(Modifier.sysuiResTag("top_level_with_conversations")) {
         Column(
             Modifier.fillMaxWidth().padding(PeopleSpacePadding),
             horizontalAlignment = Alignment.CenterHorizontally,
@@ -126,12 +120,7 @@
             Modifier.fillMaxWidth()
                 .sysuiResTag("scroll_view")
                 .verticalScroll(rememberScrollState())
-                .padding(
-                    top = 16.dp,
-                    bottom = PeopleSpacePadding,
-                    start = 8.dp,
-                    end = 8.dp,
-                ),
+                .padding(top = 16.dp, bottom = PeopleSpacePadding, start = 8.dp, end = 8.dp)
         ) {
             val hasPriorityConversations = priorityTiles.isNotEmpty()
             if (hasPriorityConversations) {
@@ -153,13 +142,13 @@
 private fun ConversationList(
     @StringRes headerTextResource: Int,
     tiles: List<PeopleTileViewModel>,
-    onTileClicked: (PeopleTileViewModel) -> Unit
+    onTileClicked: (PeopleTileViewModel) -> Unit,
 ) {
     Text(
         stringResource(headerTextResource),
         Modifier.padding(start = 16.dp),
         style = MaterialTheme.typography.labelLarge,
-        color = LocalAndroidColorScheme.current.deprecated.colorAccentPrimaryVariant,
+        color = colorAttr(com.android.internal.R.attr.colorAccentPrimaryVariant),
     )
 
     Spacer(Modifier.height(10.dp))
@@ -167,7 +156,7 @@
     tiles.forEachIndexed { index, tile ->
         if (index > 0) {
             Divider(
-                color = LocalAndroidColorScheme.current.deprecated.colorBackground,
+                color = colorAttr(com.android.internal.R.attr.colorBackground),
                 thickness = 2.dp,
             )
         }
@@ -190,14 +179,13 @@
     withTopCornerRadius: Boolean,
     withBottomCornerRadius: Boolean,
 ) {
-    val androidColors = LocalAndroidColorScheme.current.deprecated
     val cornerRadius = dimensionResource(R.dimen.people_space_widget_radius)
     val topCornerRadius = if (withTopCornerRadius) cornerRadius else 0.dp
     val bottomCornerRadius = if (withBottomCornerRadius) cornerRadius else 0.dp
 
     Surface(
-        color = androidColors.colorSurface,
-        contentColor = androidColors.textColorPrimary,
+        color = colorAttr(com.android.internal.R.attr.colorSurface),
+        contentColor = colorAttr(com.android.internal.R.attr.textColorPrimary),
         shape =
             RoundedCornerShape(
                 topStart = topCornerRadius,
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/people/ui/compose/PeopleScreenEmpty.kt b/packages/SystemUI/compose/features/src/com/android/systemui/people/ui/compose/PeopleScreenEmpty.kt
index 26cc9b9..d483f88 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/people/ui/compose/PeopleScreenEmpty.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/people/ui/compose/PeopleScreenEmpty.kt
@@ -41,13 +41,11 @@
 import androidx.compose.ui.text.style.TextAlign
 import androidx.compose.ui.text.style.TextOverflow
 import androidx.compose.ui.unit.dp
-import com.android.compose.theme.LocalAndroidColorScheme
+import com.android.compose.theme.colorAttr
 import com.android.systemui.res.R
 
 @Composable
-internal fun PeopleScreenEmpty(
-    onGotItClicked: () -> Unit,
-) {
+internal fun PeopleScreenEmpty(onGotItClicked: () -> Unit) {
     Column(
         Modifier.fillMaxSize().padding(PeopleSpacePadding),
         horizontalAlignment = Alignment.CenterHorizontally,
@@ -70,15 +68,14 @@
         ExampleTile()
         Spacer(Modifier.weight(1f))
 
-        val androidColors = LocalAndroidColorScheme.current
         Button(
             onGotItClicked,
             Modifier.fillMaxWidth().defaultMinSize(minHeight = 56.dp),
             colors =
                 ButtonDefaults.buttonColors(
-                    containerColor = androidColors.deprecated.colorAccentPrimary,
-                    contentColor = androidColors.deprecated.textColorOnAccent,
-                )
+                    containerColor = colorAttr(com.android.internal.R.attr.colorAccentPrimary),
+                    contentColor = colorAttr(com.android.internal.R.attr.textColorOnAccent),
+                ),
         ) {
             Text(stringResource(R.string.got_it))
         }
@@ -87,11 +84,10 @@
 
 @Composable
 private fun ExampleTile() {
-    val androidColors = LocalAndroidColorScheme.current
     Surface(
         shape = RoundedCornerShape(28.dp),
-        color = androidColors.deprecated.colorSurface,
-        contentColor = androidColors.deprecated.textColorPrimary,
+        color = colorAttr(com.android.internal.R.attr.colorSurface),
+        contentColor = colorAttr(com.android.internal.R.attr.textColorPrimary),
     ) {
         Row(
             Modifier.padding(vertical = 20.dp, horizontal = 16.dp),
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/qs/footer/ui/compose/FooterActions.kt b/packages/SystemUI/compose/features/src/com/android/systemui/qs/footer/ui/compose/FooterActions.kt
index e8da4bd..e382e16 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/qs/footer/ui/compose/FooterActions.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/qs/footer/ui/compose/FooterActions.kt
@@ -73,7 +73,6 @@
 import com.android.compose.animation.Expandable
 import com.android.compose.animation.scene.SceneScope
 import com.android.compose.modifiers.background
-import com.android.compose.theme.LocalAndroidColorScheme
 import com.android.compose.theme.colorAttr
 import com.android.systemui.animation.Expandable
 import com.android.systemui.common.shared.model.Icon
@@ -163,7 +162,7 @@
     }
 
     val backgroundColor = colorAttr(R.attr.underSurface)
-    val contentColor = LocalAndroidColorScheme.current.onSurface
+    val contentColor = MaterialTheme.colorScheme.onSurface
     val backgroundTopRadius = dimensionResource(R.dimen.qs_corner_radius)
     val backgroundModifier =
         remember(
@@ -344,7 +343,7 @@
 @Composable
 private fun NewChangesDot(modifier: Modifier = Modifier) {
     val contentDescription = stringResource(R.string.fgs_dot_content_description)
-    val color = LocalAndroidColorScheme.current.tertiary
+    val color = MaterialTheme.colorScheme.tertiary
 
     Canvas(modifier.size(12.dp).semantics { this.contentDescription = contentDescription }) {
         drawCircle(color)
@@ -363,7 +362,7 @@
     Expandable(
         shape = CircleShape,
         color = colorAttr(R.attr.underSurface),
-        contentColor = LocalAndroidColorScheme.current.onSurfaceVariant,
+        contentColor = MaterialTheme.colorScheme.onSurfaceVariant,
         borderStroke = BorderStroke(1.dp, colorAttr(R.attr.shadeInactive)),
         modifier = modifier.padding(horizontal = 4.dp),
         onClick = onClick,
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettings.kt b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettings.kt
index e9c5c03..58801e0 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettings.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettings.kt
@@ -24,7 +24,9 @@
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.DisposableEffect
 import androidx.compose.runtime.LaunchedEffect
+import androidx.compose.runtime.derivedStateOf
 import androidx.compose.runtime.getValue
+import androidx.compose.runtime.remember
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.draw.drawWithContent
 import androidx.compose.ui.layout.layout
@@ -38,6 +40,7 @@
 import com.android.compose.animation.scene.MovableElementContentPicker
 import com.android.compose.animation.scene.MovableElementKey
 import com.android.compose.animation.scene.SceneScope
+import com.android.compose.animation.scene.SceneTransitionLayoutState
 import com.android.compose.animation.scene.ValueKey
 import com.android.compose.animation.scene.content.state.TransitionState
 import com.android.compose.modifiers.thenIf
@@ -158,12 +161,10 @@
     squishiness: () -> Float = { QuickSettings.SharedValues.SquishinessValues.Default },
 ) {
     val contentState = { stateForQuickSettingsContent(isSplitShade, squishiness) }
-    val transitionState = layoutState.transitionState
-    val isClosing =
-        transitionState is TransitionState.Transition &&
-            transitionState.progress >= 0.9f && // almost done closing
-            !(layoutState.isTransitioning(to = Scenes.Shade) ||
-                layoutState.isTransitioning(to = Scenes.QuickSettings))
+
+    // Note: We use derivedStateOf {} here because isClosing() is reading the current transition
+    // progress and we don't want to recompose this scene each time the progress has changed.
+    val isClosing by remember(layoutState) { derivedStateOf { isClosing(layoutState) } }
 
     if (isClosing) {
         DisposableEffect(Unit) {
@@ -188,6 +189,14 @@
     }
 }
 
+private fun isClosing(layoutState: SceneTransitionLayoutState): Boolean {
+    val transitionState = layoutState.transitionState
+    return transitionState is TransitionState.Transition &&
+        !(layoutState.isTransitioning(to = Scenes.Shade) ||
+            layoutState.isTransitioning(to = Scenes.QuickSettings)) &&
+        transitionState.progress >= 0.9f // almost done closing
+}
+
 @Composable
 private fun QuickSettingsContent(
     qsSceneAdapter: QSSceneAdapter,
@@ -199,7 +208,7 @@
     QuickSettingsTheme {
         val context = LocalContext.current
 
-        LaunchedEffect(key1 = context) {
+        LaunchedEffect(context) {
             if (qsView == null) {
                 qsSceneAdapter.inflate(context)
             }
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 56de096..2d58c8c 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
@@ -24,6 +24,7 @@
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.DisposableEffect
 import androidx.compose.runtime.LaunchedEffect
+import androidx.compose.runtime.getValue
 import androidx.compose.runtime.mutableStateMapOf
 import androidx.compose.runtime.remember
 import androidx.compose.runtime.rememberCoroutineScope
@@ -31,6 +32,8 @@
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.input.pointer.pointerInput
+import androidx.compose.ui.platform.LocalContext
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
 import com.android.compose.animation.scene.ContentKey
 import com.android.compose.animation.scene.MutableSceneTransitionLayoutState
 import com.android.compose.animation.scene.OverlayKey
@@ -39,9 +42,13 @@
 import com.android.compose.animation.scene.UserAction
 import com.android.compose.animation.scene.UserActionResult
 import com.android.compose.animation.scene.observableTransitionState
+import com.android.systemui.qs.ui.adapter.QSSceneAdapter
+import com.android.systemui.qs.ui.composable.QuickSettingsTheme
 import com.android.systemui.ribbon.ui.composable.BottomRightCornerRibbon
 import com.android.systemui.scene.shared.model.SceneDataSourceDelegator
+import com.android.systemui.scene.shared.model.Scenes
 import com.android.systemui.scene.ui.viewmodel.SceneContainerViewModel
+import javax.inject.Provider
 import kotlinx.coroutines.flow.collectLatest
 
 /**
@@ -73,6 +80,7 @@
     overlayByKey: Map<OverlayKey, Overlay>,
     initialSceneKey: SceneKey,
     dataSourceDelegator: SceneDataSourceDelegator,
+    qsSceneAdapter: Provider<QSSceneAdapter>,
     modifier: Modifier = Modifier,
 ) {
     val coroutineScope = rememberCoroutineScope()
@@ -81,7 +89,6 @@
             initialScene = initialSceneKey,
             canChangeScene = { toScene -> viewModel.canChangeScene(toScene) },
             transitions = SceneContainerTransitions,
-            enableInterruptions = false,
         )
     }
 
@@ -119,6 +126,24 @@
         }
     }
 
+    // Inflate qsView here so that shade has the correct qqs height in the first measure pass after
+    // rebooting
+    if (
+        viewModel.allContentKeys.contains(Scenes.QuickSettings) ||
+            viewModel.allContentKeys.contains(Scenes.Shade)
+    ) {
+        val qsAdapter = qsSceneAdapter.get()
+        QuickSettingsTheme {
+            val context = LocalContext.current
+            val qsView by qsAdapter.qsView.collectAsStateWithLifecycle()
+            LaunchedEffect(context) {
+                if (qsView == null) {
+                    qsAdapter.inflate(context)
+                }
+            }
+        }
+    }
+
     Box(
         modifier =
             Modifier.fillMaxSize().pointerInput(Unit) {
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainerInterruptionHandler.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainerInterruptionHandler.kt
new file mode 100644
index 0000000..7e99847
--- /dev/null
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainerInterruptionHandler.kt
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.scene.ui.composable
+
+import com.android.compose.animation.scene.InterruptionHandler
+import com.android.compose.animation.scene.InterruptionResult
+import com.android.compose.animation.scene.SceneKey
+import com.android.compose.animation.scene.content.state.TransitionState
+import com.android.systemui.scene.shared.model.Scenes
+import com.android.systemui.scene.ui.composable.transitions.TO_BOUNCER_FADE_FRACTION
+
+object SceneContainerInterruptionHandler : InterruptionHandler {
+    override fun onInterruption(
+        interrupted: TransitionState.Transition.ChangeScene,
+        newTargetScene: SceneKey,
+    ): InterruptionResult? {
+        return handleTransitionToGoneDuringTransitionToBouncer(interrupted, newTargetScene)
+    }
+
+    /**
+     * Handle the case where we start transitioning to Bouncer but then we are interrupted to
+     * transition to Gone, for instance because face auth kicked in.
+     */
+    private fun handleTransitionToGoneDuringTransitionToBouncer(
+        transition: TransitionState.Transition.ChangeScene,
+        targetScene: SceneKey,
+    ): InterruptionResult? {
+        if (targetScene != Scenes.Gone || !transition.isTransitioningFromOrTo(Scenes.Bouncer)) {
+            return null
+        }
+
+        // Animate Bouncer => Gone only when the bouncer is fully opaque, otherwise animate
+        // OtherScene => Gone and reverse the OtherScene => Bouncer transition (note: OtherScene is
+        // usually the Lockscreen scene).
+        val otherScene: SceneKey
+        val animatesFromBouncer =
+            if (transition.isTransitioning(to = Scenes.Bouncer)) {
+                otherScene = transition.fromScene
+                transition.progress >= TO_BOUNCER_FADE_FRACTION
+            } else {
+                otherScene = transition.toScene
+                transition.progress <= 1f - TO_BOUNCER_FADE_FRACTION
+            }
+
+        return if (animatesFromBouncer) {
+            InterruptionResult(
+                animateFrom = Scenes.Bouncer,
+
+                // We don't want the content of the lockscreen to be shown during the Bouncer =>
+                // Launcher transition. We disable chaining of the transitions so that only the
+                // Bouncer and Launcher scenes are composed.
+                chain = false,
+            )
+        } else {
+            InterruptionResult(animateFrom = otherScene)
+        }
+    }
+}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainerTransitions.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainerTransitions.kt
index 8728521..dc545b8 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainerTransitions.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainerTransitions.kt
@@ -46,6 +46,7 @@
  * Please keep the list sorted alphabetically.
  */
 val SceneContainerTransitions = transitions {
+    interruptionHandler = SceneContainerInterruptionHandler
 
     // Overscroll progress starts linearly with some resistance (3f) and slowly approaches 0.2f
     defaultOverscrollProgressConverter = ProgressConverter.tanh(maxProgress = 0.2f, tilt = 3f)
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromLockscreenToBouncerTransition.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromLockscreenToBouncerTransition.kt
index dd37b53..cdf8d00 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromLockscreenToBouncerTransition.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromLockscreenToBouncerTransition.kt
@@ -1,6 +1,6 @@
 package com.android.systemui.scene.ui.composable.transitions
 
-import androidx.compose.animation.core.CubicBezierEasing
+import com.android.compose.animation.Easings
 import com.android.compose.animation.scene.TransitionBuilder
 import com.android.systemui.bouncer.ui.composable.Bouncer
 
@@ -9,7 +9,7 @@
 }
 
 fun TransitionBuilder.bouncerToLockscreenPreview() {
-    fractionRange(easing = CubicBezierEasing(0.1f, 0.1f, 0f, 1f)) {
+    fractionRange(easing = Easings.PredictiveBack) {
         scaleDraw(Bouncer.Elements.Content, scaleY = 0.8f, scaleX = 0.8f)
     }
 }
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt
index 3ec057b..491221f 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt
@@ -361,6 +361,7 @@
                     carouselController = mediaCarouselController,
                     modifier = Modifier.layoutId(SingleShadeMeasurePolicy.LayoutId.Media),
                     usingCollapsedLandscapeMedia = usingCollapsedLandscapeMedia,
+                    isInSplitShade = false,
                 )
 
                 NotificationScrollingStack(
@@ -565,6 +566,7 @@
                                         Modifier.zIndex(1f)
                                     },
                                 carouselController = mediaCarouselController,
+                                isInSplitShade = true,
                             )
                         }
                         FooterActionsWithAnimatedVisibility(
@@ -619,6 +621,7 @@
     mediaOffsetProvider: ShadeMediaOffsetProvider,
     modifier: Modifier = Modifier,
     usingCollapsedLandscapeMedia: Boolean = false,
+    isInSplitShade: Boolean,
 ) {
     MediaCarousel(
         modifier = modifier.fillMaxWidth(),
@@ -632,5 +635,6 @@
                 { mediaOffsetProvider.offset }
             },
         usingCollapsedLandscapeMedia = usingCollapsedLandscapeMedia,
+        isInSplitShade = isInSplitShade,
     )
 }
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/MultiPointerDraggable.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/MultiPointerDraggable.kt
index dc3135d..aa70a0c 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/MultiPointerDraggable.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/MultiPointerDraggable.kt
@@ -42,10 +42,8 @@
 import androidx.compose.ui.node.CompositionLocalConsumerModifierNode
 import androidx.compose.ui.node.DelegatingNode
 import androidx.compose.ui.node.ModifierNodeElement
-import androidx.compose.ui.node.ObserverModifierNode
 import androidx.compose.ui.node.PointerInputModifierNode
 import androidx.compose.ui.node.currentValueOf
-import androidx.compose.ui.node.observeReads
 import androidx.compose.ui.platform.LocalViewConfiguration
 import androidx.compose.ui.unit.IntSize
 import androidx.compose.ui.unit.Velocity
@@ -79,7 +77,6 @@
 @Stable
 internal fun Modifier.multiPointerDraggable(
     orientation: Orientation,
-    enabled: () -> Boolean,
     startDragImmediately: (startedPosition: Offset) -> Boolean,
     onDragStarted: (startedPosition: Offset, overSlop: Float, pointersDown: Int) -> DragController,
     onFirstPointerDown: () -> Unit = {},
@@ -89,7 +86,6 @@
     this.then(
         MultiPointerDraggableElement(
             orientation,
-            enabled,
             startDragImmediately,
             onDragStarted,
             onFirstPointerDown,
@@ -100,7 +96,6 @@
 
 private data class MultiPointerDraggableElement(
     private val orientation: Orientation,
-    private val enabled: () -> Boolean,
     private val startDragImmediately: (startedPosition: Offset) -> Boolean,
     private val onDragStarted:
         (startedPosition: Offset, overSlop: Float, pointersDown: Int) -> DragController,
@@ -111,7 +106,6 @@
     override fun create(): MultiPointerDraggableNode =
         MultiPointerDraggableNode(
             orientation = orientation,
-            enabled = enabled,
             startDragImmediately = startDragImmediately,
             onDragStarted = onDragStarted,
             onFirstPointerDown = onFirstPointerDown,
@@ -121,7 +115,6 @@
 
     override fun update(node: MultiPointerDraggableNode) {
         node.orientation = orientation
-        node.enabled = enabled
         node.startDragImmediately = startDragImmediately
         node.onDragStarted = onDragStarted
         node.onFirstPointerDown = onFirstPointerDown
@@ -131,27 +124,23 @@
 
 internal class MultiPointerDraggableNode(
     orientation: Orientation,
-    enabled: () -> Boolean,
     var startDragImmediately: (startedPosition: Offset) -> Boolean,
     var onDragStarted:
         (startedPosition: Offset, overSlop: Float, pointersDown: Int) -> DragController,
     var onFirstPointerDown: () -> Unit,
-    var swipeDetector: SwipeDetector = DefaultSwipeDetector,
+    swipeDetector: SwipeDetector = DefaultSwipeDetector,
     private val dispatcher: NestedScrollDispatcher,
 ) :
     DelegatingNode(),
     PointerInputModifierNode,
     CompositionLocalConsumerModifierNode,
-    ObserverModifierNode,
     SpaceVectorConverter {
     private val pointerTracker = delegate(SuspendingPointerInputModifierNode { pointerTracker() })
     private val pointerInput = delegate(SuspendingPointerInputModifierNode { pointerInput() })
     private val velocityTracker = VelocityTracker()
-    private var previousEnabled: Boolean = false
 
-    var enabled: () -> Boolean = enabled
+    var swipeDetector: SwipeDetector = swipeDetector
         set(value) {
-            // Reset the pointer input whenever enabled changed.
             if (value != field) {
                 field = value
                 pointerInput.resetPointerInputHandler()
@@ -178,21 +167,6 @@
             }
         }
 
-    override fun onAttach() {
-        previousEnabled = enabled()
-        onObservedReadsChanged()
-    }
-
-    override fun onObservedReadsChanged() {
-        observeReads {
-            val newEnabled = enabled()
-            if (newEnabled != previousEnabled) {
-                pointerInput.resetPointerInputHandler()
-            }
-            previousEnabled = newEnabled
-        }
-    }
-
     override fun onCancelPointerInput() {
         pointerTracker.onCancelPointerInput()
         pointerInput.onCancelPointerInput()
@@ -254,9 +228,7 @@
                         velocityTracker.resetTracking()
                         velocityTracker.addPointerInputChange(firstPointerDown)
                         startedPosition = firstPointerDown.position
-                        if (enabled()) {
-                            onFirstPointerDown()
-                        }
+                        onFirstPointerDown()
                     }
 
                     // Changes with at least one pointer
@@ -295,10 +267,6 @@
     }
 
     private suspend fun PointerInputScope.pointerInput() {
-        if (!enabled()) {
-            return
-        }
-
         val currentContext = currentCoroutineContext()
         awaitPointerEventScope {
             while (currentContext.isActive) {
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt
index 2e8fc14..2657d7c 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt
@@ -234,7 +234,6 @@
     canHideOverlay: (OverlayKey) -> Boolean = { true },
     canReplaceOverlay: (from: OverlayKey, to: OverlayKey) -> Boolean = { _, _ -> true },
     stateLinks: List<StateLink> = emptyList(),
-    enableInterruptions: Boolean = DEFAULT_INTERRUPTIONS_ENABLED,
 ): MutableSceneTransitionLayoutState {
     return MutableSceneTransitionLayoutStateImpl(
         initialScene,
@@ -245,7 +244,6 @@
         canHideOverlay,
         canReplaceOverlay,
         stateLinks,
-        enableInterruptions,
     )
 }
 
@@ -261,9 +259,6 @@
         true
     },
     private val stateLinks: List<StateLink> = emptyList(),
-
-    // TODO(b/290930950): Remove this flag.
-    internal val enableInterruptions: Boolean = DEFAULT_INTERRUPTIONS_ENABLED,
 ) : MutableSceneTransitionLayoutState {
     private val creationThread: Thread = Thread.currentThread()
 
@@ -406,13 +401,6 @@
             transition.updateOverscrollSpecs(fromSpec = null, toSpec = null)
         }
 
-        if (!enableInterruptions) {
-            // Set the current transition.
-            check(transitionStates.size == 1)
-            transitionStates = listOf(transition)
-            return
-        }
-
         when (val currentState = transitionStates.last()) {
             is TransitionState.Idle -> {
                 // Replace [Idle] by [transition].
@@ -755,9 +743,6 @@
 
 private const val TAG = "SceneTransitionLayoutState"
 
-/** Whether support for interruptions in enabled by default. */
-internal const val DEFAULT_INTERRUPTIONS_ENABLED = true
-
 /**
  * The max number of concurrent transitions. If the number of transitions goes past this number,
  * this probably means that there is a leak and we will Log.wtf before clearing the list of
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SwipeToScene.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SwipeToScene.kt
index 98d4aaa..061583a 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SwipeToScene.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SwipeToScene.kt
@@ -41,22 +41,62 @@
     draggableHandler: DraggableHandlerImpl,
     swipeDetector: SwipeDetector,
 ): Modifier {
-    return this.then(SwipeToSceneElement(draggableHandler, swipeDetector))
+    return if (draggableHandler.enabled()) {
+        this.then(SwipeToSceneElement(draggableHandler, swipeDetector))
+    } else {
+        this
+    }
+}
+
+private fun DraggableHandlerImpl.enabled(): Boolean {
+    return isDrivingTransition || contentForSwipes().shouldEnableSwipes(orientation)
+}
+
+private fun DraggableHandlerImpl.contentForSwipes(): Content {
+    return layoutImpl.contentForUserActions()
+}
+
+/** Whether swipe should be enabled in the given [orientation]. */
+private fun Content.shouldEnableSwipes(orientation: Orientation): Boolean {
+    if (userActions.isEmpty()) {
+        return false
+    }
+
+    return userActions.keys.any { it is Swipe.Resolved && it.direction.orientation == orientation }
 }
 
 private data class SwipeToSceneElement(
     val draggableHandler: DraggableHandlerImpl,
     val swipeDetector: SwipeDetector,
-) : ModifierNodeElement<SwipeToSceneNode>() {
-    override fun create(): SwipeToSceneNode = SwipeToSceneNode(draggableHandler, swipeDetector)
+) : ModifierNodeElement<SwipeToSceneRootNode>() {
+    override fun create(): SwipeToSceneRootNode =
+        SwipeToSceneRootNode(draggableHandler, swipeDetector)
 
-    override fun update(node: SwipeToSceneNode) {
-        node.draggableHandler = draggableHandler
+    override fun update(node: SwipeToSceneRootNode) {
+        node.update(draggableHandler, swipeDetector)
+    }
+}
+
+private class SwipeToSceneRootNode(
+    draggableHandler: DraggableHandlerImpl,
+    swipeDetector: SwipeDetector,
+) : DelegatingNode() {
+    private var delegate = delegate(SwipeToSceneNode(draggableHandler, swipeDetector))
+
+    fun update(draggableHandler: DraggableHandlerImpl, swipeDetector: SwipeDetector) {
+        if (draggableHandler == delegate.draggableHandler) {
+            // Simple update, just update the swipe detector directly and keep the node.
+            delegate.swipeDetector = swipeDetector
+        } else {
+            // The draggableHandler changed, force recreate the underlying SwipeToSceneNode.
+            undelegate(delegate)
+            delegate = delegate(SwipeToSceneNode(draggableHandler, swipeDetector))
+        }
     }
 }
 
 private class SwipeToSceneNode(
-    draggableHandler: DraggableHandlerImpl,
+    val draggableHandler: DraggableHandlerImpl,
     swipeDetector: SwipeDetector,
 ) : DelegatingNode(), PointerInputModifierNode {
     private val dispatcher = NestedScrollDispatcher()
@@ -64,7 +104,6 @@
         delegate(
             MultiPointerDraggableNode(
                 orientation = draggableHandler.orientation,
-                enabled = ::enabled,
                 startDragImmediately = ::startDragImmediately,
                 onDragStarted = draggableHandler::onDragStarted,
                 onFirstPointerDown = ::onFirstPointerDown,
@@ -73,18 +112,10 @@
             )
         )
 
-    private var _draggableHandler = draggableHandler
-    var draggableHandler: DraggableHandlerImpl
-        get() = _draggableHandler
+    var swipeDetector: SwipeDetector
+        get() = multiPointerDraggableNode.swipeDetector
         set(value) {
-            if (_draggableHandler != value) {
-                _draggableHandler = value
-
-                // Make sure to update the delegate orientation. Note that this will automatically
-                // reset the underlying pointer input handler, so previous gestures will be
-                // cancelled.
-                multiPointerDraggableNode.orientation = value.orientation
-            }
+            multiPointerDraggableNode.swipeDetector = value
         }
 
     private val nestedScrollHandlerImpl =
@@ -124,22 +155,6 @@
 
     override fun onCancelPointerInput() = multiPointerDraggableNode.onCancelPointerInput()
 
-    private fun enabled(): Boolean {
-        return draggableHandler.isDrivingTransition ||
-            contentForSwipes().shouldEnableSwipes(multiPointerDraggableNode.orientation)
-    }
-
-    private fun contentForSwipes(): Content {
-        return draggableHandler.layoutImpl.contentForUserActions()
-    }
-
-    /** Whether swipe should be enabled in the given [orientation]. */
-    private fun Content.shouldEnableSwipes(orientation: Orientation): Boolean {
-        return userActions.keys.any {
-            it is Swipe.Resolved && it.direction.orientation == orientation
-        }
-    }
-
     private fun startDragImmediately(startedPosition: Offset): Boolean {
         // Immediately start the drag if the user can't swipe in the other direction and the gesture
         // handler can intercept it.
@@ -152,7 +167,7 @@
                 Orientation.Vertical -> Orientation.Horizontal
                 Orientation.Horizontal -> Orientation.Vertical
             }
-        return contentForSwipes().shouldEnableSwipes(oppositeOrientation)
+        return draggableHandler.contentForSwipes().shouldEnableSwipes(oppositeOrientation)
     }
 }
 
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/state/TransitionState.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/state/TransitionState.kt
index d6751ae..3bd59df 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/state/TransitionState.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/state/TransitionState.kt
@@ -21,6 +21,7 @@
 import androidx.compose.animation.core.spring
 import androidx.compose.foundation.gestures.Orientation
 import androidx.compose.runtime.Stable
+import androidx.compose.runtime.State
 import androidx.compose.runtime.derivedStateOf
 import androidx.compose.runtime.getValue
 import com.android.compose.animation.scene.ContentKey
@@ -249,18 +250,29 @@
         private var fromOverscrollSpec: OverscrollSpecImpl? = null
         private var toOverscrollSpec: OverscrollSpecImpl? = null
 
-        /** The current [OverscrollSpecImpl], if this transition is currently overscrolling. */
-        internal val currentOverscrollSpec: OverscrollSpecImpl?
-            get() {
-                if (this !is HasOverscrollProperties) return null
-                val progress = progress
-                val bouncingContent = bouncingContent
-                return when {
-                    progress < 0f || bouncingContent == fromContent -> fromOverscrollSpec
-                    progress > 1f || bouncingContent == toContent -> toOverscrollSpec
-                    else -> null
+        /**
+         * The current [OverscrollSpecImpl], if this transition is currently overscrolling.
+         *
+         * Note: This is backed by a State<OverscrollSpecImpl?> because the overscroll spec is
+         * derived from progress, and we don't want readers of currentOverscrollSpec to recompose
+         * every time progress is changed.
+         */
+        private val _currentOverscrollSpec: State<OverscrollSpecImpl?>? =
+            if (this !is HasOverscrollProperties) {
+                null
+            } else {
+                derivedStateOf {
+                    val progress = progress
+                    val bouncingContent = bouncingContent
+                    when {
+                        progress < 0f || bouncingContent == fromContent -> fromOverscrollSpec
+                        progress > 1f || bouncingContent == toContent -> toOverscrollSpec
+                        else -> null
+                    }
                 }
             }
+        internal val currentOverscrollSpec: OverscrollSpecImpl?
+            get() = _currentOverscrollSpec?.value
 
         /**
          * An animatable that animates from 1f to 0f. This will be used to nicely animate the sudden
@@ -337,10 +349,6 @@
         }
 
         internal open fun interruptionProgress(layoutImpl: SceneTransitionLayoutImpl): Float {
-            if (!layoutImpl.state.enableInterruptions) {
-                return 0f
-            }
-
             if (replacedTransition != null) {
                 return replacedTransition.interruptionProgress(layoutImpl)
             }
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ElementTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ElementTest.kt
index 1eed54e..39d4699 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ElementTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ElementTest.kt
@@ -46,6 +46,7 @@
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.geometry.Offset
 import androidx.compose.ui.layout.approachLayout
+import androidx.compose.ui.layout.layout
 import androidx.compose.ui.platform.LocalViewConfiguration
 import androidx.compose.ui.platform.testTag
 import androidx.compose.ui.test.assertIsDisplayed
@@ -70,11 +71,13 @@
 import com.android.compose.animation.scene.TestScenes.SceneA
 import com.android.compose.animation.scene.TestScenes.SceneB
 import com.android.compose.animation.scene.TestScenes.SceneC
+import com.android.compose.animation.scene.content.state.TransitionState
 import com.android.compose.animation.scene.subjects.assertThat
 import com.android.compose.test.assertSizeIsEqualTo
 import com.android.compose.test.setContentAndCreateMainScope
 import com.android.compose.test.transition
 import com.google.common.truth.Truth.assertThat
+import com.google.common.truth.Truth.assertWithMessage
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.launch
 import org.junit.Assert.assertThrows
@@ -213,10 +216,6 @@
                         from(SceneA, to = SceneB) { spec = tween }
                         from(SceneB, to = SceneC) { spec = tween }
                     },
-
-                    // Disable interruptions so that the current transition is directly removed
-                    // when starting a new one.
-                    enableInterruptions = false,
                 )
             }
 
@@ -243,7 +242,12 @@
                 onElement(TestElements.Bar).assertExists()
 
                 // Start transition from SceneB to SceneC
-                rule.runOnUiThread { state.setTargetScene(SceneC, coroutineScope) }
+                rule.runOnUiThread {
+                    // We snap to scene B so that the transition A => B is removed from the list of
+                    // transitions.
+                    state.snapToScene(SceneB)
+                    state.setTargetScene(SceneC, coroutineScope)
+                }
             }
 
             at(3 * frameDuration) { onElement(TestElements.Bar).assertIsNotDisplayed() }
@@ -2580,4 +2584,61 @@
             }
         }
     }
+
+    @Test
+    fun staticSharedElementShouldNotRemeasureOrReplaceDuringOverscrollableTransition() {
+        val size = 30.dp
+        var numberOfMeasurements = 0
+        var numberOfPlacements = 0
+
+        // Foo is a simple element that does not move or resize during the transition.
+        @Composable
+        fun SceneScope.Foo(modifier: Modifier = Modifier) {
+            Box(
+                modifier
+                    .element(TestElements.Foo)
+                    .layout { measurable, constraints ->
+                        numberOfMeasurements++
+                        measurable.measure(constraints).run {
+                            numberOfPlacements++
+                            layout(width, height) { place(0, 0) }
+                        }
+                    }
+                    .size(size)
+            )
+        }
+
+        val state = rule.runOnUiThread { MutableSceneTransitionLayoutState(SceneA) }
+        val scope =
+            rule.setContentAndCreateMainScope {
+                SceneTransitionLayout(state) {
+                    scene(SceneA) { Box(Modifier.fillMaxSize()) { Foo() } }
+                    scene(SceneB) { Box(Modifier.fillMaxSize()) { Foo() } }
+                }
+            }
+
+        // Start an overscrollable transition driven by progress.
+        var progress by mutableFloatStateOf(0f)
+        val transition = transition(from = SceneA, to = SceneB, progress = { progress })
+        assertThat(transition).isInstanceOf(TransitionState.HasOverscrollProperties::class.java)
+        scope.launch { state.startTransition(transition) }
+
+        // Reset the counters after the first animation frame.
+        rule.waitForIdle()
+        numberOfMeasurements = 0
+        numberOfPlacements = 0
+
+        // Change the progress a bunch of times.
+        val nFrames = 20
+        repeat(nFrames) { i ->
+            progress = i / nFrames.toFloat()
+            rule.waitForIdle()
+
+            // We shouldn't have remeasured or replaced Foo.
+            assertWithMessage("Frame $i didn't remeasure Foo")
+                .that(numberOfMeasurements)
+                .isEqualTo(0)
+            assertWithMessage("Frame $i didn't replace Foo").that(numberOfPlacements).isEqualTo(0)
+        }
+    }
 }
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/MultiPointerDraggableTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/MultiPointerDraggableTest.kt
index 493f3a1..c8f6e6d 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/MultiPointerDraggableTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/MultiPointerDraggableTest.kt
@@ -45,6 +45,7 @@
 import androidx.compose.ui.unit.Density
 import androidx.compose.ui.unit.Velocity
 import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.compose.modifiers.thenIf
 import com.android.compose.nestedscroll.SuspendedValue
 import com.google.common.truth.Truth.assertThat
 import kotlin.properties.Delegates
@@ -94,19 +95,20 @@
             Box(
                 Modifier.size(with(LocalDensity.current) { Size(size, size).toDpSize() })
                     .nestedScrollDispatcher()
-                    .multiPointerDraggable(
-                        orientation = Orientation.Vertical,
-                        enabled = { enabled },
-                        startDragImmediately = { false },
-                        onDragStarted = { _, _, _ ->
-                            started = true
-                            SimpleDragController(
-                                onDrag = { dragged = true },
-                                onStop = { stopped = true },
-                            )
-                        },
-                        dispatcher = defaultDispatcher,
-                    )
+                    .thenIf(enabled) {
+                        Modifier.multiPointerDraggable(
+                            orientation = Orientation.Vertical,
+                            startDragImmediately = { false },
+                            onDragStarted = { _, _, _ ->
+                                started = true
+                                SimpleDragController(
+                                    onDrag = { dragged = true },
+                                    onStop = { stopped = true },
+                                )
+                            },
+                            dispatcher = defaultDispatcher,
+                        )
+                    }
             )
         }
 
@@ -164,7 +166,6 @@
                     .nestedScrollDispatcher()
                     .multiPointerDraggable(
                         orientation = Orientation.Vertical,
-                        enabled = { true },
                         // We want to start a drag gesture immediately
                         startDragImmediately = { true },
                         onDragStarted = { _, _, _ ->
@@ -238,7 +239,6 @@
                     .nestedScrollDispatcher()
                     .multiPointerDraggable(
                         orientation = Orientation.Vertical,
-                        enabled = { true },
                         startDragImmediately = { false },
                         onDragStarted = { _, _, _ ->
                             started = true
@@ -358,7 +358,6 @@
                     .nestedScrollDispatcher()
                     .multiPointerDraggable(
                         orientation = Orientation.Vertical,
-                        enabled = { true },
                         startDragImmediately = { false },
                         onDragStarted = { _, _, _ ->
                             started = true
@@ -464,7 +463,6 @@
                     .nestedScrollDispatcher()
                     .multiPointerDraggable(
                         orientation = Orientation.Vertical,
-                        enabled = { true },
                         startDragImmediately = { false },
                         onDragStarted = { _, _, _ ->
                             verticalStarted = true
@@ -477,7 +475,6 @@
                     )
                     .multiPointerDraggable(
                         orientation = Orientation.Horizontal,
-                        enabled = { true },
                         startDragImmediately = { false },
                         onDragStarted = { _, _, _ ->
                             horizontalStarted = true
@@ -570,7 +567,6 @@
                     .nestedScrollDispatcher()
                     .multiPointerDraggable(
                         orientation = Orientation.Vertical,
-                        enabled = { true },
                         startDragImmediately = { false },
                         swipeDetector =
                             object : SwipeDetector {
@@ -672,7 +668,6 @@
                     .nestedScrollDispatcher()
                     .multiPointerDraggable(
                         orientation = Orientation.Vertical,
-                        enabled = { true },
                         startDragImmediately = { false },
                         onDragStarted = { _, _, _ ->
                             SimpleDragController(
@@ -744,7 +739,6 @@
                     .nestedScrollDispatcher()
                     .multiPointerDraggable(
                         orientation = Orientation.Vertical,
-                        enabled = { true },
                         startDragImmediately = { false },
                         onDragStarted = { _, _, _ ->
                             SimpleDragController(
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutTest.kt
index 400f0b3..b00b894b 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutTest.kt
@@ -85,15 +85,9 @@
 
     /** The content under test. */
     @Composable
-    private fun TestContent(enableInterruptions: Boolean = true) {
+    private fun TestContent() {
         coroutineScope = rememberCoroutineScope()
-        layoutState = remember {
-            MutableSceneTransitionLayoutState(
-                SceneA,
-                EmptyTestTransitions,
-                enableInterruptions = enableInterruptions,
-            )
-        }
+        layoutState = remember { MutableSceneTransitionLayoutState(SceneA, EmptyTestTransitions) }
 
         SceneTransitionLayout(state = layoutState, modifier = Modifier.size(LayoutSize)) {
             scene(SceneA, userActions = mapOf(Back to SceneB)) {
@@ -205,7 +199,7 @@
 
     @Test
     fun testSharedElement() {
-        rule.setContent { TestContent(enableInterruptions = false) }
+        rule.setContent { TestContent() }
 
         // In scene A, the shared element SharedFoo() is at the top end of the layout and has a size
         // of 50.dp.
@@ -253,6 +247,9 @@
             .isWithin(DpOffsetSubject.DefaultTolerance)
             .of(DpOffset(25.dp, 25.dp))
 
+        // Finish the transition.
+        rule.mainClock.advanceTimeBy(TestTransitionDuration / 2)
+
         // Animate to scene C, let the animation start then go to the middle of the transition.
         currentScene = SceneC
         rule.mainClock.advanceTimeByFrame()
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SwipeToSceneTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SwipeToSceneTest.kt
index 25e8713..28d0a47 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SwipeToSceneTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SwipeToSceneTest.kt
@@ -22,11 +22,15 @@
 import androidx.compose.foundation.layout.fillMaxSize
 import androidx.compose.foundation.layout.offset
 import androidx.compose.foundation.layout.size
+import androidx.compose.material3.Button
+import androidx.compose.material3.Text
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.CompositionLocalProvider
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
 import androidx.compose.runtime.setValue
+import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.geometry.Offset
 import androidx.compose.ui.input.nestedscroll.NestedScrollConnection
@@ -36,9 +40,14 @@
 import androidx.compose.ui.platform.LocalViewConfiguration
 import androidx.compose.ui.platform.testTag
 import androidx.compose.ui.test.assertPositionInRootIsEqualTo
+import androidx.compose.ui.test.assertTextEquals
 import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.compose.ui.test.onNodeWithTag
 import androidx.compose.ui.test.onRoot
+import androidx.compose.ui.test.performClick
 import androidx.compose.ui.test.performTouchInput
+import androidx.compose.ui.test.swipeRight
+import androidx.compose.ui.test.swipeUp
 import androidx.compose.ui.test.swipeWithVelocity
 import androidx.compose.ui.unit.Density
 import androidx.compose.ui.unit.IntSize
@@ -844,4 +853,62 @@
         assertThat(transition.progress).isEqualTo(1f)
         assertThat(availableOnPostScroll).isEqualTo(ovescrollPx)
     }
+
+    @Test
+    fun sceneWithoutSwipesDoesNotConsumeGestures() {
+        val buttonTag = "button"
+
+        rule.setContent {
+            Box {
+                var count by remember { mutableStateOf(0) }
+                Button(onClick = { count++ }, Modifier.testTag(buttonTag).align(Alignment.Center)) {
+                    Text("Count: $count")
+                }
+
+                SceneTransitionLayout(remember { MutableSceneTransitionLayoutState(SceneA) }) {
+                    scene(SceneA) { Box(Modifier.fillMaxSize()) }
+                }
+            }
+        }
+
+        rule.onNodeWithTag(buttonTag).assertTextEquals("Count: 0")
+
+        // Click on the root at its center, where the button is located. Clicks should go through
+        // the STL and reach the button given that there is no swipes for the current scene.
+        repeat(3) { rule.onRoot().performClick() }
+        rule.onNodeWithTag(buttonTag).assertTextEquals("Count: 3")
+    }
+
+    @Test
+    fun swipeToSceneSupportsUpdates() {
+        val state = rule.runOnUiThread { MutableSceneTransitionLayoutState(SceneA) }
+
+        rule.setContent {
+            SceneTransitionLayout(state) {
+                // SceneA only has vertical actions, so only one vertical Modifier.swipeToScene()
+                // is composed.
+                scene(SceneA, mapOf(Swipe.Up to SceneB)) { Box(Modifier.fillMaxSize()) }
+
+                // SceneB only has horizontal actions, so only one vertical Modifier.swipeToScene()
+                // is composed, which will be force update it with a new draggableHandler.
+                scene(SceneB, mapOf(Swipe.Right to SceneC)) { Box(Modifier.fillMaxSize()) }
+                scene(SceneC) { Box(Modifier.fillMaxSize()) }
+            }
+        }
+
+        assertThat(state.transitionState).isIdle()
+        assertThat(state.transitionState).hasCurrentScene(SceneA)
+
+        // Swipe up to scene B.
+        rule.onRoot().performTouchInput { swipeUp() }
+        rule.waitForIdle()
+        assertThat(state.transitionState).isIdle()
+        assertThat(state.transitionState).hasCurrentScene(SceneB)
+
+        // Swipe right to scene C.
+        rule.onRoot().performTouchInput { swipeRight() }
+        rule.waitForIdle()
+        assertThat(state.transitionState).isIdle()
+        assertThat(state.transitionState).hasCurrentScene(SceneC)
+    }
 }
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ComposedDigitalLayerController.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ComposedDigitalLayerController.kt
new file mode 100644
index 0000000..9b94c91
--- /dev/null
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ComposedDigitalLayerController.kt
@@ -0,0 +1,203 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.shared.clocks
+
+import android.content.Context
+import android.content.res.Resources
+import android.graphics.Rect
+import androidx.annotation.VisibleForTesting
+import com.android.systemui.log.core.Logger
+import com.android.systemui.log.core.MessageBuffer
+import com.android.systemui.plugins.clocks.AlarmData
+import com.android.systemui.plugins.clocks.ClockAnimations
+import com.android.systemui.plugins.clocks.ClockEvents
+import com.android.systemui.plugins.clocks.ClockFaceConfig
+import com.android.systemui.plugins.clocks.ClockFaceEvents
+import com.android.systemui.plugins.clocks.ClockReactiveSetting
+import com.android.systemui.plugins.clocks.WeatherData
+import com.android.systemui.plugins.clocks.ZenData
+import com.android.systemui.shared.clocks.view.DigitalClockFaceView
+import com.android.systemui.shared.clocks.view.FlexClockView
+import java.util.Locale
+import java.util.TimeZone
+
+class ComposedDigitalLayerController(
+    private val ctx: Context,
+    private val assets: AssetLoader,
+    private val layer: ComposedDigitalHandLayer,
+    private val isLargeClock: Boolean,
+    messageBuffer: MessageBuffer,
+) : SimpleClockLayerController {
+    private val logger = Logger(messageBuffer, ComposedDigitalLayerController::class.simpleName!!)
+
+    val layerControllers = mutableListOf<SimpleClockLayerController>()
+    val dozeState = DefaultClockController.AnimationState(1F)
+    var isRegionDark = true
+
+    override var view: DigitalClockFaceView =
+        when (layer.customizedView) {
+            "FlexClockView" -> FlexClockView(ctx, assets, messageBuffer)
+            else -> {
+                throw IllegalStateException("CustomizedView string is not valid")
+            }
+        }
+
+    // Matches LayerControllerConstructor
+    internal constructor(
+        ctx: Context,
+        assets: AssetLoader,
+        layer: ClockLayer,
+        isLargeClock: Boolean,
+        messageBuffer: MessageBuffer,
+    ) : this(ctx, assets, layer as ComposedDigitalHandLayer, isLargeClock, messageBuffer)
+
+    init {
+        layer.digitalLayers.forEach {
+            val controller =
+                SimpleClockLayerController.Factory.create(
+                    ctx,
+                    assets,
+                    it,
+                    isLargeClock,
+                    messageBuffer,
+                )
+            view.addView(controller.view)
+            layerControllers.add(controller)
+        }
+    }
+
+    private fun refreshTime() {
+        layerControllers.forEach { it.faceEvents.onTimeTick() }
+        view.refreshTime()
+    }
+
+    override val events =
+        object : ClockEvents {
+            override fun onTimeZoneChanged(timeZone: TimeZone) {
+                layerControllers.forEach { it.events.onTimeZoneChanged(timeZone) }
+                refreshTime()
+            }
+
+            override fun onTimeFormatChanged(is24Hr: Boolean) {
+                layerControllers.forEach { it.events.onTimeFormatChanged(is24Hr) }
+                refreshTime()
+            }
+
+            override fun onLocaleChanged(locale: Locale) {
+                layerControllers.forEach { it.events.onLocaleChanged(locale) }
+                view.onLocaleChanged(locale)
+                refreshTime()
+            }
+
+            override fun onWeatherDataChanged(data: WeatherData) {
+                view.onWeatherDataChanged(data)
+            }
+
+            override fun onAlarmDataChanged(data: AlarmData) {
+                view.onAlarmDataChanged(data)
+            }
+
+            override fun onZenDataChanged(data: ZenData) {
+                view.onZenDataChanged(data)
+            }
+
+            override fun onColorPaletteChanged(resources: Resources) {}
+
+            override fun onSeedColorChanged(seedColor: Int?) {}
+
+            override fun onReactiveAxesChanged(axes: List<ClockReactiveSetting>) {}
+
+            override var isReactiveTouchInteractionEnabled
+                get() = view.isReactiveTouchInteractionEnabled
+                set(value) {
+                    view.isReactiveTouchInteractionEnabled = value
+                }
+        }
+
+    override fun updateColors() {
+        view.updateColors(assets, isRegionDark)
+    }
+
+    override val animations =
+        object : ClockAnimations {
+            override fun enter() {
+                refreshTime()
+            }
+
+            override fun doze(fraction: Float) {
+                val (hasChanged, hasJumped) = dozeState.update(fraction)
+                if (hasChanged) view.animateDoze(dozeState.isActive, !hasJumped)
+                view.dozeFraction = fraction
+                view.invalidate()
+            }
+
+            override fun fold(fraction: Float) {
+                refreshTime()
+            }
+
+            override fun charge() {
+                view.animateCharge()
+            }
+
+            override fun onPositionUpdated(fromLeft: Int, direction: Int, fraction: Float) {
+                view.onPositionUpdated(fromLeft, direction, fraction)
+            }
+
+            override fun onPositionUpdated(distance: Float, fraction: Float) {}
+
+            override fun onPickerCarouselSwiping(swipingFraction: Float) {
+                view.onPickerCarouselSwiping(swipingFraction)
+            }
+        }
+
+    override val faceEvents =
+        object : ClockFaceEvents {
+            override fun onTimeTick() {
+                refreshTime()
+            }
+
+            override fun onRegionDarknessChanged(isRegionDark: Boolean) {
+                this@ComposedDigitalLayerController.isRegionDark = isRegionDark
+                updateColors()
+            }
+
+            override fun onFontSettingChanged(fontSizePx: Float) {
+                view.onFontSettingChanged(fontSizePx)
+            }
+
+            override fun onTargetRegionChanged(targetRegion: Rect?) {}
+
+            override fun onSecondaryDisplayChanged(onSecondaryDisplay: Boolean) {}
+        }
+
+    override val config =
+        ClockFaceConfig(
+            hasCustomWeatherDataDisplay = view.hasCustomWeatherDataDisplay,
+            hasCustomPositionUpdatedAnimation = view.hasCustomPositionUpdatedAnimation,
+            useCustomClockScene = view.useCustomClockScene,
+        )
+
+    @VisibleForTesting
+    override var fakeTimeMills: Long? = null
+        get() = field
+        set(timeInMills) {
+            field = timeInMills
+            for (layerController in layerControllers) {
+                layerController.fakeTimeMills = timeInMills
+            }
+        }
+}
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockProvider.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockProvider.kt
index 07191c6..ac26842 100644
--- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockProvider.kt
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockProvider.kt
@@ -24,6 +24,8 @@
 import com.android.systemui.plugins.clocks.ClockPickerConfig
 import com.android.systemui.plugins.clocks.ClockProvider
 import com.android.systemui.plugins.clocks.ClockSettings
+import com.android.systemui.shared.clocks.view.HorizontalAlignment
+import com.android.systemui.shared.clocks.view.VerticalAlignment
 
 private val TAG = DefaultClockProvider::class.simpleName
 const val DEFAULT_CLOCK_ID = "DEFAULT"
@@ -33,8 +35,9 @@
     val ctx: Context,
     val layoutInflater: LayoutInflater,
     val resources: Resources,
-    val hasStepClockAnimation: Boolean = false,
-    val migratedClocks: Boolean = false,
+    private val hasStepClockAnimation: Boolean = false,
+    private val migratedClocks: Boolean = false,
+    private val clockReactiveVariants: Boolean = false,
 ) : ClockProvider {
     private var messageBuffers: ClockMessageBuffers? = null
 
@@ -49,15 +52,23 @@
             throw IllegalArgumentException("${settings.clockId} is unsupported by $TAG")
         }
 
-        return DefaultClockController(
-            ctx,
-            layoutInflater,
-            resources,
-            settings,
-            hasStepClockAnimation,
-            migratedClocks,
-            messageBuffers,
-        )
+        return if (clockReactiveVariants) {
+            // TODO handle the case here where only the smallClock message buffer is added
+            val assetLoader =
+                AssetLoader(ctx, ctx, "clocks/", messageBuffers?.smallClockMessageBuffer!!)
+
+            SimpleClockController(ctx, assetLoader, FLEX_DESIGN, messageBuffers)
+        } else {
+            DefaultClockController(
+                ctx,
+                layoutInflater,
+                resources,
+                settings,
+                hasStepClockAnimation,
+                migratedClocks,
+                messageBuffers,
+            )
+        }
     }
 
     override fun getClockPickerConfig(id: ClockId): ClockPickerConfig {
@@ -73,4 +84,163 @@
             resources.getDrawable(R.drawable.clock_default_thumbnail, null),
         )
     }
+
+    companion object {
+        val FLEX_DESIGN = run {
+            val largeLayer =
+                listOf(
+                    ComposedDigitalHandLayer(
+                        layerBounds = LayerBounds.FIT,
+                        customizedView = "FlexClockView",
+                        digitalLayers =
+                            listOf(
+                                DigitalHandLayer(
+                                    layerBounds = LayerBounds.FIT,
+                                    timespec = DigitalTimespec.FIRST_DIGIT,
+                                    style =
+                                        FontTextStyle(
+                                            fontFamily = "google_sans_flex.ttf",
+                                            lineHeight = 147.25f,
+                                            fontVariation =
+                                                "'wght' 603, 'wdth' 100, 'opsz' 144, 'ROND' 100",
+                                        ),
+                                    aodStyle =
+                                        FontTextStyle(
+                                            fontVariation =
+                                                "'wght' 74, 'wdth' 43, 'opsz' 144, 'ROND' 100",
+                                            fontFamily = "google_sans_flex.ttf",
+                                            fillColorLight = "#FFFFFFFF",
+                                            outlineColor = "#00000000",
+                                            renderType = RenderType.CHANGE_WEIGHT,
+                                            transitionInterpolator = InterpolatorEnum.EMPHASIZED,
+                                            transitionDuration = 750,
+                                        ),
+                                    alignment =
+                                        DigitalAlignment(
+                                            HorizontalAlignment.CENTER,
+                                            VerticalAlignment.CENTER
+                                        ),
+                                    dateTimeFormat = "hh"
+                                ),
+                                DigitalHandLayer(
+                                    layerBounds = LayerBounds.FIT,
+                                    timespec = DigitalTimespec.SECOND_DIGIT,
+                                    style =
+                                        FontTextStyle(
+                                            fontFamily = "google_sans_flex.ttf",
+                                            lineHeight = 147.25f,
+                                            fontVariation =
+                                                "'wght' 603, 'wdth' 100, 'opsz' 144, 'ROND' 100",
+                                        ),
+                                    aodStyle =
+                                        FontTextStyle(
+                                            fontVariation =
+                                                "'wght' 74, 'wdth' 43, 'opsz' 144, 'ROND' 100",
+                                            fontFamily = "google_sans_flex.ttf",
+                                            fillColorLight = "#FFFFFFFF",
+                                            outlineColor = "#00000000",
+                                            renderType = RenderType.CHANGE_WEIGHT,
+                                            transitionInterpolator = InterpolatorEnum.EMPHASIZED,
+                                            transitionDuration = 750,
+                                        ),
+                                    alignment =
+                                        DigitalAlignment(
+                                            HorizontalAlignment.CENTER,
+                                            VerticalAlignment.CENTER
+                                        ),
+                                    dateTimeFormat = "hh"
+                                ),
+                                DigitalHandLayer(
+                                    layerBounds = LayerBounds.FIT,
+                                    timespec = DigitalTimespec.FIRST_DIGIT,
+                                    style =
+                                        FontTextStyle(
+                                            fontFamily = "google_sans_flex.ttf",
+                                            lineHeight = 147.25f,
+                                            fontVariation =
+                                                "'wght' 603, 'wdth' 100, 'opsz' 144, 'ROND' 100",
+                                        ),
+                                    aodStyle =
+                                        FontTextStyle(
+                                            fontVariation =
+                                                "'wght' 74, 'wdth' 43, 'opsz' 144, 'ROND' 100",
+                                            fontFamily = "google_sans_flex.ttf",
+                                            fillColorLight = "#FFFFFFFF",
+                                            outlineColor = "#00000000",
+                                            renderType = RenderType.CHANGE_WEIGHT,
+                                            transitionInterpolator = InterpolatorEnum.EMPHASIZED,
+                                            transitionDuration = 750,
+                                        ),
+                                    alignment =
+                                        DigitalAlignment(
+                                            HorizontalAlignment.CENTER,
+                                            VerticalAlignment.CENTER
+                                        ),
+                                    dateTimeFormat = "mm"
+                                ),
+                                DigitalHandLayer(
+                                    layerBounds = LayerBounds.FIT,
+                                    timespec = DigitalTimespec.SECOND_DIGIT,
+                                    style =
+                                        FontTextStyle(
+                                            fontFamily = "google_sans_flex.ttf",
+                                            lineHeight = 147.25f,
+                                            fontVariation =
+                                                "'wght' 603, 'wdth' 100, 'opsz' 144, 'ROND' 100",
+                                        ),
+                                    aodStyle =
+                                        FontTextStyle(
+                                            fontVariation =
+                                                "'wght' 74, 'wdth' 43, 'opsz' 144, 'ROND' 100",
+                                            fontFamily = "google_sans_flex.ttf",
+                                            fillColorLight = "#FFFFFFFF",
+                                            outlineColor = "#00000000",
+                                            renderType = RenderType.CHANGE_WEIGHT,
+                                            transitionInterpolator = InterpolatorEnum.EMPHASIZED,
+                                            transitionDuration = 750,
+                                        ),
+                                    alignment =
+                                        DigitalAlignment(
+                                            HorizontalAlignment.CENTER,
+                                            VerticalAlignment.CENTER
+                                        ),
+                                    dateTimeFormat = "mm"
+                                )
+                            )
+                    )
+                )
+
+            val smallLayer =
+                listOf(
+                    DigitalHandLayer(
+                        layerBounds = LayerBounds.FIT,
+                        timespec = DigitalTimespec.TIME_FULL_FORMAT,
+                        style =
+                            FontTextStyle(
+                                fontFamily = "google_sans_flex.ttf",
+                                fontVariation = "'wght' 600, 'wdth' 100, 'opsz' 144, 'ROND' 100",
+                                fontSizeScale = 0.98f,
+                            ),
+                        aodStyle =
+                            FontTextStyle(
+                                fontFamily = "google_sans_flex.ttf",
+                                fontVariation = "'wght' 133, 'wdth' 43, 'opsz' 144, 'ROND' 100",
+                                fillColorLight = "#FFFFFFFF",
+                                outlineColor = "#00000000",
+                                renderType = RenderType.CHANGE_WEIGHT,
+                            ),
+                        alignment = DigitalAlignment(HorizontalAlignment.LEFT, null),
+                        dateTimeFormat = "h:mm"
+                    )
+                )
+
+            ClockDesign(
+                id = DEFAULT_CLOCK_ID,
+                name = "@string/clock_default_name",
+                description = "@string/clock_default_description",
+                large = ClockFace(layers = largeLayer),
+                small = ClockFace(layers = smallLayer)
+            )
+        }
+    }
 }
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/LayoutUtils.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/LayoutUtils.kt
new file mode 100644
index 0000000..ef8bee0
--- /dev/null
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/LayoutUtils.kt
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.shared.clocks
+
+import android.graphics.Rect
+import android.view.View
+
+fun computeLayoutDiff(
+    view: View,
+    targetRegion: Rect,
+    isLargeClock: Boolean,
+): Pair<Float, Float> {
+    val parent = view.parent
+    if (parent is View && parent.isLaidOut() && isLargeClock) {
+        return Pair(
+            targetRegion.centerX() - parent.width / 2f,
+            targetRegion.centerY() - parent.height / 2f
+        )
+    }
+    return Pair(0f, 0f)
+}
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/SimpleClockController.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/SimpleClockController.kt
new file mode 100644
index 0000000..ec77798
--- /dev/null
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/SimpleClockController.kt
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.shared.clocks
+
+import android.content.Context
+import android.content.res.Resources
+import com.android.systemui.monet.Style as MonetStyle
+import com.android.systemui.plugins.clocks.AlarmData
+import com.android.systemui.plugins.clocks.ClockConfig
+import com.android.systemui.plugins.clocks.ClockController
+import com.android.systemui.plugins.clocks.ClockEvents
+import com.android.systemui.plugins.clocks.ClockMessageBuffers
+import com.android.systemui.plugins.clocks.ClockReactiveSetting
+import com.android.systemui.plugins.clocks.WeatherData
+import com.android.systemui.plugins.clocks.ZenData
+import java.io.PrintWriter
+import java.util.Locale
+import java.util.TimeZone
+
+/** Controller for a simple json specified clock */
+class SimpleClockController(
+    private val ctx: Context,
+    private val assets: AssetLoader,
+    val design: ClockDesign,
+    val messageBuffers: ClockMessageBuffers?,
+) : ClockController {
+    override val smallClock = run {
+        val buffer = messageBuffers?.smallClockMessageBuffer ?: LogUtil.DEFAULT_MESSAGE_BUFFER
+        SimpleClockFaceController(
+            ctx,
+            assets.copy(messageBuffer = buffer),
+            design.small ?: design.large!!,
+            false,
+            buffer,
+        )
+    }
+
+    override val largeClock = run {
+        val buffer = messageBuffers?.largeClockMessageBuffer ?: LogUtil.DEFAULT_MESSAGE_BUFFER
+        SimpleClockFaceController(
+            ctx,
+            assets.copy(messageBuffer = buffer),
+            design.large ?: design.small!!,
+            true,
+            buffer,
+        )
+    }
+
+    override val config: ClockConfig by lazy {
+        ClockConfig(
+            design.id,
+            design.name?.let { assets.tryReadString(it) ?: it } ?: "",
+            design.description?.let { assets.tryReadString(it) ?: it } ?: "",
+            isReactiveToTone =
+                design.colorPalette == null || design.colorPalette == MonetStyle.CLOCK,
+            useAlternateSmartspaceAODTransition =
+                smallClock.config.hasCustomWeatherDataDisplay ||
+                    largeClock.config.hasCustomWeatherDataDisplay,
+            useCustomClockScene =
+                smallClock.config.useCustomClockScene || largeClock.config.useCustomClockScene,
+        )
+    }
+
+    override val events =
+        object : ClockEvents {
+            override var isReactiveTouchInteractionEnabled = false
+                set(value) {
+                    field = value
+                    smallClock.events.isReactiveTouchInteractionEnabled = value
+                    largeClock.events.isReactiveTouchInteractionEnabled = value
+                }
+
+            override fun onTimeZoneChanged(timeZone: TimeZone) {
+                smallClock.events.onTimeZoneChanged(timeZone)
+                largeClock.events.onTimeZoneChanged(timeZone)
+            }
+
+            override fun onTimeFormatChanged(is24Hr: Boolean) {
+                smallClock.events.onTimeFormatChanged(is24Hr)
+                largeClock.events.onTimeFormatChanged(is24Hr)
+            }
+
+            override fun onLocaleChanged(locale: Locale) {
+                smallClock.events.onLocaleChanged(locale)
+                largeClock.events.onLocaleChanged(locale)
+            }
+
+            override fun onColorPaletteChanged(resources: Resources) {
+                assets.refreshColorPalette(design.colorPalette)
+                smallClock.assets.refreshColorPalette(design.colorPalette)
+                largeClock.assets.refreshColorPalette(design.colorPalette)
+
+                smallClock.events.onColorPaletteChanged(resources)
+                largeClock.events.onColorPaletteChanged(resources)
+            }
+
+            override fun onSeedColorChanged(seedColor: Int?) {
+                assets.setSeedColor(seedColor, design.colorPalette)
+                smallClock.assets.setSeedColor(seedColor, design.colorPalette)
+                largeClock.assets.setSeedColor(seedColor, design.colorPalette)
+
+                smallClock.events.onSeedColorChanged(seedColor)
+                largeClock.events.onSeedColorChanged(seedColor)
+            }
+
+            override fun onWeatherDataChanged(data: WeatherData) {
+                smallClock.events.onWeatherDataChanged(data)
+                largeClock.events.onWeatherDataChanged(data)
+            }
+
+            override fun onAlarmDataChanged(data: AlarmData) {
+                smallClock.events.onAlarmDataChanged(data)
+                largeClock.events.onAlarmDataChanged(data)
+            }
+
+            override fun onZenDataChanged(data: ZenData) {
+                smallClock.events.onZenDataChanged(data)
+                largeClock.events.onZenDataChanged(data)
+            }
+
+            override fun onReactiveAxesChanged(axes: List<ClockReactiveSetting>) {
+                smallClock.events.onReactiveAxesChanged(axes)
+                largeClock.events.onReactiveAxesChanged(axes)
+            }
+        }
+
+    override fun initialize(resources: Resources, dozeFraction: Float, foldFraction: Float) {
+        events.onColorPaletteChanged(resources)
+        smallClock.animations.doze(dozeFraction)
+        largeClock.animations.doze(dozeFraction)
+        smallClock.animations.fold(foldFraction)
+        largeClock.animations.fold(foldFraction)
+        smallClock.events.onTimeTick()
+        largeClock.events.onTimeTick()
+    }
+
+    override fun dump(pw: PrintWriter) {}
+}
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/SimpleClockFaceController.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/SimpleClockFaceController.kt
new file mode 100644
index 0000000..ef398d1
--- /dev/null
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/SimpleClockFaceController.kt
@@ -0,0 +1,314 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.shared.clocks
+
+import android.content.Context
+import android.content.res.Resources
+import android.graphics.Rect
+import android.view.Gravity
+import android.view.View
+import android.view.ViewGroup.LayoutParams.MATCH_PARENT
+import android.widget.FrameLayout
+import com.android.systemui.log.core.MessageBuffer
+import com.android.systemui.plugins.clocks.AlarmData
+import com.android.systemui.plugins.clocks.ClockAnimations
+import com.android.systemui.plugins.clocks.ClockEvents
+import com.android.systemui.plugins.clocks.ClockFaceConfig
+import com.android.systemui.plugins.clocks.ClockFaceController
+import com.android.systemui.plugins.clocks.ClockFaceEvents
+import com.android.systemui.plugins.clocks.ClockFaceLayout
+import com.android.systemui.plugins.clocks.ClockReactiveSetting
+import com.android.systemui.plugins.clocks.ClockTickRate
+import com.android.systemui.plugins.clocks.DefaultClockFaceLayout
+import com.android.systemui.plugins.clocks.WeatherData
+import com.android.systemui.plugins.clocks.ZenData
+import com.android.systemui.shared.clocks.view.DigitalClockFaceView
+import java.util.Locale
+import java.util.TimeZone
+import kotlin.math.max
+
+interface ClockEventUnion : ClockEvents, ClockFaceEvents
+
+class SimpleClockFaceController(
+    ctx: Context,
+    val assets: AssetLoader,
+    face: ClockFace,
+    isLargeClock: Boolean,
+    messageBuffer: MessageBuffer,
+) : ClockFaceController {
+    override val view: View
+    override val config: ClockFaceConfig by lazy {
+        ClockFaceConfig(
+            hasCustomWeatherDataDisplay = layers.any { it.config.hasCustomWeatherDataDisplay },
+            hasCustomPositionUpdatedAnimation =
+                layers.any { it.config.hasCustomPositionUpdatedAnimation },
+            tickRate = getTickRate(),
+            useCustomClockScene = layers.any { it.config.useCustomClockScene },
+        )
+    }
+
+    val layers = mutableListOf<SimpleClockLayerController>()
+
+    val timespecHandler = DigitalTimespecHandler(DigitalTimespec.TIME_FULL_FORMAT, "hh:mm")
+
+    init {
+        val lp = FrameLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT)
+        lp.gravity = Gravity.CENTER
+        view =
+            if (face.layers.size == 1) {
+                // Optimize a clocks with a single layer by excluding the face level view group. We
+                // expect the view container from the host process to always be a FrameLayout.
+                val layer = face.layers[0]
+                val controller =
+                    SimpleClockLayerController.Factory.create(
+                        ctx,
+                        assets,
+                        layer,
+                        isLargeClock,
+                        messageBuffer,
+                    )
+                layers.add(controller)
+                controller.view.layoutParams = lp
+                controller.view
+            } else {
+                // For multiple views, we use an intermediate RelativeLayout so that we can do some
+                // intelligent laying out between the children views.
+                val group = SimpleClockRelativeLayout(ctx, face.faceLayout)
+                group.layoutParams = lp
+                group.gravity = Gravity.CENTER
+                group.clipChildren = false
+                for (layer in face.layers) {
+                    face.faceLayout?.let {
+                        if (layer is DigitalHandLayer) {
+                            layer.faceLayout = it
+                        }
+                    }
+                    val controller =
+                        SimpleClockLayerController.Factory.create(
+                            ctx,
+                            assets,
+                            layer,
+                            isLargeClock,
+                            messageBuffer,
+                        )
+                    group.addView(controller.view)
+                    layers.add(controller)
+                }
+                group
+            }
+    }
+
+    override val layout: ClockFaceLayout =
+        DefaultClockFaceLayout(view).apply {
+            views[0].id =
+                if (isLargeClock) {
+                    assets.getResourcesId("lockscreen_clock_view_large")
+                } else {
+                    assets.getResourcesId("lockscreen_clock_view")
+                }
+        }
+
+    override val events =
+        object : ClockEventUnion {
+            override var isReactiveTouchInteractionEnabled = false
+                get() = field
+                set(value) {
+                    field = value
+                    layers.forEach { it.events.isReactiveTouchInteractionEnabled = value }
+                }
+
+            override fun onTimeTick() {
+                timespecHandler.updateTime()
+                if (
+                    config.tickRate == ClockTickRate.PER_MINUTE ||
+                        view.contentDescription != timespecHandler.getContentDescription()
+                ) {
+                    view.contentDescription = timespecHandler.getContentDescription()
+                }
+                layers.forEach { it.faceEvents.onTimeTick() }
+            }
+
+            override fun onTimeZoneChanged(timeZone: TimeZone) {
+                timespecHandler.timeZone = timeZone
+                layers.forEach { it.events.onTimeZoneChanged(timeZone) }
+            }
+
+            override fun onTimeFormatChanged(is24Hr: Boolean) {
+                timespecHandler.is24Hr = is24Hr
+                layers.forEach { it.events.onTimeFormatChanged(is24Hr) }
+            }
+
+            override fun onLocaleChanged(locale: Locale) {
+                timespecHandler.updateLocale(locale)
+                layers.forEach { it.events.onLocaleChanged(locale) }
+            }
+
+            override fun onFontSettingChanged(fontSizePx: Float) {
+                layers.forEach { it.faceEvents.onFontSettingChanged(fontSizePx) }
+            }
+
+            override fun onColorPaletteChanged(resources: Resources) {
+                layers.forEach {
+                    it.events.onColorPaletteChanged(resources)
+                    it.updateColors()
+                }
+            }
+
+            override fun onSeedColorChanged(seedColor: Int?) {
+                layers.forEach {
+                    it.events.onSeedColorChanged(seedColor)
+                    it.updateColors()
+                }
+            }
+
+            override fun onRegionDarknessChanged(isRegionDark: Boolean) {
+                layers.forEach { it.faceEvents.onRegionDarknessChanged(isRegionDark) }
+            }
+
+            override fun onReactiveAxesChanged(axes: List<ClockReactiveSetting>) {}
+
+            /**
+             * targetRegion passed to all customized clock applies counter translationY of
+             * KeyguardStatusView and keyguard_large_clock_top_margin from default clock
+             */
+            override fun onTargetRegionChanged(targetRegion: Rect?) {
+                // When a clock needs to be aligned with screen, like weather clock
+                // it needs to offset back the translation of keyguard_large_clock_top_margin
+                if (view is DigitalClockFaceView && view.isAlignedWithScreen()) {
+                    val topMargin = getKeyguardLargeClockTopMargin(assets)
+                    targetRegion?.let {
+                        val (_, yDiff) = computeLayoutDiff(view, it, isLargeClock)
+                        // In LS, we use yDiff to counter translate
+                        // the translation of KeyguardLargeClockTopMargin
+                        // With the targetRegion passed from picker,
+                        // we will have yDiff = 0, no translation is needed for weather clock
+                        if (yDiff.toInt() != 0) view.translationY = yDiff - topMargin / 2
+                    }
+                    return
+                }
+
+                var maxWidth = 0f
+                var maxHeight = 0f
+
+                for (layer in layers) {
+                    layer.faceEvents.onTargetRegionChanged(targetRegion)
+                    maxWidth = max(maxWidth, layer.view.layoutParams.width.toFloat())
+                    maxHeight = max(maxHeight, layer.view.layoutParams.height.toFloat())
+                }
+
+                val lp =
+                    if (maxHeight <= 0 || maxWidth <= 0 || targetRegion == null) {
+                        // No specified width/height. Just match parent size.
+                        FrameLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT)
+                    } else {
+                        // Scale to fit in targetRegion based on largest child elements.
+                        val ratio = maxWidth / maxHeight
+                        val targetRatio = targetRegion.width() / targetRegion.height().toFloat()
+                        val scale =
+                            if (ratio > targetRatio) targetRegion.width() / maxWidth
+                            else targetRegion.height() / maxHeight
+
+                        FrameLayout.LayoutParams(
+                            (maxWidth * scale).toInt(),
+                            (maxHeight * scale).toInt(),
+                        )
+                    }
+
+                lp.gravity = Gravity.CENTER
+                view.layoutParams = lp
+                targetRegion?.let {
+                    val (xDiff, yDiff) = computeLayoutDiff(view, it, isLargeClock)
+                    view.translationX = xDiff
+                    view.translationY = yDiff
+                }
+            }
+
+            override fun onSecondaryDisplayChanged(onSecondaryDisplay: Boolean) {}
+
+            override fun onWeatherDataChanged(data: WeatherData) {
+                layers.forEach { it.events.onWeatherDataChanged(data) }
+            }
+
+            override fun onAlarmDataChanged(data: AlarmData) {
+                layers.forEach { it.events.onAlarmDataChanged(data) }
+            }
+
+            override fun onZenDataChanged(data: ZenData) {
+                layers.forEach { it.events.onZenDataChanged(data) }
+            }
+        }
+
+    override val animations =
+        object : ClockAnimations {
+            override fun enter() {
+                layers.forEach { it.animations.enter() }
+            }
+
+            override fun doze(fraction: Float) {
+                layers.forEach { it.animations.doze(fraction) }
+            }
+
+            override fun fold(fraction: Float) {
+                layers.forEach { it.animations.fold(fraction) }
+            }
+
+            override fun charge() {
+                layers.forEach { it.animations.charge() }
+            }
+
+            override fun onPickerCarouselSwiping(swipingFraction: Float) {
+                face.pickerScale?.let {
+                    view.scaleX = swipingFraction * (1 - it.scaleX) + it.scaleX
+                    view.scaleY = swipingFraction * (1 - it.scaleY) + it.scaleY
+                }
+                if (!(view is DigitalClockFaceView && view.isAlignedWithScreen())) {
+                    val topMargin = getKeyguardLargeClockTopMargin(assets)
+                    view.translationY = topMargin / 2F * swipingFraction
+                }
+                layers.forEach { it.animations.onPickerCarouselSwiping(swipingFraction) }
+                view.invalidate()
+            }
+
+            override fun onPositionUpdated(fromLeft: Int, direction: Int, fraction: Float) {
+                layers.forEach { it.animations.onPositionUpdated(fromLeft, direction, fraction) }
+            }
+
+            override fun onPositionUpdated(distance: Float, fraction: Float) {
+                layers.forEach { it.animations.onPositionUpdated(distance, fraction) }
+            }
+        }
+
+    private fun getTickRate(): ClockTickRate {
+        var tickRate = ClockTickRate.PER_MINUTE
+        for (layer in layers) {
+            if (layer.config.tickRate.value < tickRate.value) {
+                tickRate = layer.config.tickRate
+            }
+        }
+        return tickRate
+    }
+
+    private fun getKeyguardLargeClockTopMargin(assets: AssetLoader): Int {
+        val topMarginRes =
+            assets.resolveResourceId(null, "dimen", "keyguard_large_clock_top_margin")
+        if (topMarginRes != null) {
+            val (res, id) = topMarginRes
+            return res.getDimensionPixelSize(id)
+        }
+        return 0
+    }
+}
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/SimpleClockLayerController.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/SimpleClockLayerController.kt
new file mode 100644
index 0000000..f71543e
--- /dev/null
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/SimpleClockLayerController.kt
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.shared.clocks
+
+import android.content.Context
+import android.view.View
+import androidx.annotation.VisibleForTesting
+import com.android.systemui.log.core.MessageBuffer
+import com.android.systemui.plugins.clocks.ClockAnimations
+import com.android.systemui.plugins.clocks.ClockEvents
+import com.android.systemui.plugins.clocks.ClockFaceConfig
+import com.android.systemui.plugins.clocks.ClockFaceEvents
+import com.android.systemui.shared.clocks.view.SimpleDigitalClockTextView
+import kotlin.reflect.KClass
+
+typealias LayerControllerConstructor =
+    (
+        ctx: Context,
+        assets: AssetLoader,
+        layer: ClockLayer,
+        isLargeClock: Boolean,
+        messageBuffer: MessageBuffer,
+    ) -> SimpleClockLayerController
+
+interface SimpleClockLayerController {
+    val view: View
+    val events: ClockEvents
+    val animations: ClockAnimations
+    val faceEvents: ClockFaceEvents
+    val config: ClockFaceConfig
+
+    @VisibleForTesting var fakeTimeMills: Long?
+
+    // Called immediately after either onColorPaletteChanged or onSeedColorChanged is called.
+    // Provided for convience to not duplicate color update logic after state updated.
+    fun updateColors() {}
+
+    companion object Factory {
+        val constructorMap = mutableMapOf<Pair<KClass<*>, KClass<*>?>, LayerControllerConstructor>()
+
+        internal inline fun <reified TLayer> registerConstructor(
+            noinline constructor: LayerControllerConstructor,
+        ) where TLayer : ClockLayer {
+            constructorMap[Pair(TLayer::class, null)] = constructor
+        }
+
+        inline fun <reified TLayer, reified TStyle> registerTextConstructor(
+            noinline constructor: LayerControllerConstructor,
+        ) where TLayer : ClockLayer, TStyle : TextStyle {
+            constructorMap[Pair(TLayer::class, TStyle::class)] = constructor
+        }
+
+        init {
+            registerConstructor<ComposedDigitalHandLayer>(::ComposedDigitalLayerController)
+            registerTextConstructor<DigitalHandLayer, FontTextStyle>(::createSimpleDigitalLayer)
+        }
+
+        private fun createSimpleDigitalLayer(
+            ctx: Context,
+            assets: AssetLoader,
+            layer: ClockLayer,
+            isLargeClock: Boolean,
+            messageBuffer: MessageBuffer
+        ): SimpleClockLayerController {
+            val view = SimpleDigitalClockTextView(ctx, messageBuffer)
+            return SimpleDigitalHandLayerController(
+                ctx,
+                assets,
+                layer as DigitalHandLayer,
+                view,
+                messageBuffer
+            )
+        }
+
+        fun create(
+            ctx: Context,
+            assets: AssetLoader,
+            layer: ClockLayer,
+            isLargeClock: Boolean,
+            messageBuffer: MessageBuffer
+        ): SimpleClockLayerController {
+            val styleClass = if (layer is DigitalHandLayer) layer.style::class else null
+            val key = Pair(layer::class, styleClass)
+            return constructorMap[key]?.invoke(ctx, assets, layer, isLargeClock, messageBuffer)
+                ?: throw IllegalArgumentException("Unrecognized ClockLayer type: $key")
+        }
+    }
+}
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/SimpleClockRelativeLayout.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/SimpleClockRelativeLayout.kt
new file mode 100644
index 0000000..6e1b9aa
--- /dev/null
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/SimpleClockRelativeLayout.kt
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.shared.clocks
+
+import android.content.Context
+import android.view.View.MeasureSpec.EXACTLY
+import android.widget.RelativeLayout
+import androidx.core.view.children
+import com.android.systemui.shared.clocks.view.SimpleDigitalClockView
+
+class SimpleClockRelativeLayout(context: Context, val faceLayout: DigitalFaceLayout?) :
+    RelativeLayout(context) {
+    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
+        // For migrate_clocks_to_blueprint, mode is EXACTLY
+        // when the flag is turned off, we won't execute this codes
+        if (MeasureSpec.getMode(heightMeasureSpec) == EXACTLY) {
+            if (
+                faceLayout == DigitalFaceLayout.TWO_PAIRS_VERTICAL ||
+                    faceLayout == DigitalFaceLayout.FOUR_DIGITS_ALIGN_CENTER
+            ) {
+                val constrainedHeight = MeasureSpec.getSize(heightMeasureSpec) / 2F
+                children.forEach {
+                    // The assumption here is the height of text view is linear to font size
+                    (it as SimpleDigitalClockView).applyTextSize(
+                        constrainedHeight,
+                        constrainedByHeight = true,
+                    )
+                }
+            }
+        }
+        super.onMeasure(widthMeasureSpec, heightMeasureSpec)
+    }
+}
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/SimpleDigitalHandLayerController.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/SimpleDigitalHandLayerController.kt
new file mode 100644
index 0000000..a3240f8
--- /dev/null
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/SimpleDigitalHandLayerController.kt
@@ -0,0 +1,328 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.shared.clocks
+
+import android.content.Context
+import android.content.res.Resources
+import android.graphics.Rect
+import android.view.View
+import android.view.ViewGroup
+import android.widget.RelativeLayout
+import androidx.annotation.VisibleForTesting
+import com.android.systemui.customization.R
+import com.android.systemui.log.core.Logger
+import com.android.systemui.log.core.MessageBuffer
+import com.android.systemui.plugins.clocks.AlarmData
+import com.android.systemui.plugins.clocks.ClockAnimations
+import com.android.systemui.plugins.clocks.ClockEvents
+import com.android.systemui.plugins.clocks.ClockFaceConfig
+import com.android.systemui.plugins.clocks.ClockFaceEvents
+import com.android.systemui.plugins.clocks.ClockReactiveSetting
+import com.android.systemui.plugins.clocks.WeatherData
+import com.android.systemui.plugins.clocks.ZenData
+import com.android.systemui.shared.clocks.view.SimpleDigitalClockView
+import java.util.Locale
+import java.util.TimeZone
+
+private val TAG = SimpleDigitalHandLayerController::class.simpleName!!
+
+open class SimpleDigitalHandLayerController<T>(
+    private val ctx: Context,
+    private val assets: AssetLoader,
+    private val layer: DigitalHandLayer,
+    override val view: T,
+    messageBuffer: MessageBuffer,
+) : SimpleClockLayerController where T : View, T : SimpleDigitalClockView {
+    private val logger = Logger(messageBuffer, TAG)
+    val timespec = DigitalTimespecHandler(layer.timespec, layer.dateTimeFormat)
+
+    @VisibleForTesting
+    fun hasLeadingZero() = layer.dateTimeFormat.startsWith("hh") || timespec.is24Hr
+
+    @VisibleForTesting
+    override var fakeTimeMills: Long?
+        get() = timespec.fakeTimeMills
+        set(value) {
+            timespec.fakeTimeMills = value
+        }
+
+    override val config = ClockFaceConfig()
+    var dozeState: DefaultClockController.AnimationState? = null
+    var isRegionDark: Boolean = true
+
+    init {
+        view.layoutParams =
+            RelativeLayout.LayoutParams(
+                ViewGroup.LayoutParams.WRAP_CONTENT,
+                ViewGroup.LayoutParams.WRAP_CONTENT
+            )
+        if (layer.alignment != null) {
+            layer.alignment.verticalAlignment?.let { view.verticalAlignment = it }
+            layer.alignment.horizontalAlignment?.let { view.horizontalAlignment = it }
+        }
+        view.applyStyles(assets, layer.style, layer.aodStyle)
+        view.id =
+            ctx.resources.getIdentifier(
+                generateDigitalLayerIdString(layer),
+                "id",
+                ctx.getPackageName(),
+            )
+    }
+
+    fun applyLayout(layout: DigitalFaceLayout?) {
+        when (layout) {
+            DigitalFaceLayout.FOUR_DIGITS_ALIGN_CENTER,
+            DigitalFaceLayout.FOUR_DIGITS_HORIZONTAL -> applyFourDigitsLayout(layout)
+            DigitalFaceLayout.TWO_PAIRS_HORIZONTAL,
+            DigitalFaceLayout.TWO_PAIRS_VERTICAL -> applyTwoPairsLayout(layout)
+            else -> {
+                // one view always use FrameLayout
+                // no need to change here
+            }
+        }
+        applyMargin()
+    }
+
+    private fun applyMargin() {
+        if (view.layoutParams is RelativeLayout.LayoutParams) {
+            val lp = view.layoutParams as RelativeLayout.LayoutParams
+            layer.marginRatio?.let {
+                lp.setMargins(
+                    /* left = */ (it.left * view.measuredWidth).toInt(),
+                    /* top = */ (it.top * view.measuredHeight).toInt(),
+                    /* right = */ (it.right * view.measuredWidth).toInt(),
+                    /* bottom = */ (it.bottom * view.measuredHeight).toInt(),
+                )
+            }
+            view.layoutParams = lp
+        }
+    }
+
+    private fun applyTwoPairsLayout(twoPairsLayout: DigitalFaceLayout) {
+        val lp = view.layoutParams as RelativeLayout.LayoutParams
+        lp.addRule(RelativeLayout.TEXT_ALIGNMENT_CENTER)
+        if (twoPairsLayout == DigitalFaceLayout.TWO_PAIRS_HORIZONTAL) {
+            when (view.id) {
+                R.id.HOUR_DIGIT_PAIR -> {
+                    lp.addRule(RelativeLayout.CENTER_VERTICAL)
+                    lp.addRule(RelativeLayout.ALIGN_PARENT_START)
+                }
+                R.id.MINUTE_DIGIT_PAIR -> {
+                    lp.addRule(RelativeLayout.CENTER_VERTICAL)
+                    lp.addRule(RelativeLayout.END_OF, R.id.HOUR_DIGIT_PAIR)
+                }
+                else -> {
+                    throw Exception("cannot apply two pairs layout to view ${view.id}")
+                }
+            }
+        } else {
+            when (view.id) {
+                R.id.HOUR_DIGIT_PAIR -> {
+                    lp.addRule(RelativeLayout.CENTER_HORIZONTAL)
+                    lp.addRule(RelativeLayout.ALIGN_PARENT_TOP)
+                }
+                R.id.MINUTE_DIGIT_PAIR -> {
+                    lp.addRule(RelativeLayout.CENTER_HORIZONTAL)
+                    lp.addRule(RelativeLayout.BELOW, R.id.HOUR_DIGIT_PAIR)
+                }
+                else -> {
+                    throw Exception("cannot apply two pairs layout to view ${view.id}")
+                }
+            }
+        }
+        view.layoutParams = lp
+    }
+
+    private fun applyFourDigitsLayout(fourDigitsfaceLayout: DigitalFaceLayout) {
+        val lp = view.layoutParams as RelativeLayout.LayoutParams
+        when (fourDigitsfaceLayout) {
+            DigitalFaceLayout.FOUR_DIGITS_ALIGN_CENTER -> {
+                when (view.id) {
+                    R.id.HOUR_FIRST_DIGIT -> {
+                        lp.addRule(RelativeLayout.ALIGN_PARENT_START)
+                        lp.addRule(RelativeLayout.ALIGN_PARENT_TOP)
+                    }
+                    R.id.HOUR_SECOND_DIGIT -> {
+                        lp.addRule(RelativeLayout.END_OF, R.id.HOUR_FIRST_DIGIT)
+                        lp.addRule(RelativeLayout.ALIGN_TOP, R.id.HOUR_FIRST_DIGIT)
+                    }
+                    R.id.MINUTE_FIRST_DIGIT -> {
+                        lp.addRule(RelativeLayout.ALIGN_START, R.id.HOUR_FIRST_DIGIT)
+                        lp.addRule(RelativeLayout.BELOW, R.id.HOUR_FIRST_DIGIT)
+                    }
+                    R.id.MINUTE_SECOND_DIGIT -> {
+                        lp.addRule(RelativeLayout.ALIGN_START, R.id.HOUR_SECOND_DIGIT)
+                        lp.addRule(RelativeLayout.BELOW, R.id.HOUR_SECOND_DIGIT)
+                    }
+                    else -> {
+                        throw Exception("cannot apply four digits layout to view ${view.id}")
+                    }
+                }
+            }
+            DigitalFaceLayout.FOUR_DIGITS_HORIZONTAL -> {
+                when (view.id) {
+                    R.id.HOUR_FIRST_DIGIT -> {
+                        lp.addRule(RelativeLayout.CENTER_VERTICAL)
+                        lp.addRule(RelativeLayout.ALIGN_PARENT_START)
+                    }
+                    R.id.HOUR_SECOND_DIGIT -> {
+                        lp.addRule(RelativeLayout.CENTER_VERTICAL)
+                        lp.addRule(RelativeLayout.END_OF, R.id.HOUR_FIRST_DIGIT)
+                    }
+                    R.id.MINUTE_FIRST_DIGIT -> {
+                        lp.addRule(RelativeLayout.CENTER_VERTICAL)
+                        lp.addRule(RelativeLayout.END_OF, R.id.HOUR_SECOND_DIGIT)
+                    }
+                    R.id.MINUTE_SECOND_DIGIT -> {
+                        lp.addRule(RelativeLayout.CENTER_VERTICAL)
+                        lp.addRule(RelativeLayout.END_OF, R.id.MINUTE_FIRST_DIGIT)
+                    }
+                    else -> {
+                        throw Exception("cannot apply FOUR_DIGITS_HORIZONTAL to view ${view.id}")
+                    }
+                }
+            }
+            else -> {
+                throw IllegalArgumentException(
+                    "applyFourDigitsLayout function should not " +
+                        "have parameters as ${layer.faceLayout}"
+                )
+            }
+        }
+        if (lp == view.layoutParams) {
+            return
+        }
+        view.layoutParams = lp
+    }
+
+    fun refreshTime() {
+        timespec.updateTime()
+        val text = timespec.getDigitString()
+        if (view.text != text) {
+            view.text = text
+            view.refreshTime()
+            logger.d({ "refreshTime: new text=$str1" }) { str1 = text }
+        }
+    }
+
+    override val events =
+        object : ClockEvents {
+            override var isReactiveTouchInteractionEnabled = false
+
+            override fun onLocaleChanged(locale: Locale) {
+                timespec.updateLocale(locale)
+                refreshTime()
+            }
+
+            /** Call whenever the text time format changes (12hr vs 24hr) */
+            override fun onTimeFormatChanged(is24Hr: Boolean) {
+                timespec.is24Hr = is24Hr
+                refreshTime()
+            }
+
+            override fun onTimeZoneChanged(timeZone: TimeZone) {
+                timespec.timeZone = timeZone
+                refreshTime()
+            }
+
+            override fun onColorPaletteChanged(resources: Resources) {}
+
+            override fun onSeedColorChanged(seedColor: Int?) {}
+
+            override fun onWeatherDataChanged(data: WeatherData) {}
+
+            override fun onAlarmDataChanged(data: AlarmData) {}
+
+            override fun onZenDataChanged(data: ZenData) {}
+
+            override fun onReactiveAxesChanged(axes: List<ClockReactiveSetting>) {}
+        }
+
+    override fun updateColors() {
+        view.updateColors(assets, isRegionDark)
+        refreshTime()
+    }
+
+    override val animations =
+        object : ClockAnimations {
+            override fun enter() {
+                applyLayout(layer.faceLayout)
+                refreshTime()
+            }
+
+            override fun doze(fraction: Float) {
+                if (dozeState == null) {
+                    dozeState = DefaultClockController.AnimationState(fraction)
+                    view.animateDoze(dozeState!!.isActive, false)
+                } else {
+                    val (hasChanged, hasJumped) = dozeState!!.update(fraction)
+                    if (hasChanged) view.animateDoze(dozeState!!.isActive, !hasJumped)
+                }
+                view.dozeFraction = fraction
+            }
+
+            override fun fold(fraction: Float) {
+                applyLayout(layer.faceLayout)
+                refreshTime()
+            }
+
+            override fun charge() {
+                view.animateCharge()
+            }
+
+            override fun onPickerCarouselSwiping(swipingFraction: Float) {}
+
+            override fun onPositionUpdated(fromLeft: Int, direction: Int, fraction: Float) {}
+
+            override fun onPositionUpdated(distance: Float, fraction: Float) {}
+        }
+
+    override val faceEvents =
+        object : ClockFaceEvents {
+            override fun onTimeTick() {
+                refreshTime()
+                if (
+                    layer.timespec == DigitalTimespec.TIME_FULL_FORMAT ||
+                        layer.timespec == DigitalTimespec.DATE_FORMAT
+                ) {
+                    view.contentDescription = timespec.getContentDescription()
+                }
+            }
+
+            override fun onFontSettingChanged(fontSizePx: Float) {
+                view.applyTextSize(fontSizePx)
+                applyMargin()
+            }
+
+            override fun onRegionDarknessChanged(isRegionDark: Boolean) {
+                this@SimpleDigitalHandLayerController.isRegionDark = isRegionDark
+                updateColors()
+            }
+
+            override fun onTargetRegionChanged(targetRegion: Rect?) {}
+
+            override fun onSecondaryDisplayChanged(onSecondaryDisplay: Boolean) {}
+        }
+
+    companion object {
+        private val DEFAULT_LIGHT_COLOR = "@android:color/system_accent1_100+0"
+        private val DEFAULT_DARK_COLOR = "@android:color/system_accent2_600+0"
+
+        fun getDefaultColor(assets: AssetLoader, isRegionDark: Boolean) =
+            assets.readColor(if (isRegionDark) DEFAULT_LIGHT_COLOR else DEFAULT_DARK_COLOR)
+    }
+}
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/TimespecHandler.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/TimespecHandler.kt
new file mode 100644
index 0000000..ed6a403
--- /dev/null
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/TimespecHandler.kt
@@ -0,0 +1,161 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.shared.clocks
+
+import android.icu.text.DateFormat
+import android.icu.text.SimpleDateFormat
+import android.icu.util.TimeZone as IcuTimeZone
+import android.icu.util.ULocale
+import androidx.annotation.VisibleForTesting
+import java.util.Calendar
+import java.util.Locale
+import java.util.TimeZone
+
+open class TimespecHandler(
+    val cal: Calendar,
+) {
+    var timeZone: TimeZone
+        get() = cal.timeZone
+        set(value) {
+            cal.timeZone = value
+            onTimeZoneChanged()
+        }
+
+    @VisibleForTesting var fakeTimeMills: Long? = null
+
+    fun updateTime() {
+        var timeMs = fakeTimeMills ?: System.currentTimeMillis()
+        cal.timeInMillis = (timeMs * TIME_TRAVEL_SCALE).toLong()
+    }
+
+    protected open fun onTimeZoneChanged() {}
+
+    companion object {
+        // Modifying this will cause the clock to run faster or slower. This is a useful way of
+        // manually checking that clocks are correctly animating through time.
+        private const val TIME_TRAVEL_SCALE = 1.0
+    }
+}
+
+class DigitalTimespecHandler(
+    val timespec: DigitalTimespec,
+    private val timeFormat: String,
+    cal: Calendar = Calendar.getInstance(),
+) : TimespecHandler(cal) {
+    var is24Hr = false
+        set(value) {
+            field = value
+            applyPattern()
+        }
+
+    private var dateFormat = updateSimpleDateFormat(Locale.getDefault())
+    private var contentDescriptionFormat = getContentDescriptionFormat(Locale.getDefault())
+
+    init {
+        applyPattern()
+    }
+
+    override fun onTimeZoneChanged() {
+        dateFormat.timeZone = IcuTimeZone.getTimeZone(cal.timeZone.id)
+        contentDescriptionFormat?.timeZone = IcuTimeZone.getTimeZone(cal.timeZone.id)
+        applyPattern()
+    }
+
+    fun updateLocale(locale: Locale) {
+        dateFormat = updateSimpleDateFormat(locale)
+        contentDescriptionFormat = getContentDescriptionFormat(locale)
+        onTimeZoneChanged()
+    }
+
+    private fun updateSimpleDateFormat(locale: Locale): DateFormat {
+        if (
+            locale.language.equals(Locale.ENGLISH.language) ||
+                timespec != DigitalTimespec.DATE_FORMAT
+        ) {
+            // force date format in English, and time format to use format defined in json
+            return SimpleDateFormat(timeFormat, timeFormat, ULocale.forLocale(locale))
+        } else {
+            return SimpleDateFormat.getInstanceForSkeleton(timeFormat, locale)
+        }
+    }
+
+    private fun getContentDescriptionFormat(locale: Locale): DateFormat? {
+        return when (timespec) {
+            DigitalTimespec.TIME_FULL_FORMAT ->
+                SimpleDateFormat.getInstanceForSkeleton("hh:mm", locale)
+            DigitalTimespec.DATE_FORMAT ->
+                SimpleDateFormat.getInstanceForSkeleton("EEEE MMMM d", locale)
+            else -> {
+                null
+            }
+        }
+    }
+
+    private fun applyPattern() {
+        val timeFormat24Hour = timeFormat.replace("hh", "h").replace("h", "HH")
+        val format = if (is24Hr) timeFormat24Hour else timeFormat
+        if (timespec != DigitalTimespec.DATE_FORMAT) {
+            (dateFormat as SimpleDateFormat).applyPattern(format)
+            (contentDescriptionFormat as? SimpleDateFormat)?.applyPattern(
+                if (is24Hr) CONTENT_DESCRIPTION_TIME_FORMAT_24_HOUR
+                else CONTENT_DESCRIPTION_TIME_FORMAT_12_HOUR
+            )
+        }
+    }
+
+    private fun getSingleDigit(): String {
+        val isFirstDigit = timespec == DigitalTimespec.FIRST_DIGIT
+        val text = dateFormat.format(cal.time).toString()
+        return text.substring(
+            if (isFirstDigit) 0 else text.length - 1,
+            if (isFirstDigit) text.length - 1 else text.length
+        )
+    }
+
+    fun getDigitString(): String {
+        return when (timespec) {
+            DigitalTimespec.FIRST_DIGIT,
+            DigitalTimespec.SECOND_DIGIT -> getSingleDigit()
+            DigitalTimespec.DIGIT_PAIR -> {
+                dateFormat.format(cal.time).toString()
+            }
+            DigitalTimespec.TIME_FULL_FORMAT -> {
+                dateFormat.format(cal.time).toString()
+            }
+            DigitalTimespec.DATE_FORMAT -> {
+                dateFormat.format(cal.time).toString().uppercase()
+            }
+        }
+    }
+
+    fun getContentDescription(): String? {
+        return when (timespec) {
+            DigitalTimespec.TIME_FULL_FORMAT,
+            DigitalTimespec.DATE_FORMAT -> {
+                contentDescriptionFormat?.format(cal.time).toString()
+            }
+            else -> {
+                return null
+            }
+        }
+    }
+
+    companion object {
+        const val CONTENT_DESCRIPTION_TIME_FORMAT_12_HOUR = "hh:mm"
+        const val CONTENT_DESCRIPTION_TIME_FORMAT_24_HOUR = "HH:mm"
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardPatternViewControllerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewControllerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardPatternViewControllerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinViewControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardPinViewControllerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinViewControllerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardPinViewControllerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityViewFlipperControllerTest.java b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardSecurityViewFlipperControllerTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityViewFlipperControllerTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardSecurityViewFlipperControllerTest.java
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSimPinViewControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardSimPinViewControllerTest.kt
similarity index 97%
rename from packages/SystemUI/tests/src/com/android/keyguard/KeyguardSimPinViewControllerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardSimPinViewControllerTest.kt
index 8206c21..9cd5215 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSimPinViewControllerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardSimPinViewControllerTest.kt
@@ -85,9 +85,8 @@
         `when`(telephonyManager.createForSubscriptionId(anyInt())).thenReturn(telephonyManager)
         `when`(telephonyManager.supplyIccLockPin(anyString())).thenReturn(mock())
         simPinView =
-            LayoutInflater.from(context)
-                .inflate(R.layout.keyguard_sim_pin_view, null)
-                .requireViewById(R.id.keyguard_sim_pin_view) as KeyguardSimPinView
+            LayoutInflater.from(context).inflate(R.layout.keyguard_sim_pin_view, null)
+                as KeyguardSimPinView
         val fakeFeatureFlags = FakeFeatureFlags()
         val keyguardKeyboardInteractor = KeyguardKeyboardInteractor(FakeKeyboardRepository())
 
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSimPukViewControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardSimPukViewControllerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/keyguard/KeyguardSimPukViewControllerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardSimPukViewControllerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSliceViewControllerTest.java b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardSliceViewControllerTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/keyguard/KeyguardSliceViewControllerTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardSliceViewControllerTest.java
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/brightness/data/repository/ScreenBrightnessDisplayManagerRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/brightness/data/repository/ScreenBrightnessDisplayManagerRepositoryTest.kt
index a676c7d..0983105 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/brightness/data/repository/ScreenBrightnessDisplayManagerRepositoryTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/brightness/data/repository/ScreenBrightnessDisplayManagerRepositoryTest.kt
@@ -31,12 +31,11 @@
 import com.android.systemui.kosmos.testDispatcher
 import com.android.systemui.kosmos.testScope
 import com.android.systemui.log.core.FakeLogBuffer
-import com.android.systemui.log.table.TableLogBuffer
+import com.android.systemui.log.table.logcatTableLogBuffer
 import com.android.systemui.testKosmos
 import com.android.systemui.util.mockito.argumentCaptor
 import com.android.systemui.util.mockito.capture
 import com.android.systemui.util.mockito.eq
-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
@@ -78,7 +77,7 @@
                 displayId,
                 displayManager,
                 FakeLogBuffer.Factory.create(),
-                mock<TableLogBuffer>(),
+                logcatTableLogBuffer(kosmos, "screenBrightness"),
                 kosmos.applicationCoroutineScope,
                 kosmos.testDispatcher,
             )
@@ -163,7 +162,7 @@
 
                 changeBrightnessInfoAndNotify(
                     BrightnessInfo(0.5f, 0.1f, 0.7f),
-                    listenerCaptor.value
+                    listenerCaptor.value,
                 )
                 runCurrent()
 
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/brightness/domain/interactor/ScreenBrightnessInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/brightness/domain/interactor/ScreenBrightnessInteractorTest.kt
index b6616bf..18e7a7e 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/brightness/domain/interactor/ScreenBrightnessInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/brightness/domain/interactor/ScreenBrightnessInteractorTest.kt
@@ -27,9 +27,8 @@
 import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.kosmos.applicationCoroutineScope
 import com.android.systemui.kosmos.testScope
-import com.android.systemui.log.table.TableLogBuffer
+import com.android.systemui.log.table.logcatTableLogBuffer
 import com.android.systemui.testKosmos
-import com.android.systemui.util.mockito.mock
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.test.runCurrent
@@ -49,7 +48,7 @@
             ScreenBrightnessInteractor(
                 screenBrightnessRepository,
                 applicationCoroutineScope,
-                mock<TableLogBuffer>()
+                logcatTableLogBuffer(this, "screenBrightness"),
             )
         }
 
@@ -112,7 +111,7 @@
                     BrightnessUtils.convertGammaToLinearFloat(
                         gammaBrightness,
                         min.floatValue,
-                        max.floatValue
+                        max.floatValue,
                     )
                 assertThat(temporaryBrightness!!.floatValue)
                     .isWithin(1e-5f)
@@ -136,7 +135,7 @@
                     BrightnessUtils.convertGammaToLinearFloat(
                         gammaBrightness,
                         min.floatValue,
-                        max.floatValue
+                        max.floatValue,
                     )
                 assertThat(brightness!!.floatValue).isWithin(1e-5f).of(expectedBrightness)
             }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/brightness/ui/viewmodel/BrightnessSliderViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/brightness/ui/viewmodel/BrightnessSliderViewModelTest.kt
index 8402676..18f33e4 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/brightness/ui/viewmodel/BrightnessSliderViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/brightness/ui/viewmodel/BrightnessSliderViewModelTest.kt
@@ -29,6 +29,7 @@
 import com.android.systemui.common.shared.model.Icon
 import com.android.systemui.common.shared.model.Text
 import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.haptics.slider.sliderHapticsViewModelFactory
 import com.android.systemui.kosmos.applicationCoroutineScope
 import com.android.systemui.kosmos.testScope
 import com.android.systemui.res.R
@@ -54,6 +55,7 @@
                 screenBrightnessInteractor,
                 brightnessPolicyEnforcementInteractor,
                 applicationCoroutineScope,
+                sliderHapticsViewModelFactory,
             )
         }
 
@@ -61,7 +63,7 @@
     fun setUp() {
         kosmos.fakeScreenBrightnessRepository.setMinMaxBrightness(
             LinearBrightness(minBrightness),
-            LinearBrightness(maxBrightness)
+            LinearBrightness(maxBrightness),
         )
     }
 
@@ -79,7 +81,7 @@
                         BrightnessUtils.convertLinearToGammaFloat(
                             brightness,
                             minBrightness,
-                            maxBrightness
+                            maxBrightness,
                         )
                     )
 
@@ -91,7 +93,7 @@
                         BrightnessUtils.convertLinearToGammaFloat(
                             brightness,
                             minBrightness,
-                            maxBrightness
+                            maxBrightness,
                         )
                     )
             }
@@ -122,7 +124,7 @@
                     BrightnessUtils.convertGammaToLinearFloat(
                         newBrightness,
                         minBrightness,
-                        maxBrightness
+                        maxBrightness,
                     )
                 val drag = Drag.Dragging(GammaBrightness(newBrightness))
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardOverlaySuppressionControllerImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/clipboardoverlay/ClipboardOverlaySuppressionControllerImplTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardOverlaySuppressionControllerImplTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/clipboardoverlay/ClipboardOverlaySuppressionControllerImplTest.kt
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/repository/CommunalMediaRepositoryImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/repository/CommunalMediaRepositoryImplTest.kt
index dd5ad17..2b0928f 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/repository/CommunalMediaRepositoryImplTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/repository/CommunalMediaRepositoryImplTest.kt
@@ -21,7 +21,7 @@
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.kosmos.testScope
-import com.android.systemui.log.table.TableLogBuffer
+import com.android.systemui.log.table.logcatTableLogBuffer
 import com.android.systemui.media.controls.domain.pipeline.MediaDataManager
 import com.android.systemui.media.controls.shared.model.MediaData
 import com.android.systemui.testKosmos
@@ -44,7 +44,6 @@
 class CommunalMediaRepositoryImplTest : SysuiTestCase() {
     private val mediaDataManager = mock<MediaDataManager>()
     private val mediaData = mock<MediaData>()
-    private val tableLogBuffer = mock<TableLogBuffer>()
 
     private lateinit var underTest: CommunalMediaRepositoryImpl
 
@@ -52,14 +51,11 @@
 
     private val kosmos = testKosmos()
     private val testScope = kosmos.testScope
+    private val tableLogBuffer = logcatTableLogBuffer(kosmos, "CommunalMediaRepositoryImplTest")
 
     @Before
     fun setUp() {
-        underTest =
-            CommunalMediaRepositoryImpl(
-                mediaDataManager,
-                tableLogBuffer,
-            )
+        underTest = CommunalMediaRepositoryImpl(mediaDataManager, tableLogBuffer)
     }
 
     @Test
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/repository/CommunalWidgetRepositoryImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/repository/CommunalWidgetRepositoryImplTest.kt
index 3d30ecc..8ae9d2e 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/repository/CommunalWidgetRepositoryImplTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/repository/CommunalWidgetRepositoryImplTest.kt
@@ -25,8 +25,10 @@
 import android.graphics.Bitmap
 import android.os.UserHandle
 import android.os.userManager
+import android.platform.test.annotations.EnableFlags
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
+import com.android.systemui.Flags.FLAG_COMMUNAL_WIDGET_RESIZING
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.common.data.repository.fakePackageChangeRepository
 import com.android.systemui.common.shared.model.PackageInstallSession
@@ -156,6 +158,7 @@
                         appWidgetId = communalWidgetItemEntry.widgetId,
                         providerInfo = providerInfoA,
                         rank = communalItemRankEntry.rank,
+                        spanY = communalWidgetItemEntry.spanY,
                     )
                 )
 
@@ -188,11 +191,13 @@
                         appWidgetId = 1,
                         providerInfo = providerInfoA,
                         rank = 1,
+                        spanY = 3,
                     ),
                     CommunalWidgetContentModel.Available(
                         appWidgetId = 2,
                         providerInfo = providerInfoB,
                         rank = 2,
+                        spanY = 3,
                     ),
                 )
         }
@@ -219,11 +224,13 @@
                         appWidgetId = 1,
                         providerInfo = providerInfoA,
                         rank = 1,
+                        spanY = 3,
                     ),
                     CommunalWidgetContentModel.Available(
                         appWidgetId = 2,
                         providerInfo = providerInfoB,
                         rank = 2,
+                        spanY = 3,
                     ),
                 )
 
@@ -238,11 +245,13 @@
                         // Verify that provider info updated
                         providerInfo = providerInfoC,
                         rank = 1,
+                        spanY = 3,
                     ),
                     CommunalWidgetContentModel.Available(
                         appWidgetId = 2,
                         providerInfo = providerInfoB,
                         rank = 2,
+                        spanY = 3,
                     ),
                 )
         }
@@ -681,6 +690,7 @@
                         appWidgetId = 1,
                         providerInfo = providerInfoA,
                         rank = 1,
+                        spanY = 3,
                     ),
                     CommunalWidgetContentModel.Pending(
                         appWidgetId = 2,
@@ -688,6 +698,7 @@
                         componentName = ComponentName("pk_2", "cls_2"),
                         icon = fakeIcon,
                         user = mainUser,
+                        spanY = 3,
                     ),
                 )
         }
@@ -723,6 +734,7 @@
                         componentName = ComponentName("pk_1", "cls_1"),
                         icon = fakeIcon,
                         user = mainUser,
+                        spanY = 3,
                     )
                 )
 
@@ -740,20 +752,23 @@
                         appWidgetId = 1,
                         providerInfo = providerInfoA,
                         rank = 1,
+                        spanY = 3,
                     )
                 )
         }
 
     @Test
+    @EnableFlags(FLAG_COMMUNAL_WIDGET_RESIZING)
     fun updateWidgetSpanY_updatesWidgetInDaoAndRequestsBackup() =
         testScope.runTest {
             val widgetId = 1
             val newSpanY = 6
+            val widgetIdToRankMap = emptyMap<Int, Int>()
 
-            underTest.updateWidgetSpanY(widgetId, newSpanY)
+            underTest.resizeWidget(widgetId, newSpanY, widgetIdToRankMap)
             runCurrent()
 
-            verify(communalWidgetDao).updateWidgetSpanY(widgetId, newSpanY)
+            verify(communalWidgetDao).resizeWidget(widgetId, newSpanY, widgetIdToRankMap)
             verify(backupManager).dataChanged()
         }
 
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt
index b96e40f..611a61a6 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt
@@ -24,6 +24,7 @@
 import android.os.UserHandle
 import android.os.UserManager
 import android.os.userManager
+import android.platform.test.annotations.EnableFlags
 import android.provider.Settings
 import android.provider.Settings.Secure.HUB_MODE_TUTORIAL_COMPLETED
 import android.widget.RemoteViews
@@ -31,6 +32,7 @@
 import androidx.test.filters.SmallTest
 import com.android.compose.animation.scene.ObservableTransitionState
 import com.android.systemui.Flags.FLAG_COMMUNAL_HUB
+import com.android.systemui.Flags.FLAG_COMMUNAL_WIDGET_RESIZING
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.broadcast.broadcastDispatcher
 import com.android.systemui.communal.data.model.CommunalSmartspaceTimer
@@ -1078,6 +1080,108 @@
             assertThat(managedProfileController.isWorkModeEnabled()).isTrue()
         }
 
+    @Test
+    @EnableFlags(FLAG_COMMUNAL_WIDGET_RESIZING)
+    fun resizeWidget_withoutUpdatingOrder() =
+        testScope.runTest {
+            val userInfos = listOf(MAIN_USER_INFO)
+            userRepository.setUserInfos(userInfos)
+            userTracker.set(userInfos = userInfos, selectedUserIndex = 0)
+            runCurrent()
+
+            // Widgets available.
+            widgetRepository.addWidget(
+                appWidgetId = 1,
+                userId = MAIN_USER_INFO.id,
+                rank = 0,
+                spanY = CommunalContentSize.HALF.span,
+            )
+            widgetRepository.addWidget(
+                appWidgetId = 2,
+                userId = MAIN_USER_INFO.id,
+                rank = 1,
+                spanY = CommunalContentSize.HALF.span,
+            )
+            widgetRepository.addWidget(
+                appWidgetId = 3,
+                userId = MAIN_USER_INFO.id,
+                rank = 2,
+                spanY = CommunalContentSize.HALF.span,
+            )
+
+            val widgetContent by collectLastValue(underTest.widgetContent)
+
+            assertThat(widgetContent?.map { it.appWidgetId to it.size })
+                .containsExactly(
+                    1 to CommunalContentSize.HALF,
+                    2 to CommunalContentSize.HALF,
+                    3 to CommunalContentSize.HALF,
+                )
+                .inOrder()
+
+            underTest.resizeWidget(2, CommunalContentSize.FULL.span, emptyMap())
+
+            // Widget 2 should have been resized to FULL
+            assertThat(widgetContent?.map { it.appWidgetId to it.size })
+                .containsExactly(
+                    1 to CommunalContentSize.HALF,
+                    2 to CommunalContentSize.FULL,
+                    3 to CommunalContentSize.HALF,
+                )
+                .inOrder()
+        }
+
+    @Test
+    @EnableFlags(FLAG_COMMUNAL_WIDGET_RESIZING)
+    fun resizeWidget_andUpdateOrder() =
+        testScope.runTest {
+            val userInfos = listOf(MAIN_USER_INFO)
+            userRepository.setUserInfos(userInfos)
+            userTracker.set(userInfos = userInfos, selectedUserIndex = 0)
+            runCurrent()
+
+            // Widgets available.
+            widgetRepository.addWidget(
+                appWidgetId = 1,
+                userId = MAIN_USER_INFO.id,
+                rank = 0,
+                spanY = CommunalContentSize.HALF.span,
+            )
+            widgetRepository.addWidget(
+                appWidgetId = 2,
+                userId = MAIN_USER_INFO.id,
+                rank = 1,
+                spanY = CommunalContentSize.HALF.span,
+            )
+            widgetRepository.addWidget(
+                appWidgetId = 3,
+                userId = MAIN_USER_INFO.id,
+                rank = 2,
+                spanY = CommunalContentSize.HALF.span,
+            )
+
+            val widgetContent by collectLastValue(underTest.widgetContent)
+
+            assertThat(widgetContent?.map { it.appWidgetId to it.size })
+                .containsExactly(
+                    1 to CommunalContentSize.HALF,
+                    2 to CommunalContentSize.HALF,
+                    3 to CommunalContentSize.HALF,
+                )
+                .inOrder()
+
+            underTest.resizeWidget(2, CommunalContentSize.FULL.span, mapOf(2 to 0, 1 to 1))
+
+            // Widget 2 should have been resized to FULL and moved to the front of the list
+            assertThat(widgetContent?.map { it.appWidgetId to it.size })
+                .containsExactly(
+                    2 to CommunalContentSize.FULL,
+                    1 to CommunalContentSize.HALF,
+                    3 to CommunalContentSize.HALF,
+                )
+                .inOrder()
+        }
+
     private fun setKeyguardFeaturesDisabled(user: UserInfo, disabledFlags: Int) {
         whenever(kosmos.devicePolicyManager.getKeyguardDisabledFeatures(nullable(), eq(user.id)))
             .thenReturn(disabledFlags)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/ui/viewmodel/ResizeableItemFrameViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/ui/viewmodel/ResizeableItemFrameViewModelTest.kt
index e1946fc..f0d88ab 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/ui/viewmodel/ResizeableItemFrameViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/ui/viewmodel/ResizeableItemFrameViewModelTest.kt
@@ -254,6 +254,23 @@
         assertThat(resizeInfo).isEqualTo(ResizeInfo(-1, DragHandle.BOTTOM))
     }
 
+    @Test
+    fun testRowInfoBecomesNull_revertsBackToDefault() =
+        testScope.runTest {
+            val gridLayout = singleSpanGrid.copy(maxItemSpan = 3, currentRow = 1)
+            updateGridLayout(gridLayout)
+
+            val topState = underTest.topDragState
+            assertThat(topState.anchors.toList()).containsExactly(0 to 0f, -1 to -30f)
+
+            val bottomState = underTest.bottomDragState
+            assertThat(bottomState.anchors.toList()).containsExactly(0 to 0f, 1 to 30f)
+
+            updateGridLayout(gridLayout.copy(currentRow = null))
+            assertThat(topState.anchors.toList()).containsExactly(0 to 0f)
+            assertThat(bottomState.anchors.toList()).containsExactly(0 to 0f)
+        }
+
     @Test(expected = IllegalArgumentException::class)
     fun testIllegalState_maxSpanSmallerThanMinSpan() =
         testScope.runTest {
@@ -317,7 +334,7 @@
         val viewportHeightPx: Int,
         val maxItemSpan: Int,
         val minItemSpan: Int,
-        val currentRow: Int,
-        val currentSpan: Int,
+        val currentRow: Int?,
+        val currentSpan: Int?,
     )
 }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalEditModeViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalEditModeViewModelTest.kt
index 179ba22..cecc11e 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalEditModeViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalEditModeViewModelTest.kt
@@ -19,7 +19,6 @@
 import android.appwidget.AppWidgetProviderInfo
 import android.content.ActivityNotFoundException
 import android.content.ComponentName
-import android.content.Intent
 import android.content.pm.PackageManager
 import android.content.pm.UserInfo
 import android.provider.Settings
@@ -27,7 +26,6 @@
 import android.view.accessibility.AccessibilityManager
 import android.view.accessibility.accessibilityManager
 import android.widget.RemoteViews
-import androidx.activity.result.ActivityResultLauncher
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.internal.logging.UiEventLogger
@@ -88,7 +86,6 @@
     @Mock private lateinit var mediaHost: MediaHost
     @Mock private lateinit var uiEventLogger: UiEventLogger
     @Mock private lateinit var packageManager: PackageManager
-    @Mock private lateinit var activityResultLauncher: ActivityResultLauncher<Intent>
     @Mock private lateinit var metricsLogger: CommunalMetricsLogger
 
     private val kosmos = testKosmos()
@@ -117,10 +114,7 @@
         communalSceneInteractor = kosmos.communalSceneInteractor
         communalInteractor = spy(kosmos.communalInteractor)
         kosmos.fakeUserRepository.setUserInfos(listOf(MAIN_USER_INFO))
-        kosmos.fakeUserTracker.set(
-            userInfos = listOf(MAIN_USER_INFO),
-            selectedUserIndex = 0,
-        )
+        kosmos.fakeUserTracker.set(userInfos = listOf(MAIN_USER_INFO), selectedUserIndex = 0)
         kosmos.fakeFeatureFlagsClassic.set(Flags.COMMUNAL_SERVICE_ENABLED, true)
         accessibilityManager = kosmos.accessibilityManager
 
@@ -257,10 +251,13 @@
     @Test
     fun onOpenWidgetPicker_launchesWidgetPickerActivity() {
         testScope.runTest {
+            var activityStarted = false
             val success =
-                underTest.onOpenWidgetPicker(testableResources.resources, activityResultLauncher)
+                underTest.onOpenWidgetPicker(testableResources.resources) { _ ->
+                    run { activityStarted = true }
+                }
 
-            verify(activityResultLauncher).launch(any())
+            assertTrue(activityStarted)
             assertTrue(success)
         }
     }
@@ -268,14 +265,10 @@
     @Test
     fun onOpenWidgetPicker_activityLaunchThrowsException_failure() {
         testScope.runTest {
-            whenever(activityResultLauncher.launch(any()))
-                .thenThrow(ActivityNotFoundException::class.java)
-
             val success =
-                underTest.onOpenWidgetPicker(
-                    testableResources.resources,
-                    activityResultLauncher,
-                )
+                underTest.onOpenWidgetPicker(testableResources.resources) { _ ->
+                    run { throw ActivityNotFoundException() }
+                }
 
             assertFalse(success)
         }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryFaceAuthInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryFaceAuthInteractorTest.kt
index 40b2a08..a0c56b4 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryFaceAuthInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryFaceAuthInteractorTest.kt
@@ -139,7 +139,7 @@
                 TransitionStep(
                     KeyguardState.OFF,
                     KeyguardState.LOCKSCREEN,
-                    transitionState = TransitionState.STARTED
+                    transitionState = TransitionState.STARTED,
                 )
             )
 
@@ -181,7 +181,7 @@
                 TransitionStep(
                     KeyguardState.AOD,
                     KeyguardState.LOCKSCREEN,
-                    transitionState = TransitionState.STARTED
+                    transitionState = TransitionState.STARTED,
                 )
             )
 
@@ -206,7 +206,7 @@
                 TransitionStep(
                     KeyguardState.DOZING,
                     KeyguardState.LOCKSCREEN,
-                    transitionState = TransitionState.STARTED
+                    transitionState = TransitionState.STARTED,
                 )
             )
 
@@ -229,7 +229,7 @@
                 TransitionStep(
                     KeyguardState.DOZING,
                     KeyguardState.LOCKSCREEN,
-                    transitionState = TransitionState.STARTED
+                    transitionState = TransitionState.STARTED,
                 )
             )
 
@@ -244,12 +244,14 @@
     fun faceAuthLockedOutStateIsUpdatedAfterUserSwitch() =
         testScope.runTest {
             underTest.start()
+            runCurrent()
+            fakeBiometricSettingsRepository.setIsFaceAuthEnrolledAndEnabled(true)
 
             // User switching has started
             fakeUserRepository.setSelectedUserInfo(primaryUser, SelectionStatus.SELECTION_COMPLETE)
             fakeUserRepository.setSelectedUserInfo(
                 primaryUser,
-                SelectionStatus.SELECTION_IN_PROGRESS
+                SelectionStatus.SELECTION_IN_PROGRESS,
             )
             runCurrent()
 
@@ -258,7 +260,7 @@
             facePropertyRepository.setLockoutMode(secondaryUser.id, LockoutMode.NONE)
             fakeUserRepository.setSelectedUserInfo(
                 secondaryUser,
-                SelectionStatus.SELECTION_COMPLETE
+                SelectionStatus.SELECTION_COMPLETE,
             )
             runCurrent()
 
@@ -316,7 +318,7 @@
                 .isEqualTo(
                     Pair(
                         FaceAuthUiEvent.FACE_AUTH_TRIGGERED_ALTERNATE_BIOMETRIC_BOUNCER_SHOWN,
-                        false
+                        false,
                     )
                 )
         }
@@ -600,7 +602,7 @@
 
             faceAuthRepository.requestAuthenticate(
                 FaceAuthUiEvent.FACE_AUTH_UPDATED_KEYGUARD_VISIBILITY_CHANGED,
-                true
+                true,
             )
             facePropertyRepository.setCameraIno(CameraInfo("0", "1", null))
 
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayCallbackControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayCallbackControllerTest.kt
index d9dcfdc..9c6fd4b 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayCallbackControllerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayCallbackControllerTest.kt
@@ -56,6 +56,7 @@
 
         // Adding twice should not invoke twice
         reset(callback)
+        underTest.onStartDream()
         underTest.addCallback(callback)
         underTest.onWakeUp()
         verify(callback, times(1)).onWakeUp()
@@ -68,6 +69,19 @@
     }
 
     @Test
+    fun onWakeUp_multipleCalls() {
+        underTest.onStartDream()
+        assertThat(underTest.isDreaming).isEqualTo(true)
+
+        underTest.addCallback(callback)
+        underTest.onWakeUp()
+        underTest.onWakeUp()
+        underTest.onWakeUp()
+        verify(callback, times(1)).onWakeUp()
+        assertThat(underTest.isDreaming).isEqualTo(false)
+    }
+
+    @Test
     fun onStartDreamInvokesCallback() {
         underTest.addCallback(callback)
 
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayServiceTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayServiceTest.kt
index a3314e8..f5d2d42 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayServiceTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayServiceTest.kt
@@ -712,6 +712,9 @@
 
         // Verify DreamOverlayContainerViewController is destroyed.
         verify(mDreamOverlayContainerViewController).destroy()
+
+        // DreamOverlay callback receives onWakeUp.
+        verify(mDreamOverlayCallbackController).onWakeUp()
     }
 
     @Test
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/haptics/slider/SliderHapticFeedbackProviderTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/haptics/slider/SliderHapticFeedbackProviderTest.kt
index 4a80d72..28f88fe 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/haptics/slider/SliderHapticFeedbackProviderTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/haptics/slider/SliderHapticFeedbackProviderTest.kt
@@ -17,13 +17,11 @@
 package com.android.systemui.haptics.slider
 
 import android.os.VibrationEffect
-import android.view.VelocityTracker
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.haptics.fakeVibratorHelper
 import com.android.systemui.testKosmos
-import com.android.systemui.util.mockito.whenever
 import com.android.systemui.util.time.fakeSystemClock
 import kotlin.math.max
 import kotlin.test.assertEquals
@@ -31,19 +29,17 @@
 import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
-import org.mockito.Mock
-import org.mockito.MockitoAnnotations
 
 @SmallTest
 @RunWith(AndroidJUnit4::class)
 class SliderHapticFeedbackProviderTest : SysuiTestCase() {
 
-    @Mock private lateinit var velocityTracker: VelocityTracker
-
     private val kosmos = testKosmos()
 
     private val config = SliderHapticFeedbackConfig()
 
+    private val dragVelocityProvider = SliderDragVelocityProvider { config.maxVelocityToScale }
+
     private val lowTickDuration = 12 // Mocked duration of a low tick
     private val dragTextureThresholdMillis =
         lowTickDuration * config.numberOfLowTicks + config.deltaMillisForDragInterval
@@ -52,17 +48,13 @@
 
     @Before
     fun setup() {
-        MockitoAnnotations.initMocks(this)
-        whenever(velocityTracker.isAxisSupported(config.velocityAxis)).thenReturn(true)
-        whenever(velocityTracker.getAxisVelocity(config.velocityAxis))
-            .thenReturn(config.maxVelocityToScale)
 
         vibratorHelper.primitiveDurations[VibrationEffect.Composition.PRIMITIVE_LOW_TICK] =
             lowTickDuration
         sliderHapticFeedbackProvider =
             SliderHapticFeedbackProvider(
                 vibratorHelper,
-                velocityTracker,
+                dragVelocityProvider,
                 config,
                 kosmos.fakeSystemClock,
             )
@@ -75,9 +67,7 @@
                 VibrationEffect.startComposition()
                     .addPrimitive(
                         VibrationEffect.Composition.PRIMITIVE_CLICK,
-                        sliderHapticFeedbackProvider.scaleOnEdgeCollision(
-                            config.maxVelocityToScale
-                        ),
+                        sliderHapticFeedbackProvider.scaleOnEdgeCollision(config.maxVelocityToScale),
                     )
                     .compose()
 
@@ -93,7 +83,7 @@
                 VibrationEffect.startComposition()
                     .addPrimitive(
                         VibrationEffect.Composition.PRIMITIVE_CLICK,
-                        sliderHapticFeedbackProvider.scaleOnEdgeCollision(config.maxVelocityToScale)
+                        sliderHapticFeedbackProvider.scaleOnEdgeCollision(config.maxVelocityToScale),
                     )
                     .compose()
 
@@ -110,9 +100,7 @@
                 VibrationEffect.startComposition()
                     .addPrimitive(
                         VibrationEffect.Composition.PRIMITIVE_CLICK,
-                        sliderHapticFeedbackProvider.scaleOnEdgeCollision(
-                            config.maxVelocityToScale
-                        ),
+                        sliderHapticFeedbackProvider.scaleOnEdgeCollision(config.maxVelocityToScale),
                     )
                     .compose()
 
@@ -128,9 +116,7 @@
                 VibrationEffect.startComposition()
                     .addPrimitive(
                         VibrationEffect.Composition.PRIMITIVE_CLICK,
-                        sliderHapticFeedbackProvider.scaleOnEdgeCollision(
-                            config.maxVelocityToScale
-                        ),
+                        sliderHapticFeedbackProvider.scaleOnEdgeCollision(config.maxVelocityToScale),
                     )
                     .compose()
 
@@ -146,10 +132,7 @@
             // GIVEN max velocity and slider progress
             val progress = 1f
             val expectedScale =
-                sliderHapticFeedbackProvider.scaleOnDragTexture(
-                    config.maxVelocityToScale,
-                    progress,
-                )
+                sliderHapticFeedbackProvider.scaleOnDragTexture(config.maxVelocityToScale, progress)
             val ticks = VibrationEffect.startComposition()
             repeat(config.numberOfLowTicks) {
                 ticks.addPrimitive(VibrationEffect.Composition.PRIMITIVE_LOW_TICK, expectedScale)
@@ -222,10 +205,7 @@
             // GIVEN max velocity and slider progress
             val progress = 1f
             val expectedScale =
-                sliderHapticFeedbackProvider.scaleOnDragTexture(
-                    config.maxVelocityToScale,
-                    progress,
-                )
+                sliderHapticFeedbackProvider.scaleOnDragTexture(config.maxVelocityToScale, progress)
             val ticks = VibrationEffect.startComposition()
             repeat(config.numberOfLowTicks) {
                 ticks.addPrimitive(VibrationEffect.Composition.PRIMITIVE_LOW_TICK, expectedScale)
@@ -234,9 +214,7 @@
                 VibrationEffect.startComposition()
                     .addPrimitive(
                         VibrationEffect.Composition.PRIMITIVE_CLICK,
-                        sliderHapticFeedbackProvider.scaleOnEdgeCollision(
-                            config.maxVelocityToScale
-                        ),
+                        sliderHapticFeedbackProvider.scaleOnEdgeCollision(config.maxVelocityToScale),
                     )
                     .compose()
 
@@ -250,7 +228,7 @@
             // THEN there are two bookend vibrations
             assertEquals(
                 /* expected= */ 2,
-                vibratorHelper.timesVibratedWithEffect(bookendVibration)
+                vibratorHelper.timesVibratedWithEffect(bookendVibration),
             )
         }
 
@@ -260,10 +238,7 @@
             // GIVEN max velocity and slider progress
             val progress = 1f
             val expectedScale =
-                sliderHapticFeedbackProvider.scaleOnDragTexture(
-                    config.maxVelocityToScale,
-                    progress,
-                )
+                sliderHapticFeedbackProvider.scaleOnDragTexture(config.maxVelocityToScale, progress)
             val ticks = VibrationEffect.startComposition()
             repeat(config.numberOfLowTicks) {
                 ticks.addPrimitive(VibrationEffect.Composition.PRIMITIVE_LOW_TICK, expectedScale)
@@ -272,9 +247,7 @@
                 VibrationEffect.startComposition()
                     .addPrimitive(
                         VibrationEffect.Composition.PRIMITIVE_CLICK,
-                        sliderHapticFeedbackProvider.scaleOnEdgeCollision(
-                            config.maxVelocityToScale
-                        ),
+                        sliderHapticFeedbackProvider.scaleOnEdgeCollision(config.maxVelocityToScale),
                     )
                     .compose()
 
@@ -288,7 +261,7 @@
             // THEN there are two bookend vibrations
             assertEquals(
                 /* expected= */ 2,
-                vibratorHelper.timesVibratedWithEffect(bookendVibration)
+                vibratorHelper.timesVibratedWithEffect(bookendVibration),
             )
         }
 
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/haptics/slider/compose/ui/SliderHapticsViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/haptics/slider/compose/ui/SliderHapticsViewModelTest.kt
new file mode 100644
index 0000000..8693f6b
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/haptics/slider/compose/ui/SliderHapticsViewModelTest.kt
@@ -0,0 +1,177 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.haptics.slider.compose.ui
+
+import androidx.compose.foundation.gestures.Orientation
+import androidx.compose.foundation.interaction.DragInteraction
+import androidx.compose.foundation.interaction.InteractionSource
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.haptics.slider.SeekableSliderTrackerConfig
+import com.android.systemui.haptics.slider.SliderEventType
+import com.android.systemui.haptics.slider.SliderHapticFeedbackConfig
+import com.android.systemui.haptics.slider.sliderHapticsViewModelFactory
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.lifecycle.activateIn
+import com.android.systemui.testKosmos
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.asStateFlow
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class SliderHapticsViewModelTest : SysuiTestCase() {
+
+    private val kosmos = testKosmos()
+    private val testScope = kosmos.testScope
+    private val interactionSource = DragInteractionSourceTest()
+    private val underTest =
+        kosmos.sliderHapticsViewModelFactory.create(
+            interactionSource,
+            0f..1f,
+            Orientation.Horizontal,
+            SliderHapticFeedbackConfig(),
+            SeekableSliderTrackerConfig(),
+        )
+
+    @Before
+    fun setUp() {
+        underTest.activateIn(testScope)
+    }
+
+    @Test
+    fun onActivated_startsRunning() =
+        testScope.runTest {
+            // WHEN the view-model is activated
+            testScope.runCurrent()
+
+            // THEN the view-model starts running
+            assertThat(underTest.isRunning).isTrue()
+        }
+
+    @Test
+    fun onDragStart_goesToUserStartedDragging() =
+        testScope.runTest {
+            // WHEN a drag interaction starts
+            interactionSource.setDragInteraction(DragInteraction.Start())
+            runCurrent()
+
+            // THEN the current slider event type shows that the user started dragging
+            assertThat(underTest.currentSliderEventType)
+                .isEqualTo(SliderEventType.STARTED_TRACKING_TOUCH)
+        }
+
+    @Test
+    fun onValueChange_whileUserStartedDragging_goesToUserDragging() =
+        testScope.runTest {
+            // WHEN a drag interaction starts
+            interactionSource.setDragInteraction(DragInteraction.Start())
+            runCurrent()
+
+            // WHEN a value changes in the slider
+            underTest.onValueChange(0.5f)
+
+            // THEN the current slider event type shows that the user is dragging
+            assertThat(underTest.currentSliderEventType)
+                .isEqualTo(SliderEventType.PROGRESS_CHANGE_BY_USER)
+        }
+
+    @Test
+    fun onValueChange_whileUserDragging_staysInUserDragging() =
+        testScope.runTest {
+            // WHEN a drag interaction starts and the user keeps dragging
+            interactionSource.setDragInteraction(DragInteraction.Start())
+            runCurrent()
+            underTest.onValueChange(0.5f)
+
+            // WHEN value changes continue to occur due to dragging
+            underTest.onValueChange(0.6f)
+
+            // THEN the current slider event type reflects that the user continues to drag
+            assertThat(underTest.currentSliderEventType)
+                .isEqualTo(SliderEventType.PROGRESS_CHANGE_BY_USER)
+        }
+
+    @Test
+    fun onValueChange_whileNOTHING_goesToProgramStartedDragging() =
+        testScope.runTest {
+            // WHEN a value change occurs without a drag interaction
+            underTest.onValueChange(0.5f)
+
+            // THEN the current slider event type shows that the program started dragging
+            assertThat(underTest.currentSliderEventType)
+                .isEqualTo(SliderEventType.STARTED_TRACKING_PROGRAM)
+        }
+
+    @Test
+    fun onValueChange_whileProgramStartedDragging_goesToProgramDragging() =
+        testScope.runTest {
+            // WHEN the program starts dragging
+            underTest.onValueChange(0.5f)
+
+            // WHEN the program continues to make value changes
+            underTest.onValueChange(0.6f)
+
+            // THEN the current slider event type shows that program is dragging
+            assertThat(underTest.currentSliderEventType)
+                .isEqualTo(SliderEventType.PROGRESS_CHANGE_BY_PROGRAM)
+        }
+
+    @Test
+    fun onValueChange_whileProgramDragging_staysInProgramDragging() =
+        testScope.runTest {
+            // WHEN the program starts and continues to drag
+            underTest.onValueChange(0.5f)
+            underTest.onValueChange(0.6f)
+
+            // WHEN value changes continue to occur
+            underTest.onValueChange(0.7f)
+
+            // THEN the current slider event type shows that the program is dragging the slider
+            assertThat(underTest.currentSliderEventType)
+                .isEqualTo(SliderEventType.PROGRESS_CHANGE_BY_PROGRAM)
+        }
+
+    @Test
+    fun onValueChangeEnded_goesToNOTHING() =
+        testScope.runTest {
+            // WHEN changes end in the slider
+            underTest.onValueChangeEnded()
+
+            // THEN the current slider event type always resets to NOTHING
+            assertThat(underTest.currentSliderEventType).isEqualTo(SliderEventType.NOTHING)
+        }
+
+    private class DragInteractionSourceTest : InteractionSource {
+        private val _interactions = MutableStateFlow<DragInteraction>(IdleDrag)
+        override val interactions = _interactions.asStateFlow()
+
+        fun setDragInteraction(interaction: DragInteraction) {
+            _interactions.value = interaction
+        }
+    }
+
+    private object IdleDrag : DragInteraction
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractorTest.kt
index 17e3006..047d8c2 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractorTest.kt
@@ -42,7 +42,8 @@
 import com.android.systemui.communal.domain.interactor.communalInteractor
 import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
 import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository
-import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
+import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepositorySpy
+import com.android.systemui.keyguard.data.repository.keyguardTransitionRepository
 import com.android.systemui.keyguard.shared.model.KeyguardState
 import com.android.systemui.keyguard.util.KeyguardTransitionRepositorySpySubject.Companion.assertThat
 import com.android.systemui.kosmos.testScope
@@ -57,7 +58,6 @@
 import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
-import org.mockito.Mockito
 import org.mockito.Mockito.reset
 
 @ExperimentalCoroutinesApi
@@ -66,7 +66,7 @@
 class FromAlternateBouncerTransitionInteractorTest : SysuiTestCase() {
     private val kosmos =
         testKosmos().apply {
-            this.fakeKeyguardTransitionRepository = Mockito.spy(FakeKeyguardTransitionRepository())
+            this.keyguardTransitionRepository = fakeKeyguardTransitionRepositorySpy
         }
     private val testScope = kosmos.testScope
     private lateinit var underTest: FromAlternateBouncerTransitionInteractor
@@ -74,7 +74,7 @@
 
     @Before
     fun setup() {
-        transitionRepository = kosmos.fakeKeyguardTransitionRepository
+        transitionRepository = kosmos.fakeKeyguardTransitionRepositorySpy
         underTest = kosmos.fromAlternateBouncerTransitionInteractor
         underTest.start()
     }
@@ -86,7 +86,7 @@
             transitionRepository.sendTransitionSteps(
                 from = KeyguardState.OCCLUDED,
                 to = KeyguardState.ALTERNATE_BOUNCER,
-                testScope
+                testScope,
             )
             reset(transitionRepository)
 
@@ -111,7 +111,7 @@
             transitionRepository.sendTransitionSteps(
                 from = KeyguardState.OCCLUDED,
                 to = KeyguardState.ALTERNATE_BOUNCER,
-                testScope
+                testScope,
             )
             reset(transitionRepository)
 
@@ -129,7 +129,7 @@
             transitionRepository.sendTransitionSteps(
                 from = KeyguardState.OCCLUDED,
                 to = KeyguardState.ALTERNATE_BOUNCER,
-                testScope
+                testScope,
             )
             reset(transitionRepository)
 
@@ -158,7 +158,7 @@
             transitionRepository.sendTransitionSteps(
                 from = KeyguardState.OCCLUDED,
                 to = KeyguardState.ALTERNATE_BOUNCER,
-                testScope
+                testScope,
             )
             reset(transitionRepository)
 
@@ -168,7 +168,7 @@
             assertThat(transitionRepository)
                 .startedTransition(
                     from = KeyguardState.ALTERNATE_BOUNCER,
-                    to = KeyguardState.OCCLUDED
+                    to = KeyguardState.OCCLUDED,
                 )
         }
 
@@ -183,7 +183,7 @@
             transitionRepository.sendTransitionSteps(
                 from = KeyguardState.GLANCEABLE_HUB,
                 to = KeyguardState.ALTERNATE_BOUNCER,
-                testScope
+                testScope,
             )
             reset(transitionRepository)
 
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractorTest.kt
index 33f3cd4..9300964 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractorTest.kt
@@ -42,8 +42,9 @@
 import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
 import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository
-import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
+import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepositorySpy
 import com.android.systemui.keyguard.data.repository.keyguardOcclusionRepository
+import com.android.systemui.keyguard.data.repository.keyguardTransitionRepository
 import com.android.systemui.keyguard.shared.model.BiometricUnlockMode
 import com.android.systemui.keyguard.shared.model.KeyguardState
 import com.android.systemui.keyguard.shared.model.KeyguardState.GONE
@@ -69,7 +70,6 @@
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.mockito.Mockito.reset
-import org.mockito.Mockito.spy
 
 @OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
@@ -77,7 +77,7 @@
 class FromAodTransitionInteractorTest : SysuiTestCase() {
     private val kosmos =
         testKosmos().apply {
-            this.fakeKeyguardTransitionRepository = spy(FakeKeyguardTransitionRepository())
+            this.keyguardTransitionRepository = fakeKeyguardTransitionRepositorySpy
         }
 
     private val testScope = kosmos.testScope
@@ -89,7 +89,7 @@
     @Before
     fun setup() {
         powerInteractor = kosmos.powerInteractor
-        transitionRepository = kosmos.fakeKeyguardTransitionRepository
+        transitionRepository = kosmos.fakeKeyguardTransitionRepositorySpy
         underTest = kosmos.fromAodTransitionInteractor
 
         underTest.start()
@@ -101,7 +101,7 @@
             transitionRepository.sendTransitionSteps(
                 from = KeyguardState.LOCKSCREEN,
                 to = KeyguardState.AOD,
-                testScope
+                testScope,
             )
             kosmos.fakeKeyguardRepository.setBiometricUnlockState(BiometricUnlockMode.NONE)
             reset(transitionRepository)
@@ -117,10 +117,7 @@
 
             // Under default conditions, we should transition to LOCKSCREEN when waking up.
             assertThat(transitionRepository)
-                .startedTransition(
-                    from = KeyguardState.AOD,
-                    to = KeyguardState.LOCKSCREEN,
-                )
+                .startedTransition(from = KeyguardState.AOD, to = KeyguardState.LOCKSCREEN)
         }
 
     @Test
@@ -133,10 +130,7 @@
 
             // Waking with a SHOW_WHEN_LOCKED activity on top should transition to OCCLUDED.
             assertThat(transitionRepository)
-                .startedTransition(
-                    from = KeyguardState.AOD,
-                    to = KeyguardState.OCCLUDED,
-                )
+                .startedTransition(from = KeyguardState.AOD, to = KeyguardState.OCCLUDED)
         }
 
     @Test
@@ -363,13 +357,13 @@
                         from = KeyguardState.GONE,
                         to = KeyguardState.AOD,
                         transitionState = TransitionState.STARTED,
-                        value = 0f
+                        value = 0f,
                     ),
                     TransitionStep(
                         from = KeyguardState.GONE,
                         to = KeyguardState.AOD,
                         transitionState = TransitionState.RUNNING,
-                        value = 0.1f
+                        value = 0.1f,
                     ),
                 ),
                 testScope = testScope,
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractorTest.kt
index ff0a4a1..3b6e5d0 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractorTest.kt
@@ -36,8 +36,9 @@
 import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
 import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository
-import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
+import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepositorySpy
 import com.android.systemui.keyguard.data.repository.keyguardOcclusionRepository
+import com.android.systemui.keyguard.data.repository.keyguardTransitionRepository
 import com.android.systemui.keyguard.shared.model.BiometricUnlockMode
 import com.android.systemui.keyguard.shared.model.KeyguardState
 import com.android.systemui.keyguard.shared.model.KeyguardState.GONE
@@ -79,7 +80,7 @@
 class FromDozingTransitionInteractorTest(flags: FlagsParameterization?) : SysuiTestCase() {
     private val kosmos =
         testKosmos().apply {
-            this.fakeKeyguardTransitionRepository = spy(FakeKeyguardTransitionRepository())
+            this.keyguardTransitionRepository = fakeKeyguardTransitionRepositorySpy
             this.fakeCommunalSceneRepository =
                 spy(FakeCommunalSceneRepository(applicationScope = applicationCoroutineScope))
         }
@@ -105,7 +106,7 @@
     @Before
     fun setup() {
         powerInteractor = kosmos.powerInteractor
-        transitionRepository = kosmos.fakeKeyguardTransitionRepository
+        transitionRepository = kosmos.fakeKeyguardTransitionRepositorySpy
         underTest = kosmos.fromDozingTransitionInteractor
 
         underTest.start()
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractorTest.kt
index fa304c9..9ca3ce6 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractorTest.kt
@@ -32,7 +32,9 @@
 import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
 import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository
 import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
+import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepositorySpy
 import com.android.systemui.keyguard.data.repository.keyguardOcclusionRepository
+import com.android.systemui.keyguard.data.repository.keyguardTransitionRepository
 import com.android.systemui.keyguard.shared.model.BiometricUnlockMode
 import com.android.systemui.keyguard.shared.model.KeyguardState
 import com.android.systemui.keyguard.util.KeyguardTransitionRepositorySpySubject.Companion.assertThat
@@ -53,7 +55,6 @@
 import org.junit.runner.RunWith
 import org.mockito.Mockito.anyBoolean
 import org.mockito.Mockito.reset
-import org.mockito.Mockito.spy
 import org.mockito.kotlin.whenever
 import platform.test.runner.parameterized.ParameterizedAndroidJunit4
 import platform.test.runner.parameterized.Parameters
@@ -77,14 +78,21 @@
 
     private val kosmos =
         testKosmos().apply {
-            this.fakeKeyguardTransitionRepository = spy(FakeKeyguardTransitionRepository())
+            this.fakeKeyguardTransitionRepository =
+                FakeKeyguardTransitionRepository(
+                    // This test sends transition steps manually in the test cases.
+                    sendTransitionStepsOnStartTransition = false,
+                    testScope = testScope,
+                )
+
+            this.keyguardTransitionRepository = fakeKeyguardTransitionRepositorySpy
         }
 
     private val testScope = kosmos.testScope
     private val underTest by lazy { kosmos.fromDreamingTransitionInteractor }
 
     private val powerInteractor = kosmos.powerInteractor
-    private val transitionRepository = kosmos.fakeKeyguardTransitionRepository
+    private val transitionRepository = kosmos.fakeKeyguardTransitionRepositorySpy
 
     @Before
     fun setup() {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromGoneTransitionInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromGoneTransitionInteractorTest.kt
index af76b08..57b1299 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromGoneTransitionInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromGoneTransitionInteractorTest.kt
@@ -23,10 +23,10 @@
 import com.android.internal.widget.LockPatternUtils
 import com.android.systemui.Flags
 import com.android.systemui.SysuiTestCase
-import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
 import com.android.systemui.keyguard.data.repository.fakeBiometricSettingsRepository
 import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository
-import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
+import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepositorySpy
+import com.android.systemui.keyguard.data.repository.keyguardTransitionRepository
 import com.android.systemui.keyguard.shared.model.AuthenticationFlags
 import com.android.systemui.keyguard.shared.model.KeyguardState
 import com.android.systemui.keyguard.shared.model.TransitionState
@@ -41,18 +41,17 @@
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.mockito.Mockito.reset
-import org.mockito.Mockito.spy
 
 @SmallTest
 @RunWith(AndroidJUnit4::class)
 class FromGoneTransitionInteractorTest : SysuiTestCase() {
     private val kosmos =
         testKosmos().apply {
-            fakeKeyguardTransitionRepository = spy(FakeKeyguardTransitionRepository())
+            this.keyguardTransitionRepository = fakeKeyguardTransitionRepositorySpy
         }
     private val testScope = kosmos.testScope
     private val underTest = kosmos.fromGoneTransitionInteractor
-    private val keyguardTransitionRepository = kosmos.fakeKeyguardTransitionRepository
+    private val keyguardTransitionRepository = kosmos.fakeKeyguardTransitionRepositorySpy
 
     @Before
     fun setUp() {
@@ -101,9 +100,7 @@
 
             // We're in the middle of a GONE -> LOCKSCREEN transition.
             assertThat(keyguardTransitionRepository)
-                .startedTransition(
-                    to = KeyguardState.LOCKSCREEN,
-                )
+                .startedTransition(to = KeyguardState.LOCKSCREEN)
         }
 
     @Test
@@ -121,15 +118,13 @@
             kosmos.fakeBiometricSettingsRepository.setAuthenticationFlags(
                 AuthenticationFlags(
                     0,
-                    LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN
+                    LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN,
                 )
             )
             runCurrent()
 
             // We're in the middle of a GONE -> LOCKSCREEN transition.
             assertThat(keyguardTransitionRepository)
-                .startedTransition(
-                    to = KeyguardState.LOCKSCREEN,
-                )
+                .startedTransition(to = KeyguardState.LOCKSCREEN)
         }
 }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractorTest.kt
index 4d81317..9c2e631 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractorTest.kt
@@ -27,9 +27,11 @@
 import com.android.systemui.coroutines.collectValues
 import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
 import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository
-import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
+import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepositorySpy
 import com.android.systemui.keyguard.data.repository.keyguardOcclusionRepository
+import com.android.systemui.keyguard.data.repository.keyguardTransitionRepository
 import com.android.systemui.keyguard.shared.model.KeyguardState
+import com.android.systemui.keyguard.shared.model.StatusBarState
 import com.android.systemui.keyguard.shared.model.StatusBarState.KEYGUARD
 import com.android.systemui.keyguard.shared.model.TransitionState
 import com.android.systemui.keyguard.shared.model.TransitionStep
@@ -42,10 +44,10 @@
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.test.runCurrent
 import kotlinx.coroutines.test.runTest
+import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.mockito.Mockito.reset
-import org.mockito.Mockito.spy
 
 @OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
@@ -53,15 +55,20 @@
 class FromLockscreenTransitionInteractorTest : SysuiTestCase() {
     private val kosmos =
         testKosmos().apply {
-            fakeKeyguardTransitionRepository = spy(FakeKeyguardTransitionRepository())
+            this.keyguardTransitionRepository = fakeKeyguardTransitionRepositorySpy
         }
 
     private val testScope = kosmos.testScope
     private val underTest = kosmos.fromLockscreenTransitionInteractor
-    private val transitionRepository = kosmos.fakeKeyguardTransitionRepository
+    private lateinit var transitionRepository: FakeKeyguardTransitionRepository
     private val shadeRepository = kosmos.fakeShadeRepository
     private val keyguardRepository = kosmos.fakeKeyguardRepository
 
+    @Before
+    fun setup() {
+        transitionRepository = kosmos.fakeKeyguardTransitionRepositorySpy
+    }
+
     @Test
     fun testSurfaceBehindVisibility() =
         testScope.runTest {
@@ -256,4 +263,43 @@
             assertThatRepository(transitionRepository)
                 .startedTransition(from = KeyguardState.LOCKSCREEN, to = KeyguardState.DREAMING)
         }
+
+    @Test
+    fun testTransitionsBackToOccluded_ifOccluded_andCanceledSwipe() =
+        testScope.runTest {
+            underTest.start()
+            keyguardRepository.setStatusBarState(StatusBarState.KEYGUARD)
+            keyguardRepository.setKeyguardDismissible(false)
+            keyguardRepository.setKeyguardOccluded(false)
+            runCurrent()
+
+            reset(transitionRepository)
+
+            shadeRepository.setLegacyShadeTracking(true)
+            runCurrent()
+            shadeRepository.setLegacyShadeExpansion(0.5f)
+            runCurrent()
+
+            assertThatRepository(transitionRepository)
+                .startedTransition(
+                    from = KeyguardState.LOCKSCREEN,
+                    to = KeyguardState.PRIMARY_BOUNCER,
+                )
+            reset(transitionRepository)
+
+            runCurrent()
+
+            shadeRepository.setLegacyShadeExpansion(0.6f)
+            shadeRepository.setLegacyShadeExpansion(0.7f)
+            runCurrent()
+
+            shadeRepository.setLegacyShadeExpansion(1f)
+            runCurrent()
+
+            assertThatRepository(transitionRepository)
+                .startedTransition(
+                    from = KeyguardState.PRIMARY_BOUNCER,
+                    to = KeyguardState.LOCKSCREEN,
+                )
+        }
 }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromOccludedTransitionInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromOccludedTransitionInteractorTest.kt
index 7424320..4a90722 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromOccludedTransitionInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromOccludedTransitionInteractorTest.kt
@@ -42,9 +42,9 @@
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.communal.data.repository.fakeCommunalSceneRepository
 import com.android.systemui.communal.shared.model.CommunalScenes
-import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
-import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
+import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepositorySpy
 import com.android.systemui.keyguard.data.repository.keyguardOcclusionRepository
+import com.android.systemui.keyguard.data.repository.keyguardTransitionRepository
 import com.android.systemui.keyguard.shared.model.KeyguardState
 import com.android.systemui.keyguard.util.KeyguardTransitionRepositorySpySubject.Companion.assertThat
 import com.android.systemui.kosmos.testScope
@@ -60,7 +60,6 @@
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.mockito.Mockito.reset
-import org.mockito.Mockito.spy
 
 @OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
@@ -68,14 +67,14 @@
 class FromOccludedTransitionInteractorTest : SysuiTestCase() {
     private val kosmos =
         testKosmos().apply {
-            this.fakeKeyguardTransitionRepository = spy(FakeKeyguardTransitionRepository())
+            this.keyguardTransitionRepository = fakeKeyguardTransitionRepositorySpy
         }
 
     private val testScope = kosmos.testScope
     private val underTest = kosmos.fromOccludedTransitionInteractor
 
     private val powerInteractor = kosmos.powerInteractor
-    private val transitionRepository = kosmos.fakeKeyguardTransitionRepository
+    private val transitionRepository = kosmos.fakeKeyguardTransitionRepositorySpy
 
     @Before
     fun setup() {
@@ -88,7 +87,7 @@
             transitionRepository.sendTransitionSteps(
                 from = KeyguardState.LOCKSCREEN,
                 to = KeyguardState.OCCLUDED,
-                testScope
+                testScope,
             )
             reset(transitionRepository)
         }
@@ -102,10 +101,7 @@
             runCurrent()
 
             assertThat(transitionRepository)
-                .startedTransition(
-                    from = KeyguardState.OCCLUDED,
-                    to = KeyguardState.LOCKSCREEN,
-                )
+                .startedTransition(from = KeyguardState.OCCLUDED, to = KeyguardState.LOCKSCREEN)
         }
 
     @Test
@@ -122,9 +118,6 @@
             runCurrent()
 
             assertThat(transitionRepository)
-                .startedTransition(
-                    from = KeyguardState.OCCLUDED,
-                    to = KeyguardState.GLANCEABLE_HUB,
-                )
+                .startedTransition(from = KeyguardState.OCCLUDED, to = KeyguardState.GLANCEABLE_HUB)
         }
 }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractorTest.kt
index 14f2d65..a7da230 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractorTest.kt
@@ -26,9 +26,9 @@
 import com.android.systemui.communal.data.repository.fakeCommunalSceneRepository
 import com.android.systemui.communal.shared.model.CommunalScenes
 import com.android.systemui.coroutines.collectValues
-import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
-import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
+import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepositorySpy
 import com.android.systemui.keyguard.data.repository.keyguardOcclusionRepository
+import com.android.systemui.keyguard.data.repository.keyguardTransitionRepository
 import com.android.systemui.keyguard.shared.model.KeyguardState
 import com.android.systemui.keyguard.shared.model.TransitionState
 import com.android.systemui.keyguard.shared.model.TransitionStep
@@ -44,20 +44,19 @@
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.mockito.Mockito.reset
-import org.mockito.Mockito.spy
 
 @OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
 @RunWith(AndroidJUnit4::class)
 class FromPrimaryBouncerTransitionInteractorTest : SysuiTestCase() {
-    val kosmos =
+    private val kosmos =
         testKosmos().apply {
-            this.fakeKeyguardTransitionRepository = spy(FakeKeyguardTransitionRepository())
+            this.keyguardTransitionRepository = fakeKeyguardTransitionRepositorySpy
         }
     val underTest = kosmos.fromPrimaryBouncerTransitionInteractor
     val testScope = kosmos.testScope
     val selectedUserInteractor = kosmos.selectedUserInteractor
-    val transitionRepository = kosmos.fakeKeyguardTransitionRepository
+    val transitionRepository = kosmos.fakeKeyguardTransitionRepositorySpy
     val bouncerRepository = kosmos.fakeKeyguardBouncerRepository
 
     @Test
@@ -67,12 +66,7 @@
             runCurrent()
 
             // Transition-specific surface visibility should be null ("don't care") initially.
-            assertEquals(
-                listOf(
-                    null,
-                ),
-                values
-            )
+            assertEquals(listOf(null), values)
 
             transitionRepository.sendTransitionStep(
                 TransitionStep(
@@ -86,9 +80,9 @@
 
             assertEquals(
                 listOf(
-                    null, // PRIMARY_BOUNCER -> LOCKSCREEN does not have any specific visibility.
+                    null // PRIMARY_BOUNCER -> LOCKSCREEN does not have any specific visibility.
                 ),
-                values
+                values,
             )
 
             transitionRepository.sendTransitionStep(
@@ -117,7 +111,7 @@
                     null,
                     false, // Surface is only made visible once the bouncer UI animates out.
                 ),
-                values
+                values,
             )
 
             transitionRepository.sendTransitionStep(
@@ -137,7 +131,7 @@
                     false,
                     true, // Surface should eventually be visible.
                 ),
-                values
+                values,
             )
         }
 
@@ -150,7 +144,7 @@
             transitionRepository.sendTransitionSteps(
                 from = KeyguardState.LOCKSCREEN,
                 to = KeyguardState.PRIMARY_BOUNCER,
-                testScope
+                testScope,
             )
 
             reset(transitionRepository)
@@ -161,7 +155,7 @@
             assertThat(transitionRepository)
                 .startedTransition(
                     from = KeyguardState.PRIMARY_BOUNCER,
-                    to = KeyguardState.LOCKSCREEN
+                    to = KeyguardState.LOCKSCREEN,
                 )
         }
 
@@ -177,7 +171,7 @@
             transitionRepository.sendTransitionSteps(
                 from = KeyguardState.LOCKSCREEN,
                 to = KeyguardState.PRIMARY_BOUNCER,
-                testScope
+                testScope,
             )
 
             reset(transitionRepository)
@@ -188,7 +182,7 @@
             assertThat(transitionRepository)
                 .startedTransition(
                     from = KeyguardState.PRIMARY_BOUNCER,
-                    to = KeyguardState.GLANCEABLE_HUB
+                    to = KeyguardState.GLANCEABLE_HUB,
                 )
         }
 
@@ -201,7 +195,7 @@
             transitionRepository.sendTransitionSteps(
                 from = KeyguardState.LOCKSCREEN,
                 to = KeyguardState.PRIMARY_BOUNCER,
-                testScope
+                testScope,
             )
 
             reset(transitionRepository)
@@ -218,7 +212,7 @@
             assertThat(transitionRepository)
                 .startedTransition(
                     from = KeyguardState.PRIMARY_BOUNCER,
-                    to = KeyguardState.OCCLUDED
+                    to = KeyguardState.OCCLUDED,
                 )
         }
 }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardKeyEventInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardKeyEventInteractorTest.kt
index 13f30f5..945e44a 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardKeyEventInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardKeyEventInteractorTest.kt
@@ -46,6 +46,7 @@
 import org.mockito.Mockito.never
 import org.mockito.Mockito.verify
 import org.mockito.junit.MockitoJUnit
+import org.mockito.kotlin.isNull
 
 @ExperimentalCoroutinesApi
 @SmallTest
@@ -96,7 +97,7 @@
             .sendVolumeKeyEvent(
                 eq(actionDownVolumeDownKeyEvent),
                 eq(AudioManager.USE_DEFAULT_STREAM_TYPE),
-                eq(true)
+                eq(true),
             )
 
         assertThat(underTest.dispatchKeyEvent(actionDownVolumeUpKeyEvent)).isTrue()
@@ -104,7 +105,7 @@
             .sendVolumeKeyEvent(
                 eq(actionDownVolumeUpKeyEvent),
                 eq(AudioManager.USE_DEFAULT_STREAM_TYPE),
-                eq(true)
+                eq(true),
             )
     }
 
@@ -117,7 +118,7 @@
             .sendVolumeKeyEvent(
                 eq(actionDownVolumeDownKeyEvent),
                 eq(AudioManager.USE_DEFAULT_STREAM_TYPE),
-                eq(true)
+                eq(true),
             )
 
         assertThat(underTest.dispatchKeyEvent(actionDownVolumeUpKeyEvent)).isFalse()
@@ -125,7 +126,7 @@
             .sendVolumeKeyEvent(
                 eq(actionDownVolumeUpKeyEvent),
                 eq(AudioManager.USE_DEFAULT_STREAM_TYPE),
-                eq(true)
+                eq(true),
             )
     }
 
@@ -135,7 +136,9 @@
         whenever(statusBarStateController.state).thenReturn(StatusBarState.SHADE_LOCKED)
         whenever(statusBarKeyguardViewManager.shouldDismissOnMenuPressed()).thenReturn(true)
 
-        verifyActionUpCollapsesTheShade(KeyEvent.KEYCODE_MENU)
+        val actionUpMenuKeyEvent = KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_MENU)
+        assertThat(underTest.dispatchKeyEvent(actionUpMenuKeyEvent)).isTrue()
+        verify(statusBarKeyguardViewManager).dismissWithAction(any(), isNull(), eq(false))
     }
 
     @Test
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorTest.kt
index 12039c1..e079619 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorTest.kt
@@ -118,11 +118,11 @@
                             LOCKSCREEN,
                             0f,
                             STARTED,
-                            ownerName = "KeyguardTransitionRepository(boot)"
+                            ownerName = "KeyguardTransitionRepository(boot)",
                         ),
                         steps[0],
                         steps[3],
-                        steps[6]
+                        steps[6],
                     )
                 )
         }
@@ -253,51 +253,20 @@
                     true, // The repo is seeded with a transition from OFF to LOCKSCREEN.
                     false,
                 ),
-                inTransition
+                inTransition,
             )
 
-            sendSteps(
-                TransitionStep(LOCKSCREEN, GONE, 0f, STARTED),
-            )
+            sendSteps(TransitionStep(LOCKSCREEN, GONE, 0f, STARTED))
 
-            assertEquals(
-                listOf(
-                    false,
-                    true,
-                    false,
-                    true,
-                ),
-                inTransition
-            )
+            assertEquals(listOf(false, true, false, true), inTransition)
 
-            sendSteps(
-                TransitionStep(LOCKSCREEN, GONE, 0.5f, RUNNING),
-            )
+            sendSteps(TransitionStep(LOCKSCREEN, GONE, 0.5f, RUNNING))
 
-            assertEquals(
-                listOf(
-                    false,
-                    true,
-                    false,
-                    true,
-                ),
-                inTransition
-            )
+            assertEquals(listOf(false, true, false, true), inTransition)
 
-            sendSteps(
-                TransitionStep(LOCKSCREEN, GONE, 1f, FINISHED),
-            )
+            sendSteps(TransitionStep(LOCKSCREEN, GONE, 1f, FINISHED))
 
-            assertEquals(
-                listOf(
-                    false,
-                    true,
-                    false,
-                    true,
-                    false,
-                ),
-                inTransition
-            )
+            assertEquals(listOf(false, true, false, true, false), inTransition)
         }
 
     @Test
@@ -312,33 +281,16 @@
                     true, // The repo is seeded with a transition from OFF to LOCKSCREEN.
                     false,
                 ),
-                inTransition
+                inTransition,
             )
 
             kosmos.setSceneTransition(Transition(Scenes.Gone, Scenes.Bouncer))
 
-            assertEquals(
-                listOf(
-                    false,
-                    true,
-                    false,
-                    true,
-                ),
-                inTransition
-            )
+            assertEquals(listOf(false, true, false, true), inTransition)
 
             kosmos.setSceneTransition(Idle(Scenes.Bouncer))
 
-            assertEquals(
-                listOf(
-                    false,
-                    true,
-                    false,
-                    true,
-                    false,
-                ),
-                inTransition
-            )
+            assertEquals(listOf(false, true, false, true, false), inTransition)
         }
 
     @Test
@@ -346,14 +298,7 @@
         testScope.runTest {
             val inTransition by collectValues(underTest.isInTransition)
 
-            assertEquals(
-                listOf(
-                    false,
-                    true,
-                    false,
-                ),
-                inTransition
-            )
+            assertEquals(listOf(false, true, false), inTransition)
 
             // Start FINISHED in GONE.
             sendSteps(
@@ -362,32 +307,11 @@
                 TransitionStep(LOCKSCREEN, GONE, 1f, FINISHED),
             )
 
-            assertEquals(
-                listOf(
-                    false,
-                    true,
-                    false,
-                    true,
-                    false,
-                ),
-                inTransition
-            )
+            assertEquals(listOf(false, true, false, true, false), inTransition)
 
-            sendSteps(
-                TransitionStep(GONE, DOZING, 0f, STARTED),
-            )
+            sendSteps(TransitionStep(GONE, DOZING, 0f, STARTED))
 
-            assertEquals(
-                listOf(
-                    false,
-                    true,
-                    false,
-                    true,
-                    false,
-                    true,
-                ),
-                inTransition
-            )
+            assertEquals(listOf(false, true, false, true, false, true), inTransition)
 
             sendSteps(
                 TransitionStep(GONE, DOZING, 0.5f, RUNNING),
@@ -410,7 +334,7 @@
                     // transitioning to GONE, the state we're also FINISHED in.
                     true,
                 ),
-                inTransition
+                inTransition,
             )
 
             sendSteps(
@@ -418,18 +342,7 @@
                 TransitionStep(LOCKSCREEN, GONE, 1f, FINISHED),
             )
 
-            assertEquals(
-                listOf(
-                    false,
-                    true,
-                    false,
-                    true,
-                    false,
-                    true,
-                    false,
-                ),
-                inTransition
-            )
+            assertEquals(listOf(false, true, false, true, false, true, false), inTransition)
         }
 
     @Test
@@ -440,7 +353,7 @@
                 collectValues(
                     underTest.isInTransition(
                         edge = Edge.create(OFF, OFF),
-                        edgeWithoutSceneContainer = Edge.create(to = LOCKSCREEN)
+                        edgeWithoutSceneContainer = Edge.create(to = LOCKSCREEN),
                     )
                 )
 
@@ -450,49 +363,19 @@
                 TransitionStep(AOD, DOZING, 1f, FINISHED),
             )
 
-            assertThat(results)
-                .isEqualTo(
-                    listOf(
-                        false,
-                    )
-                )
+            assertThat(results).isEqualTo(listOf(false))
 
-            sendSteps(
-                TransitionStep(DOZING, LOCKSCREEN, 0f, STARTED),
-            )
+            sendSteps(TransitionStep(DOZING, LOCKSCREEN, 0f, STARTED))
 
-            assertThat(results)
-                .isEqualTo(
-                    listOf(
-                        false,
-                        true,
-                    )
-                )
+            assertThat(results).isEqualTo(listOf(false, true))
 
-            sendSteps(
-                TransitionStep(DOZING, LOCKSCREEN, 0f, RUNNING),
-            )
+            sendSteps(TransitionStep(DOZING, LOCKSCREEN, 0f, RUNNING))
 
-            assertThat(results)
-                .isEqualTo(
-                    listOf(
-                        false,
-                        true,
-                    )
-                )
+            assertThat(results).isEqualTo(listOf(false, true))
 
-            sendSteps(
-                TransitionStep(DOZING, LOCKSCREEN, 0f, FINISHED),
-            )
+            sendSteps(TransitionStep(DOZING, LOCKSCREEN, 0f, FINISHED))
 
-            assertThat(results)
-                .isEqualTo(
-                    listOf(
-                        false,
-                        true,
-                        false,
-                    )
-                )
+            assertThat(results).isEqualTo(listOf(false, true, false))
 
             sendSteps(
                 TransitionStep(LOCKSCREEN, DOZING, 0f, STARTED),
@@ -500,29 +383,14 @@
                 TransitionStep(LOCKSCREEN, DOZING, 1f, FINISHED),
             )
 
-            assertThat(results)
-                .isEqualTo(
-                    listOf(
-                        false,
-                        true,
-                        false,
-                    )
-                )
+            assertThat(results).isEqualTo(listOf(false, true, false))
 
             sendSteps(
                 TransitionStep(DOZING, LOCKSCREEN, 0f, STARTED),
                 TransitionStep(DOZING, LOCKSCREEN, 0f, RUNNING),
             )
 
-            assertThat(results)
-                .isEqualTo(
-                    listOf(
-                        false,
-                        true,
-                        false,
-                        true,
-                    )
-                )
+            assertThat(results).isEqualTo(listOf(false, true, false, true))
         }
 
     @Test
@@ -535,33 +403,15 @@
             kosmos.setSceneTransition(Transition(from = Scenes.Gone, to = Scenes.Lockscreen))
             kosmos.setSceneTransition(Idle(Scenes.Lockscreen))
 
-            assertThat(results)
-                .isEqualTo(
-                    listOf(
-                        false,
-                    )
-                )
+            assertThat(results).isEqualTo(listOf(false))
 
             kosmos.setSceneTransition(Transition(from = Scenes.Lockscreen, to = Scenes.Shade))
 
-            assertThat(results)
-                .isEqualTo(
-                    listOf(
-                        false,
-                        true,
-                    )
-                )
+            assertThat(results).isEqualTo(listOf(false, true))
 
             kosmos.setSceneTransition(Idle(Scenes.Shade))
 
-            assertThat(results)
-                .isEqualTo(
-                    listOf(
-                        false,
-                        true,
-                        false,
-                    )
-                )
+            assertThat(results).isEqualTo(listOf(false, true, false))
         }
 
     @Test
@@ -575,14 +425,7 @@
             kosmos.setSceneTransition(Idle(Scenes.Lockscreen))
             kosmos.setSceneTransition(Transition(from = Scenes.Lockscreen, to = Scenes.Gone))
 
-            assertThat(results)
-                .isEqualTo(
-                    listOf(
-                        false,
-                        true,
-                        false,
-                    )
-                )
+            assertThat(results).isEqualTo(listOf(false, true, false))
         }
 
     @Test
@@ -602,14 +445,7 @@
 
             kosmos.setSceneTransition(Idle(Scenes.Gone))
 
-            assertThat(results)
-                .isEqualTo(
-                    listOf(
-                        false,
-                        true,
-                        false,
-                    )
-                )
+            assertThat(results).isEqualTo(listOf(false, true, false))
         }
 
     @Test
@@ -623,49 +459,19 @@
                 TransitionStep(AOD, DOZING, 1f, FINISHED),
             )
 
-            assertThat(results)
-                .isEqualTo(
-                    listOf(
-                        false,
-                    )
-                )
+            assertThat(results).isEqualTo(listOf(false))
 
-            sendSteps(
-                TransitionStep(DOZING, LOCKSCREEN, 0f, STARTED),
-            )
+            sendSteps(TransitionStep(DOZING, LOCKSCREEN, 0f, STARTED))
 
-            assertThat(results)
-                .isEqualTo(
-                    listOf(
-                        false,
-                        true,
-                    )
-                )
+            assertThat(results).isEqualTo(listOf(false, true))
 
-            sendSteps(
-                TransitionStep(DOZING, LOCKSCREEN, 0f, RUNNING),
-            )
+            sendSteps(TransitionStep(DOZING, LOCKSCREEN, 0f, RUNNING))
 
-            assertThat(results)
-                .isEqualTo(
-                    listOf(
-                        false,
-                        true,
-                    )
-                )
+            assertThat(results).isEqualTo(listOf(false, true))
 
-            sendSteps(
-                TransitionStep(DOZING, LOCKSCREEN, 0f, FINISHED),
-            )
+            sendSteps(TransitionStep(DOZING, LOCKSCREEN, 0f, FINISHED))
 
-            assertThat(results)
-                .isEqualTo(
-                    listOf(
-                        false,
-                        true,
-                        false,
-                    )
-                )
+            assertThat(results).isEqualTo(listOf(false, true, false))
 
             sendSteps(
                 TransitionStep(LOCKSCREEN, DOZING, 0f, STARTED),
@@ -673,29 +479,14 @@
                 TransitionStep(LOCKSCREEN, DOZING, 1f, FINISHED),
             )
 
-            assertThat(results)
-                .isEqualTo(
-                    listOf(
-                        false,
-                        true,
-                        false,
-                    )
-                )
+            assertThat(results).isEqualTo(listOf(false, true, false))
 
             sendSteps(
                 TransitionStep(DOZING, LOCKSCREEN, 0f, STARTED),
                 TransitionStep(DOZING, LOCKSCREEN, 0f, RUNNING),
             )
 
-            assertThat(results)
-                .isEqualTo(
-                    listOf(
-                        false,
-                        true,
-                        false,
-                        true,
-                    )
-                )
+            assertThat(results).isEqualTo(listOf(false, true, false, true))
         }
 
     @Test
@@ -715,49 +506,19 @@
                 TransitionStep(AOD, DOZING, 1f, FINISHED),
             )
 
-            assertThat(results)
-                .isEqualTo(
-                    listOf(
-                        false,
-                    )
-                )
+            assertThat(results).isEqualTo(listOf(false))
 
-            sendSteps(
-                TransitionStep(DOZING, GONE, 0f, STARTED),
-            )
+            sendSteps(TransitionStep(DOZING, GONE, 0f, STARTED))
 
-            assertThat(results)
-                .isEqualTo(
-                    listOf(
-                        false,
-                        true,
-                    )
-                )
+            assertThat(results).isEqualTo(listOf(false, true))
 
-            sendSteps(
-                TransitionStep(DOZING, GONE, 0f, RUNNING),
-            )
+            sendSteps(TransitionStep(DOZING, GONE, 0f, RUNNING))
 
-            assertThat(results)
-                .isEqualTo(
-                    listOf(
-                        false,
-                        true,
-                    )
-                )
+            assertThat(results).isEqualTo(listOf(false, true))
 
-            sendSteps(
-                TransitionStep(DOZING, GONE, 0f, FINISHED),
-            )
+            sendSteps(TransitionStep(DOZING, GONE, 0f, FINISHED))
 
-            assertThat(results)
-                .isEqualTo(
-                    listOf(
-                        false,
-                        true,
-                        false,
-                    )
-                )
+            assertThat(results).isEqualTo(listOf(false, true, false))
 
             sendSteps(
                 TransitionStep(GONE, DOZING, 0f, STARTED),
@@ -765,29 +526,14 @@
                 TransitionStep(GONE, DOZING, 1f, FINISHED),
             )
 
-            assertThat(results)
-                .isEqualTo(
-                    listOf(
-                        false,
-                        true,
-                        false,
-                    )
-                )
+            assertThat(results).isEqualTo(listOf(false, true, false))
 
             sendSteps(
                 TransitionStep(DOZING, GONE, 0f, STARTED),
                 TransitionStep(DOZING, GONE, 0f, RUNNING),
             )
 
-            assertThat(results)
-                .isEqualTo(
-                    listOf(
-                        false,
-                        true,
-                        false,
-                        true,
-                    )
-                )
+            assertThat(results).isEqualTo(listOf(false, true, false, true))
         }
 
     @Test
@@ -807,48 +553,19 @@
                 TransitionStep(AOD, DOZING, 1f, FINISHED),
             )
 
-            assertThat(results)
-                .isEqualTo(
-                    listOf(
-                        false,
-                    )
-                )
+            assertThat(results).isEqualTo(listOf(false))
 
-            sendSteps(
-                TransitionStep(DOZING, GONE, 0f, STARTED),
-            )
+            sendSteps(TransitionStep(DOZING, GONE, 0f, STARTED))
 
-            assertThat(results)
-                .isEqualTo(
-                    listOf(
-                        false,
-                        true,
-                    )
-                )
+            assertThat(results).isEqualTo(listOf(false, true))
 
-            sendSteps(
-                TransitionStep(DOZING, GONE, 0f, RUNNING),
-            )
+            sendSteps(TransitionStep(DOZING, GONE, 0f, RUNNING))
 
-            assertThat(results)
-                .isEqualTo(
-                    listOf(
-                        false,
-                        true,
-                    )
-                )
+            assertThat(results).isEqualTo(listOf(false, true))
 
-            sendSteps(
-                TransitionStep(DOZING, GONE, 0f, CANCELED),
-            )
+            sendSteps(TransitionStep(DOZING, GONE, 0f, CANCELED))
 
-            assertThat(results)
-                .isEqualTo(
-                    listOf(
-                        false,
-                        true,
-                    )
-                )
+            assertThat(results).isEqualTo(listOf(false, true))
 
             sendSteps(
                 TransitionStep(GONE, DOZING, 0f, STARTED),
@@ -856,29 +573,14 @@
                 TransitionStep(GONE, DOZING, 1f, FINISHED),
             )
 
-            assertThat(results)
-                .isEqualTo(
-                    listOf(
-                        false,
-                        true,
-                        false,
-                    )
-                )
+            assertThat(results).isEqualTo(listOf(false, true, false))
 
             sendSteps(
                 TransitionStep(DOZING, GONE, 0f, STARTED),
                 TransitionStep(DOZING, GONE, 0f, RUNNING),
             )
 
-            assertThat(results)
-                .isEqualTo(
-                    listOf(
-                        false,
-                        true,
-                        false,
-                        true,
-                    )
-                )
+            assertThat(results).isEqualTo(listOf(false, true, false, true))
         }
 
     @Test
@@ -895,87 +597,43 @@
             assertThat(results)
                 .isEqualTo(
                     listOf(
-                        false, // Finished in DOZING, not GONE.
+                        false // Finished in DOZING, not GONE.
                     )
                 )
 
             sendSteps(TransitionStep(DOZING, GONE, 0f, STARTED))
 
-            assertThat(results)
-                .isEqualTo(
-                    listOf(
-                        false,
-                    )
-                )
+            assertThat(results).isEqualTo(listOf(false))
 
             sendSteps(TransitionStep(DOZING, GONE, 0f, RUNNING))
 
-            assertThat(results)
-                .isEqualTo(
-                    listOf(
-                        false,
-                    )
-                )
+            assertThat(results).isEqualTo(listOf(false))
 
             sendSteps(TransitionStep(DOZING, GONE, 1f, FINISHED))
 
-            assertThat(results)
-                .isEqualTo(
-                    listOf(
-                        false,
-                        true,
-                    )
-                )
+            assertThat(results).isEqualTo(listOf(false, true))
 
             sendSteps(
                 TransitionStep(GONE, DOZING, 0f, STARTED),
                 TransitionStep(GONE, DOZING, 0f, RUNNING),
             )
 
-            assertThat(results)
-                .isEqualTo(
-                    listOf(
-                        false,
-                        true,
-                    )
-                )
+            assertThat(results).isEqualTo(listOf(false, true))
 
             sendSteps(TransitionStep(GONE, DOZING, 1f, FINISHED))
 
-            assertThat(results)
-                .isEqualTo(
-                    listOf(
-                        false,
-                        true,
-                        false,
-                    )
-                )
+            assertThat(results).isEqualTo(listOf(false, true, false))
 
             sendSteps(
                 TransitionStep(DOZING, GONE, 0f, STARTED),
                 TransitionStep(DOZING, GONE, 0f, RUNNING),
             )
 
-            assertThat(results)
-                .isEqualTo(
-                    listOf(
-                        false,
-                        true,
-                        false,
-                    )
-                )
+            assertThat(results).isEqualTo(listOf(false, true, false))
 
             sendSteps(TransitionStep(DOZING, GONE, 1f, FINISHED))
 
-            assertThat(results)
-                .isEqualTo(
-                    listOf(
-                        false,
-                        true,
-                        false,
-                        true,
-                    )
-                )
+            assertThat(results).isEqualTo(listOf(false, true, false, true))
         }
 
     @Test
@@ -993,87 +651,43 @@
             assertThat(results)
                 .isEqualTo(
                     listOf(
-                        false, // Finished in DOZING, not GONE.
+                        false // Finished in DOZING, not GONE.
                     )
                 )
 
             sendSteps(TransitionStep(DOZING, GONE, 0f, STARTED))
 
-            assertThat(results)
-                .isEqualTo(
-                    listOf(
-                        false,
-                    )
-                )
+            assertThat(results).isEqualTo(listOf(false))
 
             sendSteps(TransitionStep(DOZING, GONE, 0f, RUNNING))
 
-            assertThat(results)
-                .isEqualTo(
-                    listOf(
-                        false,
-                    )
-                )
+            assertThat(results).isEqualTo(listOf(false))
 
             sendSteps(TransitionStep(DOZING, GONE, 1f, FINISHED))
 
-            assertThat(results)
-                .isEqualTo(
-                    listOf(
-                        false,
-                        true,
-                    )
-                )
+            assertThat(results).isEqualTo(listOf(false, true))
 
             sendSteps(
                 TransitionStep(GONE, DOZING, 0f, STARTED),
                 TransitionStep(GONE, DOZING, 0f, RUNNING),
             )
 
-            assertThat(results)
-                .isEqualTo(
-                    listOf(
-                        false,
-                        true,
-                    )
-                )
+            assertThat(results).isEqualTo(listOf(false, true))
 
             sendSteps(TransitionStep(GONE, DOZING, 1f, FINISHED))
 
-            assertThat(results)
-                .isEqualTo(
-                    listOf(
-                        false,
-                        true,
-                        false,
-                    )
-                )
+            assertThat(results).isEqualTo(listOf(false, true, false))
 
             sendSteps(
                 TransitionStep(DOZING, GONE, 0f, STARTED),
                 TransitionStep(DOZING, GONE, 0f, RUNNING),
             )
 
-            assertThat(results)
-                .isEqualTo(
-                    listOf(
-                        false,
-                        true,
-                        false,
-                    )
-                )
+            assertThat(results).isEqualTo(listOf(false, true, false))
 
             sendSteps(TransitionStep(DOZING, GONE, 1f, FINISHED))
 
-            assertThat(results)
-                .isEqualTo(
-                    listOf(
-                        false,
-                        true,
-                        false,
-                        true,
-                    )
-                )
+            assertThat(results).isEqualTo(listOf(false, true, false, true))
         }
 
     @Test
@@ -1091,72 +705,33 @@
             assertThat(results)
                 .isEqualTo(
                     listOf(
-                        false, // Finished in DOZING, not GONE.
+                        false // Finished in DOZING, not GONE.
                     )
                 )
 
             kosmos.setSceneTransition(Transition(from = Scenes.Lockscreen, to = Scenes.Gone))
 
-            assertThat(results)
-                .isEqualTo(
-                    listOf(
-                        false,
-                    )
-                )
+            assertThat(results).isEqualTo(listOf(false))
 
             kosmos.setSceneTransition(Idle(Scenes.Gone))
 
-            assertThat(results)
-                .isEqualTo(
-                    listOf(
-                        false,
-                        true,
-                    )
-                )
+            assertThat(results).isEqualTo(listOf(false, true))
 
             kosmos.setSceneTransition(Transition(from = Scenes.Gone, to = Scenes.Lockscreen))
 
-            assertThat(results)
-                .isEqualTo(
-                    listOf(
-                        false,
-                        true,
-                    )
-                )
+            assertThat(results).isEqualTo(listOf(false, true))
 
             kosmos.setSceneTransition(Idle(Scenes.Lockscreen))
 
-            assertThat(results)
-                .isEqualTo(
-                    listOf(
-                        false,
-                        true,
-                        false,
-                    )
-                )
+            assertThat(results).isEqualTo(listOf(false, true, false))
 
             kosmos.setSceneTransition(Transition(from = Scenes.Lockscreen, to = Scenes.Gone))
 
-            assertThat(results)
-                .isEqualTo(
-                    listOf(
-                        false,
-                        true,
-                        false,
-                    )
-                )
+            assertThat(results).isEqualTo(listOf(false, true, false))
 
             kosmos.setSceneTransition(Idle(Scenes.Gone))
 
-            assertThat(results)
-                .isEqualTo(
-                    listOf(
-                        false,
-                        true,
-                        false,
-                        true,
-                    )
-                )
+            assertThat(results).isEqualTo(listOf(false, true, false, true))
         }
 
     @Test
@@ -1165,68 +740,29 @@
             val currentStates by collectValues(underTest.currentKeyguardState)
 
             // We init the repo with a transition from OFF -> LOCKSCREEN.
-            assertEquals(
-                listOf(
-                    OFF,
-                    LOCKSCREEN,
-                ),
-                currentStates
-            )
+            assertEquals(listOf(OFF, LOCKSCREEN), currentStates)
 
-            sendSteps(
-                TransitionStep(LOCKSCREEN, AOD, 0f, STARTED),
-            )
+            sendSteps(TransitionStep(LOCKSCREEN, AOD, 0f, STARTED))
 
             // The current state should continue to be LOCKSCREEN as we transition to AOD.
-            assertEquals(
-                listOf(
-                    OFF,
-                    LOCKSCREEN,
-                ),
-                currentStates
-            )
+            assertEquals(listOf(OFF, LOCKSCREEN), currentStates)
 
-            sendSteps(
-                TransitionStep(LOCKSCREEN, AOD, 0.5f, RUNNING),
-            )
+            sendSteps(TransitionStep(LOCKSCREEN, AOD, 0.5f, RUNNING))
 
             // The current state should continue to be LOCKSCREEN as we transition to AOD.
-            assertEquals(
-                listOf(
-                    OFF,
-                    LOCKSCREEN,
-                ),
-                currentStates
-            )
+            assertEquals(listOf(OFF, LOCKSCREEN), currentStates)
 
-            sendSteps(
-                TransitionStep(LOCKSCREEN, AOD, 0.6f, CANCELED),
-            )
+            sendSteps(TransitionStep(LOCKSCREEN, AOD, 0.6f, CANCELED))
 
             // Once CANCELED, we're still currently in LOCKSCREEN...
-            assertEquals(
-                listOf(
-                    OFF,
-                    LOCKSCREEN,
-                ),
-                currentStates
-            )
+            assertEquals(listOf(OFF, LOCKSCREEN), currentStates)
 
-            sendSteps(
-                TransitionStep(AOD, LOCKSCREEN, 0.6f, STARTED),
-            )
+            sendSteps(TransitionStep(AOD, LOCKSCREEN, 0.6f, STARTED))
 
             // ...until STARTING back to LOCKSCREEN, at which point the "current" state should be
             // the
             // one we're transitioning from, despite never FINISHING in that state.
-            assertEquals(
-                listOf(
-                    OFF,
-                    LOCKSCREEN,
-                    AOD,
-                ),
-                currentStates
-            )
+            assertEquals(listOf(OFF, LOCKSCREEN, AOD), currentStates)
 
             sendSteps(
                 TransitionStep(AOD, LOCKSCREEN, 0.8f, RUNNING),
@@ -1234,15 +770,7 @@
             )
 
             // FINSHING in LOCKSCREEN should update the current state to LOCKSCREEN.
-            assertEquals(
-                listOf(
-                    OFF,
-                    LOCKSCREEN,
-                    AOD,
-                    LOCKSCREEN,
-                ),
-                currentStates
-            )
+            assertEquals(listOf(OFF, LOCKSCREEN, AOD, LOCKSCREEN), currentStates)
         }
 
     @Test
@@ -1251,13 +779,7 @@
             val currentStates by collectValues(underTest.currentKeyguardState)
 
             // We init the repo with a transition from OFF -> LOCKSCREEN.
-            assertEquals(
-                listOf(
-                    OFF,
-                    LOCKSCREEN,
-                ),
-                currentStates
-            )
+            assertEquals(listOf(OFF, LOCKSCREEN), currentStates)
 
             sendSteps(
                 TransitionStep(LOCKSCREEN, GONE, 0f, STARTED),
@@ -1273,7 +795,7 @@
                     // Transitioned to GONE
                     GONE,
                 ),
-                currentStates
+                currentStates,
             )
 
             sendSteps(
@@ -1290,12 +812,10 @@
                     // Current state should not be DOZING until the post-cancelation transition is
                     // STARTED
                 ),
-                currentStates
+                currentStates,
             )
 
-            sendSteps(
-                TransitionStep(DOZING, LOCKSCREEN, 0f, STARTED),
-            )
+            sendSteps(TransitionStep(DOZING, LOCKSCREEN, 0f, STARTED))
 
             assertEquals(
                 listOf(
@@ -1305,7 +825,7 @@
                     // DOZING -> LS STARTED, DOZING is now the current state.
                     DOZING,
                 ),
-                currentStates
+                currentStates,
             )
 
             sendSteps(
@@ -1313,19 +833,9 @@
                 TransitionStep(DOZING, LOCKSCREEN, 0.6f, CANCELED),
             )
 
-            assertEquals(
-                listOf(
-                    OFF,
-                    LOCKSCREEN,
-                    GONE,
-                    DOZING,
-                ),
-                currentStates
-            )
+            assertEquals(listOf(OFF, LOCKSCREEN, GONE, DOZING), currentStates)
 
-            sendSteps(
-                TransitionStep(LOCKSCREEN, GONE, 0f, STARTED),
-            )
+            sendSteps(TransitionStep(LOCKSCREEN, GONE, 0f, STARTED))
 
             assertEquals(
                 listOf(
@@ -1336,7 +846,7 @@
                     // LS -> GONE STARTED, LS is now the current state.
                     LOCKSCREEN,
                 ),
-                currentStates
+                currentStates,
             )
 
             sendSteps(
@@ -1354,7 +864,7 @@
                     // FINISHED in GONE, GONE is now the current state.
                     GONE,
                 ),
-                currentStates
+                currentStates,
             )
         }
 
@@ -1504,6 +1014,126 @@
             }
         }
 
+    @Test
+    @EnableSceneContainer
+    fun simulateTransitionStepsForSceneTransitions_emits_correct_values_for_wildcard_from_edge() =
+        testScope.runTest {
+            val sceneToSceneSteps by
+                collectValues(underTest.transition(Edge.create(from = Scenes.Gone)))
+            val progress = MutableSharedFlow<Float>()
+
+            kosmos.setSceneTransition(
+                Transition(Scenes.Gone, Scenes.Lockscreen, progress = progress)
+            )
+
+            progress.emit(0.2f)
+            runCurrent()
+            progress.emit(0.6f)
+            runCurrent()
+
+            kosmos.setSceneTransition(Transition(Scenes.Gone, Scenes.Bouncer, progress = progress))
+
+            progress.emit(0.1f)
+            runCurrent()
+
+            kosmos.setSceneTransition(
+                Transition(Scenes.Bouncer, Scenes.Lockscreen, progress = progress)
+            )
+
+            progress.emit(0.3f)
+            runCurrent()
+
+            kosmos.setSceneTransition(Idle(Scenes.Gone))
+
+            assertEquals(
+                listOf(
+                    TransitionStep(UNDEFINED, UNDEFINED, 0f, STARTED),
+                    TransitionStep(UNDEFINED, UNDEFINED, 0.2f, RUNNING),
+                    TransitionStep(UNDEFINED, UNDEFINED, 0.6f, RUNNING),
+                    TransitionStep(UNDEFINED, UNDEFINED, 1f, FINISHED),
+                    TransitionStep(UNDEFINED, UNDEFINED, 0f, STARTED),
+                    TransitionStep(UNDEFINED, UNDEFINED, 0.1f, RUNNING),
+                    TransitionStep(UNDEFINED, UNDEFINED, 1f, FINISHED),
+                ),
+                sceneToSceneSteps,
+            )
+        }
+
+    @Test
+    @EnableSceneContainer
+    fun simulateTransitionStepsForSceneTransitions_emits_correct_values_for_wildcard_to_edge() =
+        testScope.runTest {
+            val sceneToSceneSteps by
+                collectValues(underTest.transition(Edge.create(to = Scenes.Gone)))
+            val progress = MutableSharedFlow<Float>()
+
+            kosmos.setSceneTransition(
+                Transition(Scenes.Gone, Scenes.Lockscreen, progress = progress)
+            )
+
+            progress.emit(0.2f)
+            runCurrent()
+
+            kosmos.setSceneTransition(Idle(Scenes.Gone))
+
+            kosmos.setSceneTransition(Transition(Scenes.Gone, Scenes.Bouncer, progress = progress))
+
+            progress.emit(0.1f)
+            runCurrent()
+
+            kosmos.setSceneTransition(Transition(Scenes.Bouncer, Scenes.Gone, progress = progress))
+
+            progress.emit(0.3f)
+            runCurrent()
+
+            kosmos.setSceneTransition(Idle(Scenes.Gone))
+
+            assertEquals(
+                listOf(
+                    TransitionStep(UNDEFINED, UNDEFINED, 0f, STARTED),
+                    TransitionStep(UNDEFINED, UNDEFINED, 0.3f, RUNNING),
+                    TransitionStep(UNDEFINED, UNDEFINED, 1f, FINISHED),
+                ),
+                sceneToSceneSteps,
+            )
+        }
+
+    @Test
+    @EnableSceneContainer
+    fun flatMapLatestWithFinished_emission_of_previous_progress_flow_is_not_interleaving() =
+        testScope.runTest {
+            val sceneToSceneSteps by
+                collectValues(underTest.transition(Edge.create(from = Scenes.Gone)))
+            val progress1 = MutableSharedFlow<Float>()
+            val progress2 = MutableSharedFlow<Float>()
+
+            kosmos.setSceneTransition(
+                Transition(Scenes.Gone, Scenes.Lockscreen, progress = progress1)
+            )
+
+            progress1.emit(0.1f)
+            runCurrent()
+
+            kosmos.setSceneTransition(Transition(Scenes.Gone, Scenes.Bouncer, progress = progress2))
+
+            progress2.emit(0.3f)
+            runCurrent()
+
+            progress1.emit(0.2f)
+            runCurrent()
+
+            assertEquals(
+                listOf(
+                    TransitionStep(UNDEFINED, UNDEFINED, 0f, STARTED),
+                    TransitionStep(UNDEFINED, UNDEFINED, 0.1f, RUNNING),
+                    TransitionStep(UNDEFINED, UNDEFINED, 1f, FINISHED),
+                    TransitionStep(UNDEFINED, UNDEFINED, 0f, STARTED),
+                    TransitionStep(UNDEFINED, UNDEFINED, 0.3f, RUNNING),
+                ),
+                sceneToSceneSteps,
+            )
+        }
+
     private suspend fun sendSteps(vararg steps: TransitionStep) {
         steps.forEach {
             repository.sendTransitionStep(it)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt
index a617484..8f3d549 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt
@@ -41,9 +41,9 @@
 import com.android.systemui.flags.Flags.COMMUNAL_SERVICE_ENABLED
 import com.android.systemui.flags.andSceneContainer
 import com.android.systemui.flags.fakeFeatureFlagsClassic
-import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
 import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository
-import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
+import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepositorySpy
+import com.android.systemui.keyguard.data.repository.keyguardTransitionRepository
 import com.android.systemui.keyguard.shared.model.BiometricUnlockMode
 import com.android.systemui.keyguard.shared.model.DozeStateModel
 import com.android.systemui.keyguard.shared.model.DozeTransitionModel
@@ -76,7 +76,6 @@
 import org.mockito.Mock
 import org.mockito.Mockito.clearInvocations
 import org.mockito.Mockito.reset
-import org.mockito.Mockito.spy
 import org.mockito.MockitoAnnotations
 import platform.test.runner.parameterized.ParameterizedAndroidJunit4
 import platform.test.runner.parameterized.Parameters
@@ -91,7 +90,7 @@
 class KeyguardTransitionScenariosTest(flags: FlagsParameterization?) : SysuiTestCase() {
     private val kosmos =
         testKosmos().apply {
-            fakeKeyguardTransitionRepository = spy(FakeKeyguardTransitionRepository())
+            this.keyguardTransitionRepository = fakeKeyguardTransitionRepositorySpy
         }
     private val testScope = kosmos.testScope
 
@@ -99,7 +98,7 @@
     private val keyguardInteractor by lazy { kosmos.keyguardInteractor }
     private val bouncerRepository by lazy { kosmos.fakeKeyguardBouncerRepository }
     private val shadeTestUtil by lazy { kosmos.shadeTestUtil }
-    private val transitionRepository by lazy { kosmos.fakeKeyguardTransitionRepository }
+    private val transitionRepository by lazy { kosmos.fakeKeyguardTransitionRepositorySpy }
     private lateinit var featureFlags: FakeFeatureFlags
 
     // Used to verify transition requests for test output
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/binder/WindowManagerLockscreenVisibilityManagerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/binder/WindowManagerLockscreenVisibilityManagerTest.kt
index 43c7ed6..9c58e2b 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/binder/WindowManagerLockscreenVisibilityManagerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/binder/WindowManagerLockscreenVisibilityManagerTest.kt
@@ -25,6 +25,7 @@
 import com.android.systemui.statusbar.policy.KeyguardStateController
 import com.android.systemui.util.concurrency.FakeExecutor
 import com.android.systemui.util.time.FakeSystemClock
+import com.android.wm.shell.keyguard.KeyguardTransitions
 import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -46,6 +47,7 @@
     @Mock private lateinit var keyguardSurfaceBehindAnimator: KeyguardSurfaceBehindParamsApplier
     @Mock
     private lateinit var keyguardDismissTransitionInteractor: KeyguardDismissTransitionInteractor
+    @Mock private lateinit var keyguardTransitions: KeyguardTransitions
 
     @Before
     fun setUp() {
@@ -59,6 +61,7 @@
                 keyguardStateController = keyguardStateController,
                 keyguardSurfaceBehindAnimator = keyguardSurfaceBehindAnimator,
                 keyguardDismissTransitionInteractor = keyguardDismissTransitionInteractor,
+                keyguardTransitions = keyguardTransitions,
             )
     }
 
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryBackgroundViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryBackgroundViewModelTest.kt
new file mode 100644
index 0000000..22677b2
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryBackgroundViewModelTest.kt
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.keyguard.ui.viewmodel
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.biometrics.data.repository.fingerprintPropertyRepository
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
+import com.android.systemui.keyguard.shared.model.KeyguardState
+import com.android.systemui.keyguard.shared.model.TransitionState
+import com.android.systemui.keyguard.shared.model.TransitionState.RUNNING
+import com.android.systemui.keyguard.shared.model.TransitionState.STARTED
+import com.android.systemui.keyguard.shared.model.TransitionStep
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.testKosmos
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@ExperimentalCoroutinesApi
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class DeviceEntryBackgroundViewModelTest : SysuiTestCase() {
+    private val kosmos = testKosmos()
+    private val testScope = kosmos.testScope
+    private val underTest: DeviceEntryBackgroundViewModel by lazy {
+        kosmos.deviceEntryBackgroundViewModel
+    }
+
+    @Test
+    fun lockscreenToDozingTransitionChangesBackgroundViewAlphaToZero() =
+        testScope.runTest {
+            kosmos.fingerprintPropertyRepository.supportsUdfps()
+            val alpha by collectLastValue(underTest.alpha)
+
+            kosmos.fakeKeyguardTransitionRepository.sendTransitionSteps(
+                listOf(dozingToLockscreen(0f, STARTED), dozingToLockscreen(0.1f)),
+                testScope,
+            )
+            runCurrent()
+            assertThat(alpha).isEqualTo(1.0f)
+
+            kosmos.fakeKeyguardTransitionRepository.sendTransitionSteps(
+                listOf(lockscreenToDozing(0f, STARTED)),
+                testScope,
+            )
+            runCurrent()
+
+            assertThat(alpha).isEqualTo(0.0f)
+        }
+
+    private fun lockscreenToDozing(value: Float, state: TransitionState = RUNNING): TransitionStep {
+        return TransitionStep(
+            from = KeyguardState.LOCKSCREEN,
+            to = KeyguardState.DOZING,
+            value = value,
+            transitionState = state,
+            ownerName = "DeviceEntryBackgroundViewModelTest",
+        )
+    }
+
+    private fun dozingToLockscreen(value: Float, state: TransitionState = RUNNING): TransitionStep {
+        return TransitionStep(
+            from = KeyguardState.DOZING,
+            to = KeyguardState.LOCKSCREEN,
+            value = value,
+            transitionState = state,
+            ownerName = "DeviceEntryBackgroundViewModelTest",
+        )
+    }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelTest.kt
index 5186536..12eadfc 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelTest.kt
@@ -184,17 +184,6 @@
         }
 
     @Test
-    fun iconContainer_isVisible_bypassEnabled() =
-        testScope.runTest {
-            val isVisible by collectLastValue(underTest.isNotifIconContainerVisible)
-            runCurrent()
-            deviceEntryRepository.setBypassEnabled(true)
-            runCurrent()
-
-            assertThat(isVisible?.value).isTrue()
-        }
-
-    @Test
     fun iconContainer_isNotVisible_pulseExpanding_notBypassing() =
         testScope.runTest {
             val isVisible by collectLastValue(underTest.isNotifIconContainerVisible)
@@ -283,22 +272,23 @@
         }
 
     @Test
-    fun iconContainer_isNotVisible_bypassDisabled_onLockscreen() =
+    fun iconContainer_isNotVisible_notifsFullyHiddenThenVisible_bypassEnabled() =
         testScope.runTest {
             val isVisible by collectLastValue(underTest.isNotifIconContainerVisible)
             runCurrent()
-            keyguardTransitionRepository.sendTransitionSteps(
-                from = KeyguardState.AOD,
-                to = KeyguardState.LOCKSCREEN,
-                testScope,
-            )
             notificationsKeyguardInteractor.setPulseExpanding(false)
-            deviceEntryRepository.setBypassEnabled(false)
+            deviceEntryRepository.setBypassEnabled(true)
             whenever(dozeParameters.alwaysOn).thenReturn(true)
             whenever(dozeParameters.displayNeedsBlanking).thenReturn(false)
             notificationsKeyguardInteractor.setNotificationsFullyHidden(true)
             runCurrent()
 
+            assertThat(isVisible?.value).isTrue()
+            assertThat(isVisible?.isAnimating).isTrue()
+
+            notificationsKeyguardInteractor.setNotificationsFullyHidden(false)
+            runCurrent()
+
             assertThat(isVisible?.value).isFalse()
             assertThat(isVisible?.isAnimating).isTrue()
         }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/lifecycle/HydratorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/lifecycle/HydratorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/lifecycle/HydratorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/lifecycle/HydratorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/views/NavigationBarButtonTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/navigationbar/views/NavigationBarButtonTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/navigationbar/views/NavigationBarButtonTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/navigationbar/views/NavigationBarButtonTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyDialogControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/privacy/PrivacyDialogControllerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyDialogControllerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/privacy/PrivacyDialogControllerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyDialogControllerV2Test.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/privacy/PrivacyDialogControllerV2Test.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyDialogControllerV2Test.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/privacy/PrivacyDialogControllerV2Test.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qrcodescanner/controller/QRCodeScannerControllerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/qrcodescanner/controller/QRCodeScannerControllerTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/qrcodescanner/controller/QRCodeScannerControllerTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/qrcodescanner/controller/QRCodeScannerControllerTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/TileLayoutTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/TileLayoutTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/qs/TileLayoutTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/qs/TileLayoutTest.java
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/data/repository/QSColumnsRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/data/repository/QSColumnsRepositoryTest.kt
new file mode 100644
index 0000000..fd1f52b
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/data/repository/QSColumnsRepositoryTest.kt
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.panels.data.repository
+
+import android.platform.test.annotations.EnableFlags
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.common.ui.data.repository.fakeConfigurationRepository
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.kosmos.testCase
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.res.R
+import com.android.systemui.shade.shared.flag.DualShade
+import com.android.systemui.testKosmos
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class QSColumnsRepositoryTest : SysuiTestCase() {
+    private val kosmos = testKosmos()
+    private lateinit var underTest: QSColumnsRepository
+
+    @Before
+    fun setUp() {
+        underTest = with(kosmos) { qsColumnsRepository }
+    }
+
+    @Test
+    fun configChanges_triggerColumnsUpdate() =
+        with(kosmos) {
+            testScope.runTest {
+                val latest by collectLastValue(underTest.columns)
+
+                setColumnsInConfig(4)
+                assertThat(latest).isEqualTo(4)
+
+                setColumnsInConfig(8)
+                assertThat(latest).isEqualTo(8)
+            }
+        }
+
+    @Test
+    @EnableFlags(DualShade.FLAG_NAME)
+    fun withDualShade_returnsCorrectValue() =
+        with(kosmos) {
+            testScope.runTest {
+                val latest by collectLastValue(underTest.columns)
+                assertThat(latest).isEqualTo(4)
+
+                setColumnsInConfig(8, id = R.integer.quick_settings_dual_shade_num_columns)
+                // Asserts config changes are ignored
+                assertThat(latest).isEqualTo(4)
+            }
+        }
+
+    private fun setColumnsInConfig(
+        columns: Int,
+        id: Int = R.integer.quick_settings_infinite_grid_num_columns,
+    ) =
+        with(kosmos) {
+            testCase.context.orCreateTestableResources.addOverride(id, columns)
+            fakeConfigurationRepository.onConfigurationChange()
+        }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/viewmodel/QuickQuickSettingsViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/viewmodel/QuickQuickSettingsViewModelTest.kt
index ef85302..a1c0ef2 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/viewmodel/QuickQuickSettingsViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/viewmodel/QuickQuickSettingsViewModelTest.kt
@@ -58,6 +58,11 @@
             qsPreferencesInteractor.setLargeTilesSpecs(
                 tiles.filter { it.spec.startsWith(PREFIX_LARGE) }.toSet()
             )
+            testCase.context.orCreateTestableResources.addOverride(
+                R.integer.quick_settings_infinite_grid_num_columns,
+                4,
+            )
+            fakeConfigurationRepository.onConfigurationChange()
         }
 
     private val underTest = kosmos.quickQuickSettingsViewModel
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/HearingDevicesTileTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/HearingDevicesTileTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/qs/tiles/HearingDevicesTileTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/HearingDevicesTileTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/InternetTileNewImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/InternetTileNewImplTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/qs/tiles/InternetTileNewImplTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/InternetTileNewImplTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ModesTileTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/ModesTileTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ModesTileTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/ModesTileTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/RecordIssueTileTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/RecordIssueTileTest.kt
similarity index 91%
rename from packages/SystemUI/tests/src/com/android/systemui/qs/tiles/RecordIssueTileTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/RecordIssueTileTest.kt
index ca518f9..c7da03d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/RecordIssueTileTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/RecordIssueTileTest.kt
@@ -17,6 +17,7 @@
 package com.android.systemui.qs.tiles
 
 import android.os.Handler
+import android.os.Looper
 import android.service.quicksettings.Tile
 import android.testing.TestableLooper
 import androidx.test.ext.junit.runners.AndroidJUnit4
@@ -31,9 +32,10 @@
 import com.android.systemui.qs.QsEventLogger
 import com.android.systemui.qs.logging.QSLogger
 import com.android.systemui.qs.pipeline.domain.interactor.PanelInteractor
+import com.android.systemui.recordissue.IssueRecordingServiceConnection
 import com.android.systemui.recordissue.IssueRecordingState
 import com.android.systemui.recordissue.RecordIssueDialogDelegate
-import com.android.systemui.recordissue.TraceurMessageSender
+import com.android.systemui.recordissue.TraceurConnection
 import com.android.systemui.res.R
 import com.android.systemui.screenrecord.RecordingController
 import com.android.systemui.settings.UserContextProvider
@@ -75,13 +77,14 @@
     @Mock private lateinit var panelInteractor: PanelInteractor
     @Mock private lateinit var userContextProvider: UserContextProvider
     @Mock private lateinit var issueRecordingState: IssueRecordingState
-    @Mock private lateinit var traceurMessageSender: TraceurMessageSender
     @Mock private lateinit var delegateFactory: RecordIssueDialogDelegate.Factory
     @Mock private lateinit var dialogDelegate: RecordIssueDialogDelegate
     @Mock private lateinit var dialog: SystemUIDialog
 
     private lateinit var testableLooper: TestableLooper
     private lateinit var tile: RecordIssueTile
+    private lateinit var irsConnProvider: IssueRecordingServiceConnection.Provider
+    private lateinit var traceurConnProvider: TraceurConnection.Provider
 
     @Before
     fun setUp() {
@@ -90,6 +93,10 @@
         whenever(delegateFactory.create(any())).thenReturn(dialogDelegate)
         whenever(dialogDelegate.createDialog()).thenReturn(dialog)
 
+        irsConnProvider = IssueRecordingServiceConnection.Provider(userContextProvider)
+        traceurConnProvider =
+            TraceurConnection.Provider(userContextProvider, Looper.getMainLooper())
+
         testableLooper = TestableLooper.get(this)
         tile =
             RecordIssueTile(
@@ -107,7 +114,8 @@
                 dialogLauncherAnimator,
                 panelInteractor,
                 userContextProvider,
-                traceurMessageSender,
+                irsConnProvider,
+                traceurConnProvider,
                 Executors.newSingleThreadExecutor(),
                 issueRecordingState,
                 delegateFactory,
@@ -169,7 +177,7 @@
             .executeWhenUnlocked(
                 isA(ActivityStarter.OnDismissAction::class.java),
                 eq(false),
-                eq(true)
+                eq(true),
             )
     }
 }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/modes/domain/interactor/ModesTileDataInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/modes/domain/interactor/ModesTileDataInteractorTest.kt
index de3dc57..1d80826 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/modes/domain/interactor/ModesTileDataInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/modes/domain/interactor/ModesTileDataInteractorTest.kt
@@ -28,6 +28,7 @@
 import com.android.settingslib.notification.modes.TestModeBuilder
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.SysuiTestableContext
+import com.android.systemui.common.shared.model.Icon
 import com.android.systemui.common.shared.model.asIcon
 import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.coroutines.collectValues
@@ -144,13 +145,13 @@
 
             // Tile starts with the generic Modes icon.
             runCurrent()
-            assertThat(tileData?.icon).isEqualTo(MODES_ICON)
+            assertThat(tileData?.icon).isEqualTo(MODES_RESOURCE_ICON)
             assertThat(tileData?.iconResId).isEqualTo(MODES_DRAWABLE_ID)
 
             // Add an inactive mode -> Still modes icon
             zenModeRepository.addMode(id = "Mode", active = false)
             runCurrent()
-            assertThat(tileData?.icon).isEqualTo(MODES_ICON)
+            assertThat(tileData?.icon).isEqualTo(MODES_RESOURCE_ICON)
             assertThat(tileData?.iconResId).isEqualTo(MODES_DRAWABLE_ID)
 
             // Add an active mode with a default icon: icon should be the mode icon, and the
@@ -158,7 +159,7 @@
             zenModeRepository.addMode(
                 id = "Bedtime with default icon",
                 type = AutomaticZenRule.TYPE_BEDTIME,
-                active = true
+                active = true,
             )
             runCurrent()
             assertThat(tileData?.icon).isEqualTo(BEDTIME_ICON)
@@ -189,7 +190,7 @@
             // Deactivate remaining mode: back to the default modes icon
             zenModeRepository.deactivateMode("Driving with custom icon")
             runCurrent()
-            assertThat(tileData?.icon).isEqualTo(MODES_ICON)
+            assertThat(tileData?.icon).isEqualTo(MODES_RESOURCE_ICON)
             assertThat(tileData?.iconResId).isEqualTo(MODES_DRAWABLE_ID)
         }
 
@@ -204,18 +205,18 @@
                 )
 
             runCurrent()
-            assertThat(tileData?.icon).isEqualTo(MODES_ICON)
+            assertThat(tileData?.icon).isEqualTo(MODES_RESOURCE_ICON)
             assertThat(tileData?.iconResId).isEqualTo(MODES_DRAWABLE_ID)
 
             // Activate a Mode -> Icon doesn't change.
             zenModeRepository.addMode(id = "Mode", active = true)
             runCurrent()
-            assertThat(tileData?.icon).isEqualTo(MODES_ICON)
+            assertThat(tileData?.icon).isEqualTo(MODES_RESOURCE_ICON)
             assertThat(tileData?.iconResId).isEqualTo(MODES_DRAWABLE_ID)
 
             zenModeRepository.deactivateMode(id = "Mode")
             runCurrent()
-            assertThat(tileData?.icon).isEqualTo(MODES_ICON)
+            assertThat(tileData?.icon).isEqualTo(MODES_RESOURCE_ICON)
             assertThat(tileData?.iconResId).isEqualTo(MODES_DRAWABLE_ID)
         }
 
@@ -263,7 +264,7 @@
         val BEDTIME_DRAWABLE = TestStubDrawable("bedtime")
         val CUSTOM_DRAWABLE = TestStubDrawable("custom")
 
-        val MODES_ICON = MODES_DRAWABLE.asIcon()
+        val MODES_RESOURCE_ICON = Icon.Resource(MODES_DRAWABLE_ID, null)
         val BEDTIME_ICON = BEDTIME_DRAWABLE.asIcon()
         val CUSTOM_ICON = CUSTOM_DRAWABLE.asIcon()
     }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/modes/ui/ModesTileMapperTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/modes/ui/ModesTileMapperTest.kt
index c3d45db..a58cb9c 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/modes/ui/ModesTileMapperTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/modes/ui/ModesTileMapperTest.kt
@@ -22,7 +22,9 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
+import com.android.systemui.common.shared.model.Icon
 import com.android.systemui.common.shared.model.asIcon
+import com.android.systemui.qs.tiles.ModesTile
 import com.android.systemui.qs.tiles.impl.modes.domain.model.ModesTileModel
 import com.android.systemui.qs.tiles.viewmodel.QSTileConfigTestBuilder
 import com.android.systemui.qs.tiles.viewmodel.QSTileState
@@ -51,6 +53,11 @@
                 .apply {
                     addOverride(R.drawable.qs_dnd_icon_on, TestStubDrawable())
                     addOverride(R.drawable.qs_dnd_icon_off, TestStubDrawable())
+                    addOverride(
+                        ModesTile.ICON_RES_ID,
+                        TestStubDrawable(ModesTile.ICON_RES_ID.toString()),
+                    )
+                    addOverride(123, TestStubDrawable("123"))
                 }
                 .resources,
             context.theme,
@@ -59,12 +66,7 @@
     @Test
     fun inactiveState() {
         val icon = TestStubDrawable("res123").asIcon()
-        val model =
-            ModesTileModel(
-                isActivated = false,
-                activeModes = emptyList(),
-                icon = icon,
-            )
+        val model = ModesTileModel(isActivated = false, activeModes = emptyList(), icon = icon)
 
         val state = underTest.map(config, model)
 
@@ -76,12 +78,7 @@
     @Test
     fun activeState_oneMode() {
         val icon = TestStubDrawable("res123").asIcon()
-        val model =
-            ModesTileModel(
-                isActivated = true,
-                activeModes = listOf("DND"),
-                icon = icon,
-            )
+        val model = ModesTileModel(isActivated = true, activeModes = listOf("DND"), icon = icon)
 
         val state = underTest.map(config, model)
 
@@ -108,19 +105,36 @@
     }
 
     @Test
-    fun state_modelHasIconResId_includesIconResId() {
-        val icon = TestStubDrawable("res123").asIcon()
+    fun resourceIconModel_whenResIdsIdentical_mapsToLoadedIconWithInputResId() {
+        val icon = Icon.Resource(123, null)
         val model =
             ModesTileModel(
                 isActivated = false,
                 activeModes = emptyList(),
                 icon = icon,
-                iconResId = 123
+                iconResId = 123,
             )
 
         val state = underTest.map(config, model)
 
-        assertThat(state.icon()).isEqualTo(icon)
+        assertThat(state.icon()).isEqualTo(TestStubDrawable("123").asIcon())
+        assertThat(state.iconRes).isEqualTo(123)
+    }
+
+    @Test
+    fun resourceIconModel_whenResIdsNonIdentical_mapsToLoadedIconWithIconResourceId() {
+        val icon = Icon.Resource(123, null)
+        val model =
+            ModesTileModel(
+                isActivated = false,
+                activeModes = emptyList(),
+                icon = icon,
+                iconResId = 321, // Note: NOT 123. This will be ignored.
+            )
+
+        val state = underTest.map(config, model)
+
+        assertThat(state.icon()).isEqualTo(TestStubDrawable("123").asIcon())
         assertThat(state.iconRes).isEqualTo(123)
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsUserActionsViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsUserActionsViewModelTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsUserActionsViewModelTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsUserActionsViewModelTest.kt
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/recordissue/IssueRecordingServiceSessionTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/recordissue/IssueRecordingServiceSessionTest.kt
index 3e5dee6..a1edfc1 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/recordissue/IssueRecordingServiceSessionTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/recordissue/IssueRecordingServiceSessionTest.kt
@@ -53,7 +53,7 @@
     private val bgExecutor = kosmos.fakeExecutor
     private val userContextProvider: UserContextProvider = kosmos.userTracker
     private val dialogTransitionAnimator: DialogTransitionAnimator = kosmos.dialogTransitionAnimator
-    private lateinit var traceurMessageSender: TraceurMessageSender
+    private lateinit var traceurConnection: TraceurConnection
     private val issueRecordingState =
         IssueRecordingState(kosmos.userTracker, kosmos.userFileManager)
 
@@ -65,13 +65,13 @@
 
     @Before
     fun setup() {
-        traceurMessageSender = mock<TraceurMessageSender>()
+        traceurConnection = mock<TraceurConnection>()
         underTest =
             IssueRecordingServiceSession(
                 bgExecutor,
                 dialogTransitionAnimator,
                 panelInteractor,
-                traceurMessageSender,
+                traceurConnection,
                 issueRecordingState,
                 iActivityManager,
                 notificationManager,
@@ -85,7 +85,7 @@
         bgExecutor.runAllReady()
 
         Truth.assertThat(issueRecordingState.isRecording).isTrue()
-        verify(traceurMessageSender).startTracing(any<TraceConfig>())
+        verify(traceurConnection).startTracing(any<TraceConfig>())
     }
 
     @Test
@@ -94,12 +94,12 @@
         bgExecutor.runAllReady()
 
         Truth.assertThat(issueRecordingState.isRecording).isFalse()
-        verify(traceurMessageSender).stopTracing()
+        verify(traceurConnection).stopTracing()
     }
 
     @Test
     fun cancelsNotification_afterReceivingShareCommand() {
-        underTest.share(0, null, mContext)
+        underTest.share(0, null)
         bgExecutor.runAllReady()
 
         verify(notificationManager).cancelAsUser(isNull(), anyInt(), any<UserHandle>())
@@ -110,7 +110,7 @@
         issueRecordingState.takeBugreport = true
         val uri = mock<Uri>()
 
-        underTest.share(0, uri, mContext)
+        underTest.share(0, uri)
         bgExecutor.runAllReady()
 
         verify(iActivityManager).requestBugReportWithExtraAttachment(uri)
@@ -121,17 +121,17 @@
         issueRecordingState.takeBugreport = false
         val uri = mock<Uri>()
 
-        underTest.share(0, uri, mContext)
+        underTest.share(0, uri)
         bgExecutor.runAllReady()
 
-        verify(traceurMessageSender).shareTraces(mContext, uri)
+        verify(traceurConnection).shareTraces(uri)
     }
 
     @Test
     fun closesShade_afterReceivingShareCommand() {
         val uri = mock<Uri>()
 
-        underTest.share(0, uri, mContext)
+        underTest.share(0, uri)
         bgExecutor.runAllReady()
 
         verify(panelInteractor).collapsePanels()
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/recordissue/TraceurConnectionTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/recordissue/TraceurConnectionTest.kt
new file mode 100644
index 0000000..d90cca9
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/recordissue/TraceurConnectionTest.kt
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.recordissue
+
+import android.os.IBinder
+import android.os.Looper
+import android.os.Messenger
+import android.testing.TestableLooper
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.settings.UserContextProvider
+import com.android.traceur.PresetTraceConfigs
+import java.util.concurrent.CountDownLatch
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Mockito.mock
+import org.mockito.MockitoAnnotations
+import org.mockito.kotlin.any
+import org.mockito.kotlin.verify
+import org.mockito.kotlin.whenever
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
+class TraceurConnectionTest : SysuiTestCase() {
+
+    @Mock private lateinit var userContextProvider: UserContextProvider
+
+    private lateinit var underTest: TraceurConnection
+
+    @Before
+    fun setup() {
+        MockitoAnnotations.initMocks(this)
+        whenever(userContextProvider.userContext).thenReturn(mContext)
+        underTest = TraceurConnection.Provider(userContextProvider, Looper.getMainLooper()).create()
+    }
+
+    @Test
+    fun onBoundRunnables_areRun_whenServiceIsBound() {
+        val latch = CountDownLatch(1)
+        underTest.onBound.add { latch.countDown() }
+
+        underTest.onServiceConnected(
+            InstrumentationRegistry.getInstrumentation().componentName,
+            mock(IBinder::class.java),
+        )
+
+        latch.await()
+    }
+
+    @Test
+    fun startTracing_sendsMsg_toStartTracing() {
+        underTest.binder = mock(Messenger::class.java)
+
+        underTest.startTracing(PresetTraceConfigs.getThermalConfig())
+
+        verify(underTest.binder)!!.send(any())
+    }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/recordissue/UserAwareConnectionTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/recordissue/UserAwareConnectionTest.kt
new file mode 100644
index 0000000..f671bf4
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/recordissue/UserAwareConnectionTest.kt
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.recordissue
+
+import android.content.Context
+import android.content.Intent
+import android.testing.TestableLooper
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.settings.UserContextProvider
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers.anyInt
+import org.mockito.Mock
+import org.mockito.Mockito.any
+import org.mockito.MockitoAnnotations
+import org.mockito.kotlin.times
+import org.mockito.kotlin.verify
+import org.mockito.kotlin.whenever
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
+class UserAwareConnectionTest : SysuiTestCase() {
+
+    @Mock private lateinit var userContextProvider: UserContextProvider
+    @Mock private lateinit var mockContext: Context
+
+    private lateinit var underTest: UserAwareConnection
+
+    @Before
+    fun setup() {
+        MockitoAnnotations.initMocks(this)
+        whenever(userContextProvider.userContext).thenReturn(mockContext)
+        whenever(mockContext.bindService(any(), any(), anyInt())).thenReturn(true)
+        underTest = UserAwareConnection(userContextProvider, Intent())
+    }
+
+    @Test
+    fun doBindService_requestToBindToTheService_viaTheCorrectUserContext() {
+        underTest.doBind()
+
+        verify(userContextProvider).userContext
+    }
+
+    @Test
+    fun doBindService_DoesntRequestToBindToTheService_IfAlreadyRequested() {
+        underTest.doBind()
+        underTest.doBind()
+        underTest.doBind()
+
+        verify(userContextProvider, times(1)).userContext
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingServiceTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/screenrecord/RecordingServiceTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingServiceTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/screenrecord/RecordingServiceTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialogDelegateTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialogDelegateTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialogDelegateTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialogDelegateTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenrecord/data/model/ScreenRecordModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/screenrecord/data/model/ScreenRecordModelTest.kt
similarity index 96%
rename from packages/SystemUI/tests/src/com/android/systemui/screenrecord/data/model/ScreenRecordModelTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/screenrecord/data/model/ScreenRecordModelTest.kt
index 9331c8d..0bbf47c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenrecord/data/model/ScreenRecordModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/screenrecord/data/model/ScreenRecordModelTest.kt
@@ -16,13 +16,16 @@
 
 package com.android.systemui.screenrecord.data.model
 
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.screenrecord.data.model.ScreenRecordModel.Starting.Companion.toCountdownSeconds
 import com.google.common.truth.Truth.assertThat
+import org.junit.runner.RunWith
 import kotlin.test.Test
 
 @SmallTest
+@RunWith(AndroidJUnit4::class)
 class ScreenRecordModelTest : SysuiTestCase() {
     @Test
     fun countdownSeconds_millis0_is0() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenrecord/data/repository/ScreenRecordRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/screenrecord/data/repository/ScreenRecordRepositoryTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/screenrecord/data/repository/ScreenRecordRepositoryTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/screenrecord/data/repository/ScreenRecordRepositoryTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ActionIntentExecutorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/ActionIntentExecutorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/screenshot/ActionIntentExecutorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/ActionIntentExecutorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/AnnouncementResolverTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/AnnouncementResolverTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/screenshot/AnnouncementResolverTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/AnnouncementResolverTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/DraggableConstraintLayoutTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/DraggableConstraintLayoutTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/screenshot/DraggableConstraintLayoutTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/DraggableConstraintLayoutTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/FakeImageCapture.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/FakeImageCapture.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/screenshot/FakeImageCapture.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/FakeImageCapture.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/FakeScreenshotPolicy.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/FakeScreenshotPolicy.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/screenshot/FakeScreenshotPolicy.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/FakeScreenshotPolicy.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/MessageContainerControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/MessageContainerControllerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/screenshot/MessageContainerControllerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/MessageContainerControllerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/RecyclerViewActivity.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/RecyclerViewActivity.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/screenshot/RecyclerViewActivity.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/RecyclerViewActivity.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotActionsControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/ScreenshotActionsControllerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotActionsControllerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/ScreenshotActionsControllerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotDataTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/ScreenshotDataTest.kt
similarity index 95%
rename from packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotDataTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/ScreenshotDataTest.kt
index 1d74e8b..4ede90e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotDataTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/ScreenshotDataTest.kt
@@ -53,8 +53,8 @@
 
         assertThat(data.source).isEqualTo(source)
         assertThat(data.type).isEqualTo(type)
-        assertThat(data.screenBounds).isEqualTo(bounds)
-        assertThat(data.insets).isEqualTo(insets)
+        assertThat(data.originalScreenBounds).isEqualTo(bounds)
+        assertThat(data.originalInsets).isEqualTo(insets)
         assertThat(data.taskId).isEqualTo(taskId)
         assertThat(data.userHandle).isEqualTo(UserHandle.of(userId))
         assertThat(data.topComponent).isEqualTo(component)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotNotificationSmartActionsTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/ScreenshotNotificationSmartActionsTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotNotificationSmartActionsTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/ScreenshotNotificationSmartActionsTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotSoundControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/ScreenshotSoundControllerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotSoundControllerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/ScreenshotSoundControllerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/SmartActionsReceiverTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/SmartActionsReceiverTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/screenshot/SmartActionsReceiverTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/SmartActionsReceiverTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/TakeScreenshotExecutorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/TakeScreenshotExecutorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/screenshot/TakeScreenshotExecutorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/TakeScreenshotExecutorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/WorkProfileMessageControllerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/WorkProfileMessageControllerTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/screenshot/WorkProfileMessageControllerTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/WorkProfileMessageControllerTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/appclips/AppClipsScreenshotHelperServiceTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/appclips/AppClipsScreenshotHelperServiceTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/screenshot/appclips/AppClipsScreenshotHelperServiceTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/appclips/AppClipsScreenshotHelperServiceTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/appclips/AppClipsServiceTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/appclips/AppClipsServiceTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/screenshot/appclips/AppClipsServiceTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/appclips/AppClipsServiceTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/data/model/DisplayContentScenarios.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/data/model/DisplayContentScenarios.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/screenshot/data/model/DisplayContentScenarios.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/data/model/DisplayContentScenarios.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/data/repository/ProfileTypeRepositoryKosmos.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/data/repository/ProfileTypeRepositoryKosmos.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/screenshot/data/repository/ProfileTypeRepositoryKosmos.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/data/repository/ProfileTypeRepositoryKosmos.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/message/ProfileMessageControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/message/ProfileMessageControllerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/screenshot/message/ProfileMessageControllerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/message/ProfileMessageControllerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/policy/NewRootTaskInfo.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/policy/NewRootTaskInfo.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/screenshot/policy/NewRootTaskInfo.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/policy/NewRootTaskInfo.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/policy/PrivateProfilePolicyTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/policy/PrivateProfilePolicyTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/screenshot/policy/PrivateProfilePolicyTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/policy/PrivateProfilePolicyTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/policy/TestUserIds.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/policy/TestUserIds.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/screenshot/policy/TestUserIds.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/policy/TestUserIds.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/policy/WorkProfilePolicyTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/policy/WorkProfilePolicyTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/screenshot/policy/WorkProfilePolicyTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/policy/WorkProfilePolicyTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/scroll/FakeSessionTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/scroll/FakeSessionTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/screenshot/scroll/FakeSessionTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/scroll/FakeSessionTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/scroll/ScrollCaptureControllerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/scroll/ScrollCaptureControllerTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/screenshot/scroll/ScrollCaptureControllerTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/scroll/ScrollCaptureControllerTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/scroll/ScrollCaptureFrameworkSmokeTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/scroll/ScrollCaptureFrameworkSmokeTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/screenshot/scroll/ScrollCaptureFrameworkSmokeTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/scroll/ScrollCaptureFrameworkSmokeTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/scroll/ScrollViewActivity.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/scroll/ScrollViewActivity.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/screenshot/scroll/ScrollViewActivity.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/scroll/ScrollViewActivity.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ui/viewmodel/ScreenshotViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/ui/viewmodel/ScreenshotViewModelTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/screenshot/ui/viewmodel/ScreenshotViewModelTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/ui/viewmodel/ScreenshotViewModelTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/scrim/ScrimViewTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/scrim/ScrimViewTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/scrim/ScrimViewTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/scrim/ScrimViewTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/sensorprivacy/SensorUseStartedActivityTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/sensorprivacy/SensorUseStartedActivityTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/sensorprivacy/SensorUseStartedActivityTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/sensorprivacy/SensorUseStartedActivityTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/settings/brightness/BrightnessControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/settings/brightness/BrightnessControllerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/settings/brightness/BrightnessControllerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/settings/brightness/BrightnessControllerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/settings/brightness/BrightnessDialogTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/settings/brightness/BrightnessDialogTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/settings/brightness/BrightnessDialogTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/settings/brightness/BrightnessDialogTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/settings/brightness/BrightnessSliderControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/settings/brightness/BrightnessSliderControllerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/settings/brightness/BrightnessSliderControllerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/settings/brightness/BrightnessSliderControllerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/CombinedShadeHeaderConstraintsTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/CombinedShadeHeaderConstraintsTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/shade/CombinedShadeHeaderConstraintsTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/shade/CombinedShadeHeaderConstraintsTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/ConstraintChangeTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/ConstraintChangeTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/shade/ConstraintChangeTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/shade/ConstraintChangeTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/ConstraintChangesTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/ConstraintChangesTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/shade/ConstraintChangesTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/shade/ConstraintChangesTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/LockscreenHostedDreamGestureListenerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/LockscreenHostedDreamGestureListenerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/shade/LockscreenHostedDreamGestureListenerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/shade/LockscreenHostedDreamGestureListenerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelUnfoldAnimationControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationPanelUnfoldAnimationControllerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelUnfoldAnimationControllerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationPanelUnfoldAnimationControllerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
similarity index 99%
rename from packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
index 0e9ef06..0454317 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
@@ -22,6 +22,10 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static kotlinx.coroutines.flow.FlowKt.emptyFlow;
+import static kotlinx.coroutines.flow.SharedFlowKt.MutableSharedFlow;
+import static kotlinx.coroutines.flow.StateFlowKt.MutableStateFlow;
+
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyFloat;
@@ -36,10 +40,6 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
-import static kotlinx.coroutines.flow.FlowKt.emptyFlow;
-import static kotlinx.coroutines.flow.SharedFlowKt.MutableSharedFlow;
-import static kotlinx.coroutines.flow.StateFlowKt.MutableStateFlow;
-
 import android.animation.Animator;
 import android.annotation.IdRes;
 import android.content.ContentResolver;
@@ -201,6 +201,12 @@
 import com.android.systemui.util.time.SystemClock;
 import com.android.wm.shell.animation.FlingAnimationUtils;
 
+import dagger.Lazy;
+
+import kotlinx.coroutines.CoroutineDispatcher;
+import kotlinx.coroutines.channels.BufferOverflow;
+import kotlinx.coroutines.test.TestScope;
+
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Rule;
@@ -215,11 +221,6 @@
 import java.util.List;
 import java.util.Optional;
 
-import dagger.Lazy;
-import kotlinx.coroutines.CoroutineDispatcher;
-import kotlinx.coroutines.channels.BufferOverflow;
-import kotlinx.coroutines.test.TestScope;
-
 public class NotificationPanelViewControllerBaseTest extends SysuiTestCase {
 
     protected static final int SPLIT_SHADE_FULL_TRANSITION_DISTANCE = 400;
@@ -461,7 +462,8 @@
                 () -> mKosmos.getSceneInteractor(),
                 () -> mKosmos.getSceneContainerOcclusionInteractor(),
                 () -> mKosmos.getKeyguardClockInteractor(),
-                () -> mKosmos.getSceneBackInteractor());
+                () -> mKosmos.getSceneBackInteractor(),
+                () -> mKosmos.getAlternateBouncerInteractor());
 
         KeyguardStatusView keyguardStatusView = new KeyguardStatusView(mContext);
         keyguardStatusView.setId(R.id.keyguard_status_view);
@@ -622,7 +624,8 @@
                                 () -> mKosmos.getSceneInteractor(),
                                 () -> mKosmos.getSceneContainerOcclusionInteractor(),
                                 () -> mKosmos.getKeyguardClockInteractor(),
-                                () -> mKosmos.getSceneBackInteractor()),
+                                () -> mKosmos.getSceneBackInteractor(),
+                                () -> mKosmos.getAlternateBouncerInteractor()),
                         mKeyguardBypassController,
                         mDozeParameters,
                         mScreenOffAnimationController,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerWithCoroutinesTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationPanelViewControllerWithCoroutinesTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerWithCoroutinesTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationPanelViewControllerWithCoroutinesTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationsQuickSettingsContainerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationsQuickSettingsContainerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/shade/NotificationsQuickSettingsContainerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationsQuickSettingsContainerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/PulsingGestureListenerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/PulsingGestureListenerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/shade/PulsingGestureListenerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/shade/PulsingGestureListenerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/QsBatteryModeControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/QsBatteryModeControllerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/shade/QsBatteryModeControllerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/shade/QsBatteryModeControllerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerImplBaseTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/QuickSettingsControllerImplBaseTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerImplBaseTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/shade/QuickSettingsControllerImplBaseTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerImplTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/QuickSettingsControllerImplTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerImplTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/shade/QuickSettingsControllerImplTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerImplWithCoroutinesTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/QuickSettingsControllerImplWithCoroutinesTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerImplWithCoroutinesTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/shade/QuickSettingsControllerImplWithCoroutinesTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/ShadeControllerImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/ShadeControllerImplTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/shade/ShadeControllerImplTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/shade/ShadeControllerImplTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/carrier/CellSignalStateTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/carrier/CellSignalStateTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/shade/carrier/CellSignalStateTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/shade/carrier/CellSignalStateTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/carrier/ShadeCarrierTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/carrier/ShadeCarrierTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/shade/carrier/ShadeCarrierTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/shade/carrier/ShadeCarrierTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/data/repository/ShadeRepositoryImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/data/repository/ShadeRepositoryImplTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/shade/data/repository/ShadeRepositoryImplTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/shade/data/repository/ShadeRepositoryImplTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/domain/interactor/ShadeInteractorSceneContainerImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeInteractorSceneContainerImplTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/shade/domain/interactor/ShadeInteractorSceneContainerImplTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeInteractorSceneContainerImplTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/transition/ScrimShadeTransitionControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/transition/ScrimShadeTransitionControllerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/shade/transition/ScrimShadeTransitionControllerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/shade/transition/ScrimShadeTransitionControllerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shadow/DoubleShadowTextClockTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shadow/DoubleShadowTextClockTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/shadow/DoubleShadowTextClockTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/shadow/DoubleShadowTextClockTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/animation/DisableSubpixelTextTransitionListenerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shared/animation/DisableSubpixelTextTransitionListenerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/shared/animation/DisableSubpixelTextTransitionListenerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/shared/animation/DisableSubpixelTextTransitionListenerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/animation/UnfoldConstantTranslateAnimatorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shared/animation/UnfoldConstantTranslateAnimatorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/shared/animation/UnfoldConstantTranslateAnimatorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/shared/animation/UnfoldConstantTranslateAnimatorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/animation/UnfoldMoveFromCenterAnimatorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shared/animation/UnfoldMoveFromCenterAnimatorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/shared/animation/UnfoldMoveFromCenterAnimatorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/shared/animation/UnfoldMoveFromCenterAnimatorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/AnimatableClockViewTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shared/clocks/AnimatableClockViewTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/shared/clocks/AnimatableClockViewTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/shared/clocks/AnimatableClockViewTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/DefaultClockProviderTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shared/clocks/DefaultClockProviderTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/shared/clocks/DefaultClockProviderTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/shared/clocks/DefaultClockProviderTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/condition/CombinedConditionTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shared/condition/CombinedConditionTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/shared/condition/CombinedConditionTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/shared/condition/CombinedConditionTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/condition/ConditionExtensionsTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shared/condition/ConditionExtensionsTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/shared/condition/ConditionExtensionsTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/shared/condition/ConditionExtensionsTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/condition/ConditionMonitorTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/shared/condition/ConditionMonitorTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/shared/condition/ConditionMonitorTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/shared/condition/ConditionMonitorTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/condition/ConditionTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/shared/condition/ConditionTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/shared/condition/ConditionTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/shared/condition/ConditionTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/condition/FakeCondition.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/shared/condition/FakeCondition.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/shared/condition/FakeCondition.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/shared/condition/FakeCondition.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/notifications/data/repository/NotificationSettingsRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shared/notifications/data/repository/NotificationSettingsRepositoryTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/shared/notifications/data/repository/NotificationSettingsRepositoryTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/shared/notifications/data/repository/NotificationSettingsRepositoryTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/plugins/PluginInstanceTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/shared/plugins/PluginInstanceTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/shared/plugins/PluginInstanceTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/shared/plugins/PluginInstanceTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/plugins/PluginManagerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/shared/plugins/PluginManagerTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/shared/plugins/PluginManagerTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/shared/plugins/PluginManagerTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/plugins/VersionInfoTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/shared/plugins/VersionInfoTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/shared/plugins/VersionInfoTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/shared/plugins/VersionInfoTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/regionsampling/RegionSamplerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shared/regionsampling/RegionSamplerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/shared/regionsampling/RegionSamplerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/shared/regionsampling/RegionSamplerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/rotation/RotationButtonControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shared/rotation/RotationButtonControllerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/shared/rotation/RotationButtonControllerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/shared/rotation/RotationButtonControllerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/system/QuickStepContractTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shared/system/QuickStepContractTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/shared/system/QuickStepContractTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/shared/system/QuickStepContractTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/system/UncaughtExceptionPreHandlerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shared/system/UncaughtExceptionPreHandlerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/shared/system/UncaughtExceptionPreHandlerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/shared/system/UncaughtExceptionPreHandlerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/BlurUtilsTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/BlurUtilsTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/BlurUtilsTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/BlurUtilsTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/DragDownHelperTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/DragDownHelperTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/DragDownHelperTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/DragDownHelperTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerBaseTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/KeyguardIndicationControllerBaseTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerBaseTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/KeyguardIndicationControllerBaseTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/LSShadeTransitionLoggerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/LSShadeTransitionLoggerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/LSShadeTransitionLoggerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/LSShadeTransitionLoggerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeQsTransitionControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/LockscreenShadeQsTransitionControllerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeQsTransitionControllerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/LockscreenShadeQsTransitionControllerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationListenerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/NotificationListenerTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationListenerTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/NotificationListenerTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationUiAdjustmentTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/NotificationUiAdjustmentTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationUiAdjustmentTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/NotificationUiAdjustmentTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/OperatorNameViewControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/OperatorNameViewControllerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/OperatorNameViewControllerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/OperatorNameViewControllerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/PulseExpansionHandlerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/PulseExpansionHandlerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/PulseExpansionHandlerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/PulseExpansionHandlerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/RemoteInputNotificationRebuilderTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/RemoteInputNotificationRebuilderTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/RemoteInputNotificationRebuilderTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/RemoteInputNotificationRebuilderTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/SingleShadeLockScreenOverScrollerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/SingleShadeLockScreenOverScrollerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/SingleShadeLockScreenOverScrollerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/SingleShadeLockScreenOverScrollerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/SmartReplyControllerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/SmartReplyControllerTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/SmartReplyControllerTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/SmartReplyControllerTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarIconViewTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/StatusBarIconViewTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarIconViewTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/StatusBarIconViewTest.java
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt
index db274cc..f8720b4 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt
@@ -28,6 +28,8 @@
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.authentication.data.repository.fakeAuthenticationRepository
 import com.android.systemui.authentication.shared.model.AuthenticationMethodModel
+import com.android.systemui.bouncer.domain.interactor.alternateBouncerInteractor
+import com.android.systemui.bouncer.domain.interactor.givenCanShowAlternateBouncer
 import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.deviceentry.domain.interactor.deviceUnlockedInteractor
 import com.android.systemui.flags.DisableSceneContainer
@@ -83,8 +85,9 @@
 
     private val kosmos = testKosmos()
     private val testScope = kosmos.testScope
-    private val sceneInteractor = kosmos.sceneInteractor
-    private val keyguardTransitionRepository = kosmos.fakeKeyguardTransitionRepository
+    private val sceneInteractor by lazy { kosmos.sceneInteractor }
+    private val keyguardTransitionRepository by lazy { kosmos.fakeKeyguardTransitionRepository }
+    private val alternateBouncerInteractor by lazy { kosmos.alternateBouncerInteractor }
     private val mockDarkAnimator = mock<ObjectAnimator>()
 
     private lateinit var underTest: StatusBarStateControllerImpl
@@ -121,6 +124,7 @@
                     { kosmos.sceneContainerOcclusionInteractor },
                     { kosmos.keyguardClockInteractor },
                     { kosmos.sceneBackInteractor },
+                    { kosmos.alternateBouncerInteractor },
                 ) {
                 override fun createDarkAnimator(): ObjectAnimator {
                     return mockDarkAnimator
@@ -299,6 +303,52 @@
 
     @Test
     @EnableSceneContainer
+    @DisableFlags(DualShade.FLAG_NAME)
+    fun start_hydratesStatusBarState_withAlternateBouncer() =
+        testScope.runTest {
+            var statusBarState = underTest.state
+            val listener =
+                object : StatusBarStateController.StateListener {
+                    override fun onStateChanged(newState: Int) {
+                        statusBarState = newState
+                    }
+                }
+            underTest.addCallback(listener)
+
+            val currentScene by collectLastValue(sceneInteractor.currentScene)
+            val deviceUnlockStatus by
+                collectLastValue(kosmos.deviceUnlockedInteractor.deviceUnlockStatus)
+            val alternateBouncerIsVisible by collectLastValue(alternateBouncerInteractor.isVisible)
+
+            kosmos.fakeAuthenticationRepository.setAuthenticationMethod(
+                AuthenticationMethodModel.Password
+            )
+            kosmos.fakeDeviceEntryFingerprintAuthRepository.setAuthenticationStatus(
+                SuccessFingerprintAuthenticationStatus(0, true)
+            )
+            runCurrent()
+            assertThat(deviceUnlockStatus!!.isUnlocked).isTrue()
+
+            sceneInteractor.changeScene(toScene = Scenes.Lockscreen, loggingReason = "reason")
+            runCurrent()
+            assertThat(currentScene).isEqualTo(Scenes.Lockscreen)
+
+            kosmos.givenCanShowAlternateBouncer()
+            alternateBouncerInteractor.forceShow()
+            runCurrent()
+            assertThat(alternateBouncerIsVisible).isTrue()
+
+            // Call start to begin hydrating based on the scene framework:
+            underTest.start()
+
+            sceneInteractor.changeScene(toScene = Scenes.Gone, loggingReason = "reason")
+            runCurrent()
+            assertThat(currentScene).isEqualTo(Scenes.Gone)
+            assertThat(statusBarState).isEqualTo(StatusBarState.KEYGUARD)
+        }
+
+    @Test
+    @EnableSceneContainer
     @EnableFlags(DualShade.FLAG_NAME)
     fun start_hydratesStatusBarState_dualShade_whileLocked() =
         testScope.runTest {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateEventTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/StatusBarStateEventTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateEventTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/StatusBarStateEventTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/VibratorHelperTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/VibratorHelperTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/VibratorHelperTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/VibratorHelperTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/call/domain/interactor/CallChipInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/call/domain/interactor/CallChipInteractorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/call/domain/interactor/CallChipInteractorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/call/domain/interactor/CallChipInteractorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/call/ui/viewmodel/CallChipViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/call/ui/viewmodel/CallChipViewModelTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/call/ui/viewmodel/CallChipViewModelTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/call/ui/viewmodel/CallChipViewModelTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/casttootherdevice/domian/interactor/MediaRouterChipInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/casttootherdevice/domian/interactor/MediaRouterChipInteractorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/casttootherdevice/domian/interactor/MediaRouterChipInteractorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/casttootherdevice/domian/interactor/MediaRouterChipInteractorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/casttootherdevice/ui/view/EndCastScreenToOtherDeviceDialogDelegateTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/casttootherdevice/ui/view/EndCastScreenToOtherDeviceDialogDelegateTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/casttootherdevice/ui/view/EndCastScreenToOtherDeviceDialogDelegateTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/casttootherdevice/ui/view/EndCastScreenToOtherDeviceDialogDelegateTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/casttootherdevice/ui/view/EndGenericCastToOtherDeviceDialogDelegateTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/casttootherdevice/ui/view/EndGenericCastToOtherDeviceDialogDelegateTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/casttootherdevice/ui/view/EndGenericCastToOtherDeviceDialogDelegateTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/casttootherdevice/ui/view/EndGenericCastToOtherDeviceDialogDelegateTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/casttootherdevice/ui/viewmodel/CastToOtherDeviceChipViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/casttootherdevice/ui/viewmodel/CastToOtherDeviceChipViewModelTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/casttootherdevice/ui/viewmodel/CastToOtherDeviceChipViewModelTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/casttootherdevice/ui/viewmodel/CastToOtherDeviceChipViewModelTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/mediaprojection/domain/interactor/MediaProjectionChipInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/mediaprojection/domain/interactor/MediaProjectionChipInteractorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/mediaprojection/domain/interactor/MediaProjectionChipInteractorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/mediaprojection/domain/interactor/MediaProjectionChipInteractorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/mediaprojection/ui/view/EndMediaProjectionDialogHelperTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/mediaprojection/ui/view/EndMediaProjectionDialogHelperTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/mediaprojection/ui/view/EndMediaProjectionDialogHelperTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/mediaprojection/ui/view/EndMediaProjectionDialogHelperTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/ron/demo/ui/viewmodel/DemoRonChipViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ron/demo/ui/viewmodel/DemoRonChipViewModelTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/ron/demo/ui/viewmodel/DemoRonChipViewModelTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ron/demo/ui/viewmodel/DemoRonChipViewModelTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/screenrecord/domain/interactor/ScreenRecordChipInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/screenrecord/domain/interactor/ScreenRecordChipInteractorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/screenrecord/domain/interactor/ScreenRecordChipInteractorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/screenrecord/domain/interactor/ScreenRecordChipInteractorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/screenrecord/ui/view/EndScreenRecordingDialogDelegateTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/screenrecord/ui/view/EndScreenRecordingDialogDelegateTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/screenrecord/ui/view/EndScreenRecordingDialogDelegateTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/screenrecord/ui/view/EndScreenRecordingDialogDelegateTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/screenrecord/ui/viewmodel/ScreenRecordChipViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/screenrecord/ui/viewmodel/ScreenRecordChipViewModelTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/screenrecord/ui/viewmodel/ScreenRecordChipViewModelTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/screenrecord/ui/viewmodel/ScreenRecordChipViewModelTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/sharetoapp/ui/view/EndShareToAppDialogDelegateTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/sharetoapp/ui/view/EndShareToAppDialogDelegateTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/sharetoapp/ui/view/EndShareToAppDialogDelegateTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/sharetoapp/ui/view/EndShareToAppDialogDelegateTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/sharetoapp/ui/viewmodel/ShareToAppChipViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/sharetoapp/ui/viewmodel/ShareToAppChipViewModelTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/sharetoapp/ui/viewmodel/ShareToAppChipViewModelTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/sharetoapp/ui/viewmodel/ShareToAppChipViewModelTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/ui/view/ChipBackgroundContainerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ui/view/ChipBackgroundContainerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/ui/view/ChipBackgroundContainerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ui/view/ChipBackgroundContainerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/ui/view/ChipChronometerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ui/view/ChipChronometerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/ui/view/ChipChronometerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ui/view/ChipChronometerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/ui/viewmodel/ChipTransitionHelperTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ui/viewmodel/ChipTransitionHelperTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/ui/viewmodel/ChipTransitionHelperTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ui/viewmodel/ChipTransitionHelperTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipViewModelTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipViewModelTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipViewModelTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModelTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModelTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModelTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsWithRonsViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsWithRonsViewModelTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsWithRonsViewModelTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsWithRonsViewModelTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/commandline/ParametersTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/commandline/ParametersTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/commandline/ParametersTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/commandline/ParametersTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/commandline/ParseableCommandTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/commandline/ParseableCommandTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/commandline/ParseableCommandTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/commandline/ParseableCommandTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/commandline/ValueParserTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/commandline/ValueParserTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/commandline/ValueParserTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/commandline/ValueParserTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/AccessPointControllerImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/connectivity/AccessPointControllerImplTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/AccessPointControllerImplTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/connectivity/AccessPointControllerImplTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/MobileIconCarrierIdOverridesFake.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/connectivity/MobileIconCarrierIdOverridesFake.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/MobileIconCarrierIdOverridesFake.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/connectivity/MobileIconCarrierIdOverridesFake.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkTypeResIdCacheTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/connectivity/NetworkTypeResIdCacheTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkTypeResIdCacheTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/connectivity/NetworkTypeResIdCacheTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/ui/MobileContextProviderTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/connectivity/ui/MobileContextProviderTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/ui/MobileContextProviderTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/connectivity/ui/MobileContextProviderTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/core/CommandQueueInitializerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/core/CommandQueueInitializerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/core/CommandQueueInitializerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/core/CommandQueueInitializerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/core/StatusBarInitializerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/core/StatusBarInitializerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/core/StatusBarInitializerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/core/StatusBarInitializerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/core/StatusBarOrchestratorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/core/StatusBarOrchestratorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/core/StatusBarOrchestratorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/core/StatusBarOrchestratorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/data/repository/KeyguardStatusBarRepositoryImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/data/repository/KeyguardStatusBarRepositoryImplTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/data/repository/KeyguardStatusBarRepositoryImplTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/data/repository/KeyguardStatusBarRepositoryImplTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/data/repository/StatusBarModeRepositoryImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/data/repository/StatusBarModeRepositoryImplTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/data/repository/StatusBarModeRepositoryImplTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/data/repository/StatusBarModeRepositoryImplTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/disableflags/DisableFlagsLoggerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/disableflags/DisableFlagsLoggerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/disableflags/DisableFlagsLoggerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/disableflags/DisableFlagsLoggerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/disableflags/DisableStateTrackerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/disableflags/DisableStateTrackerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/disableflags/DisableStateTrackerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/disableflags/DisableStateTrackerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/disableflags/data/repository/DisableFlagsRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/disableflags/data/repository/DisableFlagsRepositoryTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/disableflags/data/repository/DisableFlagsRepositoryTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/disableflags/data/repository/DisableFlagsRepositoryTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/events/FakeStatusEvent.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/events/FakeStatusEvent.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/events/FakeStatusEvent.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/events/FakeStatusEvent.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/events/SystemEventChipAnimationControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/events/SystemEventChipAnimationControllerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/events/SystemEventChipAnimationControllerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/events/SystemEventChipAnimationControllerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/events/SystemEventCoordinatorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/events/SystemEventCoordinatorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/events/SystemEventCoordinatorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/events/SystemEventCoordinatorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceControllerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceControllerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceControllerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/AboveShelfObserverTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/AboveShelfObserverTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/AboveShelfObserverTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/AboveShelfObserverTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/DynamicChildBindControllerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/DynamicChildBindControllerTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/DynamicChildBindControllerTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/DynamicChildBindControllerTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/DynamicPrivacyControllerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/DynamicPrivacyControllerTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/DynamicPrivacyControllerTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/DynamicPrivacyControllerTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationTransitionAnimatorControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/NotificationTransitionAnimatorControllerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationTransitionAnimatorControllerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/NotificationTransitionAnimatorControllerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorLoggerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorLoggerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorLoggerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorLoggerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/HighPriorityProviderTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/HighPriorityProviderTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/HighPriorityProviderTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/HighPriorityProviderTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NoManSimulator.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/NoManSimulator.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NoManSimulator.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/NoManSimulator.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifLiveDataImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/NotifLiveDataImplTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifLiveDataImplTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/NotifLiveDataImplTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifLiveDataStoreImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/NotifLiveDataStoreImplTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifLiveDataStoreImplTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/NotifLiveDataStoreImplTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifLiveDataStoreMocks.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/NotifLiveDataStoreMocks.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifLiveDataStoreMocks.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/NotifLiveDataStoreMocks.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifPipelineChoreographerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/NotifPipelineChoreographerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifPipelineChoreographerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/NotifPipelineChoreographerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/SectionStyleProviderTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/SectionStyleProviderTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/SectionStyleProviderTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/SectionStyleProviderTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coalescer/GroupCoalescerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coalescer/GroupCoalescerTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coalescer/GroupCoalescerTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coalescer/GroupCoalescerTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ColorizedFgsCoordinatorTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/ColorizedFgsCoordinatorTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ColorizedFgsCoordinatorTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/ColorizedFgsCoordinatorTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/DeviceProvisionedCoordinatorTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/DeviceProvisionedCoordinatorTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/DeviceProvisionedCoordinatorTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/DeviceProvisionedCoordinatorTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/DismissibilityCoordinatorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/DismissibilityCoordinatorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/DismissibilityCoordinatorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/DismissibilityCoordinatorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/DreamCoordinatorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/DreamCoordinatorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/DreamCoordinatorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/DreamCoordinatorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/GroupCountCoordinatorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/GroupCountCoordinatorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/GroupCountCoordinatorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/GroupCountCoordinatorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/GroupWhenCoordinatorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/GroupWhenCoordinatorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/GroupWhenCoordinatorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/GroupWhenCoordinatorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/GutsCoordinatorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/GutsCoordinatorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/GutsCoordinatorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/GutsCoordinatorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HideNotifsForOtherUsersCoordinatorTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/HideNotifsForOtherUsersCoordinatorTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HideNotifsForOtherUsersCoordinatorTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/HideNotifsForOtherUsersCoordinatorTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/MediaCoordinatorTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/MediaCoordinatorTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/MediaCoordinatorTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/MediaCoordinatorTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/NotificationStatsLoggerCoordinatorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/NotificationStatsLoggerCoordinatorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/NotificationStatsLoggerCoordinatorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/NotificationStatsLoggerCoordinatorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinatorTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinatorTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinatorTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinatorTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinatorTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinatorTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinatorTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinatorTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RemoteInputCoordinatorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/RemoteInputCoordinatorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RemoteInputCoordinatorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/RemoteInputCoordinatorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RowAlertTimeCoordinatorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/RowAlertTimeCoordinatorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RowAlertTimeCoordinatorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/RowAlertTimeCoordinatorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/SensitiveContentCoordinatorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/SensitiveContentCoordinatorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/SensitiveContentCoordinatorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/SensitiveContentCoordinatorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/SmartspaceDedupingCoordinatorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/SmartspaceDedupingCoordinatorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/SmartspaceDedupingCoordinatorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/SmartspaceDedupingCoordinatorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/inflation/NotifUiAdjustmentProviderTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/inflation/NotifUiAdjustmentProviderTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/inflation/NotifUiAdjustmentProviderTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/inflation/NotifUiAdjustmentProviderTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/listbuilder/SemiStableSortTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/listbuilder/SemiStableSortTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/listbuilder/SemiStableSortTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/listbuilder/SemiStableSortTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/listbuilder/ShadeListBuilderHelperTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/listbuilder/ShadeListBuilderHelperTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/listbuilder/ShadeListBuilderHelperTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/listbuilder/ShadeListBuilderHelperTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionInconsistencyTrackerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionInconsistencyTrackerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionInconsistencyTrackerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionInconsistencyTrackerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/notifcollection/SelfTrackingLifetimeExtenderTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/notifcollection/SelfTrackingLifetimeExtenderTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/notifcollection/SelfTrackingLifetimeExtenderTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/notifcollection/SelfTrackingLifetimeExtenderTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/provider/VisualStabilityProviderTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/provider/VisualStabilityProviderTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/provider/VisualStabilityProviderTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/provider/VisualStabilityProviderTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/render/FakeNodeController.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/render/FakeNodeController.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/render/FakeNodeController.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/render/FakeNodeController.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/render/NodeSpecBuilderTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/render/NodeSpecBuilderTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/render/NodeSpecBuilderTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/render/NodeSpecBuilderTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/render/RenderStageManagerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/render/RenderStageManagerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/render/RenderStageManagerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/render/RenderStageManagerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewDifferTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewDifferTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewDifferTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewDifferTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/domain/interactor/HeadsUpNotificationInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/domain/interactor/HeadsUpNotificationInteractorTest.kt
similarity index 99%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/domain/interactor/HeadsUpNotificationInteractorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/domain/interactor/HeadsUpNotificationInteractorTest.kt
index eb1bcc7..d717fe4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/domain/interactor/HeadsUpNotificationInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/domain/interactor/HeadsUpNotificationInteractorTest.kt
@@ -48,7 +48,7 @@
     private val kosmos =
         testKosmos().apply {
             fakeKeyguardTransitionRepository =
-                FakeKeyguardTransitionRepository(initInLockscreen = false)
+                FakeKeyguardTransitionRepository(initInLockscreen = false, testScope = testScope)
         }
     private val testScope = kosmos.testScope
     private val faceAuthRepository by lazy { kosmos.fakeDeviceEntryFaceAuthRepository }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/domain/interactor/NotificationAlertsInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/domain/interactor/NotificationAlertsInteractorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/domain/interactor/NotificationAlertsInteractorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/domain/interactor/NotificationAlertsInteractorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/domain/interactor/NotificationLaunchAnimationInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/domain/interactor/NotificationLaunchAnimationInteractorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/domain/interactor/NotificationLaunchAnimationInteractorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/domain/interactor/NotificationLaunchAnimationInteractorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/domain/interactor/NotificationsKeyguardInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/domain/interactor/NotificationsKeyguardInteractorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/domain/interactor/NotificationsKeyguardInteractorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/domain/interactor/NotificationsKeyguardInteractorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/domain/interactor/RenderNotificationsListInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/domain/interactor/RenderNotificationsListInteractorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/domain/interactor/RenderNotificationsListInteractorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/domain/interactor/RenderNotificationsListInteractorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/footer/ui/viewmodel/FooterViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/footer/ui/viewmodel/FooterViewModelTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/footer/ui/viewmodel/FooterViewModelTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/footer/ui/viewmodel/FooterViewModelTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/domain/interactor/NotificationIconsInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/icon/domain/interactor/NotificationIconsInteractorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/domain/interactor/NotificationIconsInteractorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/icon/domain/interactor/NotificationIconsInteractorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerAlwaysOnDisplayViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerAlwaysOnDisplayViewModelTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerAlwaysOnDisplayViewModelTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerAlwaysOnDisplayViewModelTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/HeadsUpViewBinderTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/interruption/HeadsUpViewBinderTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/HeadsUpViewBinderTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/interruption/HeadsUpViewBinderTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/KeyguardNotificationVisibilityProviderTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/interruption/KeyguardNotificationVisibilityProviderTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/KeyguardNotificationVisibilityProviderTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/interruption/KeyguardNotificationVisibilityProviderTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderTestBase.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderTestBase.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderTestBase.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderTestBase.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderTestUtil.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderTestUtil.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderTestUtil.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderTestUtil.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/ExpansionStateLoggerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/logging/ExpansionStateLoggerTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/ExpansionStateLoggerTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/logging/ExpansionStateLoggerTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationPanelLoggerFake.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/logging/NotificationPanelLoggerFake.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationPanelLoggerFake.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/logging/NotificationPanelLoggerFake.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationViewTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationViewTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationViewTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationViewTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowControllerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowControllerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowControllerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowDragControllerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowDragControllerTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowDragControllerTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowDragControllerTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/FeedbackInfoTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/FeedbackInfoTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/FeedbackInfoTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/FeedbackInfoTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/HeadsUpStyleProviderImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/HeadsUpStyleProviderImplTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/HeadsUpStyleProviderImplTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/HeadsUpStyleProviderImplTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotifBindPipelineTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotifBindPipelineTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotifBindPipelineTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotifBindPipelineTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotifInflationErrorManagerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotifInflationErrorManagerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotifInflationErrorManagerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotifInflationErrorManagerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotifRemoteViewCacheImplTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotifRemoteViewCacheImplTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotifRemoteViewCacheImplTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotifRemoteViewCacheImplTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationGutsTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationGutsTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageResolverTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageResolverTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageResolverTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageResolverTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationMenuRowTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationMenuRowTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationMenuRowTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationMenuRowTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinderImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinderImplTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinderImplTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinderImplTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationSnoozeTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationSnoozeTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationSnoozeTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationSnoozeTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/PartialConversationInfoTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/PartialConversationInfoTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/PartialConversationInfoTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/PartialConversationInfoTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/RowContentBindStageTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/RowContentBindStageTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/RowContentBindStageTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/RowContentBindStageTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ui/viewmodel/ActivatableNotificationViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/ui/viewmodel/ActivatableNotificationViewModelTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ui/viewmodel/ActivatableNotificationViewModelTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/ui/viewmodel/ActivatableNotificationViewModelTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ui/viewmodel/NotificationViewFlipperViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/ui/viewmodel/NotificationViewFlipperViewModelTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ui/viewmodel/NotificationViewFlipperViewModelTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/ui/viewmodel/NotificationViewFlipperViewModelTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationBigPictureTemplateViewWrapperTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationBigPictureTemplateViewWrapperTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationBigPictureTemplateViewWrapperTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationBigPictureTemplateViewWrapperTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationConversationTemplateViewWrapperTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationConversationTemplateViewWrapperTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationConversationTemplateViewWrapperTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationConversationTemplateViewWrapperTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationCustomViewWrapperTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationCustomViewWrapperTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationCustomViewWrapperTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationCustomViewWrapperTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMessagingTemplateViewWrapperTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMessagingTemplateViewWrapperTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMessagingTemplateViewWrapperTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMessagingTemplateViewWrapperTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapperTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapperTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapperTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapperTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/shared/TestActiveNotificationModel.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/shared/TestActiveNotificationModel.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/shared/TestActiveNotificationModel.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/shared/TestActiveNotificationModel.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/shelf/domain/interactor/NotificationShelfInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/shelf/domain/interactor/NotificationShelfInteractorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/shelf/domain/interactor/NotificationShelfInteractorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/shelf/domain/interactor/NotificationShelfInteractorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/shelf/ui/viewmodel/NotificationShelfViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/shelf/ui/viewmodel/NotificationShelfViewModelTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/shelf/ui/viewmodel/NotificationShelfViewModelTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/shelf/ui/viewmodel/NotificationShelfViewModelTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/AmbientStateTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/AmbientStateTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/AmbientStateTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/AmbientStateTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/DisplaySwitchNotificationsHiderTrackerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/DisplaySwitchNotificationsHiderTrackerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/DisplaySwitchNotificationsHiderTrackerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/DisplaySwitchNotificationsHiderTrackerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/MediaContainerViewTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/MediaContainerViewTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/MediaContainerViewTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/MediaContainerViewTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainerTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainerTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainerTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationShelfTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/NotificationShelfTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationShelfTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/NotificationShelfTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackSizeCalculatorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/NotificationStackSizeCalculatorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackSizeCalculatorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/NotificationStackSizeCalculatorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelperTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelperTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelperTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelperTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationTargetsHelperTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/NotificationTargetsHelperTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationTargetsHelperTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/NotificationTargetsHelperTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/StackStateAnimatorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/StackStateAnimatorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/StackStateAnimatorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/StackStateAnimatorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/ViewStateTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ViewStateTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/ViewStateTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ViewStateTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/domain/interactor/HideNotificationsInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/domain/interactor/HideNotificationsInteractorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/domain/interactor/HideNotificationsInteractorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/domain/interactor/HideNotificationsInteractorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/domain/interactor/NotificationStackInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/domain/interactor/NotificationStackInteractorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/domain/interactor/NotificationStackInteractorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/domain/interactor/NotificationStackInteractorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationLoggerViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationLoggerViewModelTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationLoggerViewModelTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationLoggerViewModelTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacksTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacksTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacksTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacksTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ConfigurationControllerImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ConfigurationControllerImplTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ConfigurationControllerImplTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ConfigurationControllerImplTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeParametersTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/DozeParametersTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeParametersTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/DozeParametersTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeScrimControllerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/DozeScrimControllerTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeScrimControllerTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/DozeScrimControllerTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBypassControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/KeyguardBypassControllerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBypassControllerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/KeyguardBypassControllerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardDismissUtilTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/KeyguardDismissUtilTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardDismissUtilTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/KeyguardDismissUtilTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardIndicationTextViewTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/KeyguardIndicationTextViewTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardIndicationTextViewTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/KeyguardIndicationTextViewTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LegacyLightsOutNotifControllerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/LegacyLightsOutNotifControllerTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LegacyLightsOutNotifControllerTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/LegacyLightsOutNotifControllerTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LetterboxAppearanceCalculatorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/LetterboxAppearanceCalculatorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LetterboxAppearanceCalculatorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/LetterboxAppearanceCalculatorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LetterboxBackgroundProviderTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/LetterboxBackgroundProviderTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LetterboxBackgroundProviderTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/LetterboxBackgroundProviderTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LightBarControllerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/LightBarControllerTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LightBarControllerTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/LightBarControllerTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LightBarTransitionsControllerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/LightBarTransitionsControllerTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LightBarTransitionsControllerTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/LightBarTransitionsControllerTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ManagedProfileControllerImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ManagedProfileControllerImplTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ManagedProfileControllerImplTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ManagedProfileControllerImplTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupTestHelper.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/NotificationGroupTestHelper.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupTestHelper.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/NotificationGroupTestHelper.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationIconContainerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/NotificationIconContainerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationIconContainerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/NotificationIconContainerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationTapHelperTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/NotificationTapHelperTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationTapHelperTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/NotificationTapHelperTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicyTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicyTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicyTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicyTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallbackTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallbackTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallbackTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallbackTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTouchableRegionManagerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/StatusBarTouchableRegionManagerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTouchableRegionManagerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/StatusBarTouchableRegionManagerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusOverlayHoverListenerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/StatusOverlayHoverListenerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusOverlayHoverListenerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/StatusOverlayHoverListenerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/SystemUIBottomSheetDialogTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/SystemUIBottomSheetDialogTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/SystemUIBottomSheetDialogTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/SystemUIBottomSheetDialogTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationControllerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationControllerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationControllerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/domain/interactor/LightsOutInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/domain/interactor/LightsOutInteractorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/domain/interactor/LightsOutInteractorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/domain/interactor/LightsOutInteractorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentLoggerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentLoggerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentLoggerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentLoggerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/StatusBarVisibilityModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/fragment/StatusBarVisibilityModelTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/StatusBarVisibilityModelTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/fragment/StatusBarVisibilityModelTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerViaListenerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerViaListenerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerViaListenerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerViaListenerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerViaRepoTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerViaRepoTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerViaRepoTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerViaRepoTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/data/repository/OngoingCallRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ongoingcall/data/repository/OngoingCallRepositoryTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/data/repository/OngoingCallRepositoryTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ongoingcall/data/repository/OngoingCallRepositoryTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ui/IconManagerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ui/IconManagerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ui/IconManagerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ui/IconManagerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ui/StatusBarIconControllerImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ui/StatusBarIconControllerImplTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ui/StatusBarIconControllerImplTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ui/StatusBarIconControllerImplTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ui/StatusBarIconControllerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ui/StatusBarIconControllerTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ui/StatusBarIconControllerTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ui/StatusBarIconControllerTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ui/StatusBarIconListTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ui/StatusBarIconListTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ui/StatusBarIconListTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ui/StatusBarIconListTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/airplane/data/repository/AirplaneModeRepositoryImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/airplane/data/repository/AirplaneModeRepositoryImplTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/airplane/data/repository/AirplaneModeRepositoryImplTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/airplane/data/repository/AirplaneModeRepositoryImplTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/airplane/domain/interactor/AirplaneModeInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/airplane/domain/interactor/AirplaneModeInteractorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/airplane/domain/interactor/AirplaneModeInteractorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/airplane/domain/interactor/AirplaneModeInteractorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/ethernet/domain/EthernetInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/ethernet/domain/EthernetInteractorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/ethernet/domain/EthernetInteractorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/ethernet/domain/EthernetInteractorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionParameterizedTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionParameterizedTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionParameterizedTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionParameterizedTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepositoryTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepositoryTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepositoryTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/CarrierMergedConnectionRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/CarrierMergedConnectionRepositoryTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/CarrierMergedConnectionRepositoryTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/CarrierMergedConnectionRepositoryTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/MobileViewLoggerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/ui/MobileViewLoggerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/MobileViewLoggerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/ui/MobileViewLoggerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/model/SignalIconModelParameterizedTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/ui/model/SignalIconModelParameterizedTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/model/SignalIconModelParameterizedTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/ui/model/SignalIconModelParameterizedTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/LocationBasedMobileIconViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/LocationBasedMobileIconViewModelTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/LocationBasedMobileIconViewModelTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/LocationBasedMobileIconViewModelTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModelTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModelTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModelTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModelTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModelTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModelTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/data/DeviceBasedSatelliteRepositorySwitcherTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/satellite/data/DeviceBasedSatelliteRepositorySwitcherTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/data/DeviceBasedSatelliteRepositorySwitcherTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/satellite/data/DeviceBasedSatelliteRepositorySwitcherTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/data/demo/DemoDeviceBasedSatelliteRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/satellite/data/demo/DemoDeviceBasedSatelliteRepositoryTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/data/demo/DemoDeviceBasedSatelliteRepositoryTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/satellite/data/demo/DemoDeviceBasedSatelliteRepositoryTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/data/prod/FakeDeviceBasedSatelliteRepository.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/satellite/data/prod/FakeDeviceBasedSatelliteRepository.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/data/prod/FakeDeviceBasedSatelliteRepository.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/satellite/data/prod/FakeDeviceBasedSatelliteRepository.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/domain/interactor/DeviceBasedSatelliteInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/satellite/domain/interactor/DeviceBasedSatelliteInteractorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/domain/interactor/DeviceBasedSatelliteInteractorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/satellite/domain/interactor/DeviceBasedSatelliteInteractorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/ui/viewmodel/DeviceBasedSatelliteViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/satellite/ui/viewmodel/DeviceBasedSatelliteViewModelTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/ui/viewmodel/DeviceBasedSatelliteViewModelTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/satellite/ui/viewmodel/DeviceBasedSatelliteViewModelTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/ui/viewmodel/FakeDeviceBasedSatelliteViewModel.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/satellite/ui/viewmodel/FakeDeviceBasedSatelliteViewModel.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/ui/viewmodel/FakeDeviceBasedSatelliteViewModel.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/satellite/ui/viewmodel/FakeDeviceBasedSatelliteViewModel.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/data/model/DefaultConnectionModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/data/model/DefaultConnectionModelTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/data/model/DefaultConnectionModelTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/data/model/DefaultConnectionModelTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/domain/interactor/CollapsedStatusBarInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/domain/interactor/CollapsedStatusBarInteractorTest.kt
similarity index 96%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/domain/interactor/CollapsedStatusBarInteractorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/domain/interactor/CollapsedStatusBarInteractorTest.kt
index 5036e77..46f822a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/domain/interactor/CollapsedStatusBarInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/domain/interactor/CollapsedStatusBarInteractorTest.kt
@@ -21,6 +21,7 @@
 import android.app.StatusBarManager.DISABLE_NONE
 import android.app.StatusBarManager.DISABLE_NOTIFICATION_ICONS
 import android.app.StatusBarManager.DISABLE_SYSTEM_INFO
+import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.coroutines.collectLastValue
@@ -31,8 +32,10 @@
 import com.google.common.truth.Truth.assertThat
 import kotlin.test.Test
 import kotlinx.coroutines.test.runTest
+import org.junit.runner.RunWith;
 
 @SmallTest
+@RunWith(AndroidJUnit4::class)
 class CollapsedStatusBarInteractorTest : SysuiTestCase() {
     val kosmos = testKosmos()
     val testScope = kosmos.testScope
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/view/ModernStatusBarViewTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/ui/view/ModernStatusBarViewTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/view/ModernStatusBarViewTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/ui/view/ModernStatusBarViewTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/view/SingleBindableStatusBarIconViewTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/ui/view/SingleBindableStatusBarIconViewTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/view/SingleBindableStatusBarIconViewTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/ui/view/SingleBindableStatusBarIconViewTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/CollapsedStatusBarViewModelImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/CollapsedStatusBarViewModelImplTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/CollapsedStatusBarViewModelImplTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/CollapsedStatusBarViewModelImplTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/FakeCollapsedStatusBarViewBinder.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/FakeCollapsedStatusBarViewBinder.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/FakeCollapsedStatusBarViewBinder.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/FakeCollapsedStatusBarViewBinder.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/FakeCollapsedStatusBarViewModel.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/FakeCollapsedStatusBarViewModel.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/FakeCollapsedStatusBarViewModel.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/FakeCollapsedStatusBarViewModel.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/InternetTileViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/InternetTileViewModelTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/InternetTileViewModelTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/InternetTileViewModelTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BaseUserSwitcherAdapterTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/BaseUserSwitcherAdapterTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BaseUserSwitcherAdapterTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/BaseUserSwitcherAdapterTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BlockingQueueIntentReceiver.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/BlockingQueueIntentReceiver.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BlockingQueueIntentReceiver.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/BlockingQueueIntentReceiver.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BluetoothControllerImplTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/BluetoothControllerImplTest.java
similarity index 99%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BluetoothControllerImplTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/BluetoothControllerImplTest.java
index 2588f1f..e3bd885 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BluetoothControllerImplTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/BluetoothControllerImplTest.java
@@ -61,7 +61,7 @@
 import java.util.List;
 import java.util.concurrent.Executor;
 
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
 @RunWithLooper
 @SmallTest
 public class BluetoothControllerImplTest extends SysuiTestCase {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/CastControllerImplTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/CastControllerImplTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/CastControllerImplTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/CastControllerImplTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/CastDeviceTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/CastDeviceTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/CastDeviceTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/CastDeviceTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/ClockTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/ClockTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/ClockTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/ClockTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/DevicePostureControllerImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/DevicePostureControllerImplTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/DevicePostureControllerImplTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/DevicePostureControllerImplTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/DeviceProvisionedControllerImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/DeviceProvisionedControllerImplTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/DeviceProvisionedControllerImplTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/DeviceProvisionedControllerImplTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/ExtensionControllerImplTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/ExtensionControllerImplTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/ExtensionControllerImplTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/ExtensionControllerImplTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HotspotControllerImplTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/HotspotControllerImplTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HotspotControllerImplTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/HotspotControllerImplTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyguardQsUserSwitchControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/KeyguardQsUserSwitchControllerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyguardQsUserSwitchControllerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/KeyguardQsUserSwitchControllerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyguardStateControllerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/KeyguardStateControllerTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyguardStateControllerTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/KeyguardStateControllerTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherAdapterTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherAdapterTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherAdapterTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherAdapterTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputQuickSettingsDisablerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/RemoteInputQuickSettingsDisablerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputQuickSettingsDisablerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/RemoteInputQuickSettingsDisablerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SafetyControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/SafetyControllerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SafetyControllerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/SafetyControllerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyConstantsTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/SmartReplyConstantsTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyConstantsTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/SmartReplyConstantsTest.java
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/ZenModeControllerImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/ZenModeControllerImplTest.kt
new file mode 100644
index 0000000..9abdf42
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/ZenModeControllerImplTest.kt
@@ -0,0 +1,207 @@
+/*
+ * 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.systemui.statusbar.policy
+
+import android.app.NotificationManager
+import android.os.Handler
+import android.provider.Settings
+import android.service.notification.ZenModeConfig
+import android.testing.TestableLooper
+import android.testing.TestableLooper.RunWithLooper
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.broadcast.broadcastDispatcher
+import com.android.systemui.dump.dumpManager
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.settings.userTracker
+import com.android.systemui.testKosmos
+import com.android.systemui.util.settings.fakeGlobalSettings
+import com.google.common.truth.Truth.assertThat
+import java.util.concurrent.atomic.AtomicBoolean
+import java.util.concurrent.atomic.AtomicInteger
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers
+import org.mockito.Mockito
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.whenever
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+@RunWithLooper
+class ZenModeControllerImplTest : SysuiTestCase() {
+
+    private val kosmos = testKosmos()
+    private val testScope = kosmos.testScope
+    private lateinit var testableLooper: TestableLooper
+    private lateinit var controller: ZenModeControllerImpl
+
+    private val globalSettings = kosmos.fakeGlobalSettings
+    private val config: ZenModeConfig = mock<ZenModeConfig>()
+    private val mNm: NotificationManager = mock<NotificationManager>()
+
+    @Before
+    fun setUp() {
+        testableLooper = TestableLooper.get(this)
+        mContext.addMockSystemService(NotificationManager::class.java, mNm)
+        whenever(mNm.zenModeConfig).thenReturn(config)
+
+        controller =
+            ZenModeControllerImpl(
+                mContext,
+                Handler.createAsync(testableLooper.looper),
+                kosmos.broadcastDispatcher,
+                kosmos.dumpManager,
+                globalSettings,
+                kosmos.userTracker,
+            )
+    }
+
+    @Test
+    fun testRemoveDuringCallback() {
+        val callback =
+            object : ZenModeController.Callback {
+                override fun onConfigChanged(config: ZenModeConfig) {
+                    controller.removeCallback(this)
+                }
+            }
+
+        controller.addCallback(callback)
+        val mockCallback = Mockito.mock(ZenModeController.Callback::class.java)
+        controller.addCallback(mockCallback)
+        controller.fireConfigChanged(config)
+        Mockito.verify(mockCallback).onConfigChanged(ArgumentMatchers.eq(config))
+    }
+
+    @Test
+    fun testAreNotificationsHiddenInShade_zenOffShadeSuppressed() {
+        config.suppressedVisualEffects =
+            NotificationManager.Policy.SUPPRESSED_EFFECT_NOTIFICATION_LIST
+        controller.updateZenMode(Settings.Global.ZEN_MODE_OFF)
+        controller.updateZenModeConfig()
+        assertThat(controller.areNotificationsHiddenInShade()).isFalse()
+    }
+
+    @Test
+    fun testAreNotificationsHiddenInShade_zenOnShadeNotSuppressed() {
+        val policy =
+            NotificationManager.Policy(
+                0,
+                0,
+                0,
+                NotificationManager.Policy.SUPPRESSED_EFFECT_STATUS_BAR,
+            )
+        whenever(mNm.consolidatedNotificationPolicy).thenReturn(policy)
+        controller.updateConsolidatedNotificationPolicy()
+        controller.updateZenMode(Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS)
+        assertThat(controller.areNotificationsHiddenInShade()).isFalse()
+    }
+
+    @Test
+    fun testAreNotificationsHiddenInShade_zenOnShadeSuppressed() {
+        val policy =
+            NotificationManager.Policy(
+                0,
+                0,
+                0,
+                NotificationManager.Policy.SUPPRESSED_EFFECT_NOTIFICATION_LIST,
+            )
+        whenever(mNm.consolidatedNotificationPolicy).thenReturn(policy)
+        controller.updateConsolidatedNotificationPolicy()
+        controller.updateZenMode(Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS)
+        assertThat(controller.areNotificationsHiddenInShade()).isTrue()
+    }
+
+    @Test
+    fun testModeChange() =
+        testScope.runTest {
+            val states =
+                listOf(
+                    Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS,
+                    Settings.Global.ZEN_MODE_NO_INTERRUPTIONS,
+                    Settings.Global.ZEN_MODE_ALARMS,
+                    Settings.Global.ZEN_MODE_ALARMS,
+                )
+
+            for (state in states) {
+                globalSettings.putInt(Settings.Global.ZEN_MODE, state)
+                testScope.runCurrent()
+                testableLooper.processAllMessages()
+                assertThat(controller.zen).isEqualTo(state)
+            }
+        }
+
+    @Test
+    fun testModeChange_callbackNotified() =
+        testScope.runTest {
+            val currentState = AtomicInteger(-1)
+
+            val callback: ZenModeController.Callback =
+                object : ZenModeController.Callback {
+                    override fun onZenChanged(zen: Int) {
+                        currentState.set(zen)
+                    }
+                }
+
+            controller.addCallback(callback)
+
+            val states =
+                listOf(
+                    Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS,
+                    Settings.Global.ZEN_MODE_NO_INTERRUPTIONS,
+                    Settings.Global.ZEN_MODE_ALARMS,
+                    Settings.Global.ZEN_MODE_ALARMS,
+                )
+
+            for (state in states) {
+                globalSettings.putInt(Settings.Global.ZEN_MODE, state)
+                testScope.runCurrent()
+                testableLooper.processAllMessages()
+                assertThat(currentState.get()).isEqualTo(state)
+            }
+        }
+
+    @Test
+    fun testCallbackRemovedWhileDispatching_doesntCrash() =
+        testScope.runTest {
+            val remove = AtomicBoolean(false)
+            globalSettings.putInt(Settings.Global.ZEN_MODE, Settings.Global.ZEN_MODE_OFF)
+            testableLooper.processAllMessages()
+            val callback: ZenModeController.Callback =
+                object : ZenModeController.Callback {
+                    override fun onZenChanged(zen: Int) {
+                        if (remove.get()) {
+                            controller.removeCallback(this)
+                        }
+                    }
+                }
+            controller.addCallback(callback)
+            controller.addCallback(object : ZenModeController.Callback {})
+
+            remove.set(true)
+
+            globalSettings.putInt(
+                Settings.Global.ZEN_MODE,
+                Settings.Global.ZEN_MODE_NO_INTERRUPTIONS,
+            )
+            testScope.runCurrent()
+            testableLooper.processAllMessages()
+        }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/ZenModesCleanupStartableTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/ZenModesCleanupStartableTest.kt
new file mode 100644
index 0000000..4a53a7a
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/ZenModesCleanupStartableTest.kt
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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 android.app.AutomaticZenRule
+import android.app.NotificationManager
+import android.net.Uri
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.kosmos.backgroundCoroutineContext
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.testKosmos
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.MockitoAnnotations
+import org.mockito.kotlin.any
+import org.mockito.kotlin.eq
+import org.mockito.kotlin.never
+import org.mockito.kotlin.verify
+import org.mockito.kotlin.whenever
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@RunWith(AndroidJUnit4::class)
+@SmallTest
+class ZenModesCleanupStartableTest : SysuiTestCase() {
+
+    private val kosmos = testKosmos()
+    private val testScope = kosmos.testScope
+
+    @Mock private lateinit var notificationManager: NotificationManager
+
+    private lateinit var underTest: ZenModesCleanupStartable
+
+    @Before
+    fun setUp() {
+        MockitoAnnotations.initMocks(this)
+        underTest =
+            ZenModesCleanupStartable(
+                testScope.backgroundScope,
+                kosmos.backgroundCoroutineContext,
+                notificationManager,
+            )
+    }
+
+    @Test
+    fun start_withGamingModeZenRule_deletesIt() =
+        testScope.runTest {
+            whenever(notificationManager.automaticZenRules)
+                .thenReturn(
+                    mutableMapOf(
+                        Pair(
+                            "gaming",
+                            AutomaticZenRule.Builder(
+                                    "Gaming Mode",
+                                    Uri.parse(
+                                        "android-app://com.android.systemui/game-mode-dnd-controller"
+                                    ),
+                                )
+                                .setPackage("com.android.systemui")
+                                .build(),
+                        ),
+                        Pair(
+                            "other",
+                            AutomaticZenRule.Builder("Other Mode", Uri.parse("something-else"))
+                                .setPackage("com.other.package")
+                                .build(),
+                        ),
+                    )
+                )
+
+            underTest.start()
+            runCurrent()
+
+            verify(notificationManager).removeAutomaticZenRule(eq("gaming"))
+        }
+
+    @Test
+    fun start_withoutGamingModeZenRule_doesNothing() =
+        testScope.runTest {
+            whenever(notificationManager.automaticZenRules)
+                .thenReturn(
+                    mutableMapOf(
+                        Pair(
+                            "other",
+                            AutomaticZenRule.Builder("Other Mode", Uri.parse("something-else"))
+                                .setPackage("com.android.systemui")
+                                .build(),
+                        )
+                    )
+                )
+
+            underTest.start()
+            runCurrent()
+
+            verify(notificationManager, never()).removeAutomaticZenRule(any())
+        }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/bluetooth/BluetoothRepositoryImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/bluetooth/BluetoothRepositoryImplTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/bluetooth/BluetoothRepositoryImplTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/bluetooth/BluetoothRepositoryImplTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/bluetooth/FakeBluetoothRepository.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/bluetooth/FakeBluetoothRepository.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/bluetooth/FakeBluetoothRepository.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/bluetooth/FakeBluetoothRepository.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/data/repository/DeviceProvisioningRepositoryImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/data/repository/DeviceProvisioningRepositoryImplTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/data/repository/DeviceProvisioningRepositoryImplTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/data/repository/DeviceProvisioningRepositoryImplTest.kt
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/domain/interactor/ZenModeInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/domain/interactor/ZenModeInteractorTest.kt
index c5ccf9e..74d4178 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/domain/interactor/ZenModeInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/domain/interactor/ZenModeInteractorTest.kt
@@ -18,6 +18,8 @@
 
 import android.app.AutomaticZenRule
 import android.app.Flags
+import android.app.NotificationManager.INTERRUPTION_FILTER_NONE
+import android.app.NotificationManager.INTERRUPTION_FILTER_PRIORITY
 import android.app.NotificationManager.Policy
 import android.platform.test.annotations.EnableFlags
 import android.provider.Settings
@@ -25,6 +27,7 @@
 import android.provider.Settings.Secure.ZEN_DURATION_FOREVER
 import android.provider.Settings.Secure.ZEN_DURATION_PROMPT
 import android.service.notification.SystemZenRules
+import android.service.notification.ZenPolicy
 import android.service.notification.ZenPolicy.VISUAL_EFFECT_NOTIFICATION_LIST
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
@@ -383,6 +386,120 @@
         }
 
     @Test
+    @EnableFlags(Flags.FLAG_MODES_UI)
+    fun activeModesBlockingEverything_hasModesWithFilterNone() =
+        testScope.runTest {
+            val blockingEverything by collectLastValue(underTest.activeModesBlockingEverything)
+
+            zenModeRepository.addModes(
+                listOf(
+                    TestModeBuilder()
+                        .setName("Filter=None, Not active")
+                        .setInterruptionFilter(INTERRUPTION_FILTER_NONE)
+                        .setActive(false)
+                        .build(),
+                    TestModeBuilder()
+                        .setName("Filter=Priority, Active")
+                        .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY)
+                        .setActive(true)
+                        .build(),
+                    TestModeBuilder()
+                        .setName("Filter=None, Active")
+                        .setInterruptionFilter(INTERRUPTION_FILTER_NONE)
+                        .setActive(true)
+                        .build(),
+                    TestModeBuilder()
+                        .setName("Filter=None, Active Too")
+                        .setInterruptionFilter(INTERRUPTION_FILTER_NONE)
+                        .setActive(true)
+                        .build(),
+                )
+            )
+            runCurrent()
+
+            assertThat(blockingEverything!!.mainMode!!.name).isEqualTo("Filter=None, Active")
+            assertThat(blockingEverything!!.modeNames)
+                .containsExactly("Filter=None, Active", "Filter=None, Active Too")
+                .inOrder()
+        }
+
+    @Test
+    @EnableFlags(Flags.FLAG_MODES_UI)
+    fun activeModesBlockingMedia_hasModesWithPolicyBlockingMedia() =
+        testScope.runTest {
+            val blockingMedia by collectLastValue(underTest.activeModesBlockingMedia)
+
+            zenModeRepository.addModes(
+                listOf(
+                    TestModeBuilder()
+                        .setName("Blocks media, Not active")
+                        .setZenPolicy(ZenPolicy.Builder().allowMedia(false).build())
+                        .setActive(false)
+                        .build(),
+                    TestModeBuilder()
+                        .setName("Allows media, Active")
+                        .setZenPolicy(ZenPolicy.Builder().allowMedia(true).build())
+                        .setActive(true)
+                        .build(),
+                    TestModeBuilder()
+                        .setName("Blocks media, Active")
+                        .setZenPolicy(ZenPolicy.Builder().allowMedia(false).build())
+                        .setActive(true)
+                        .build(),
+                    TestModeBuilder()
+                        .setName("Blocks media, Active Too")
+                        .setZenPolicy(ZenPolicy.Builder().allowMedia(false).build())
+                        .setActive(true)
+                        .build(),
+                )
+            )
+            runCurrent()
+
+            assertThat(blockingMedia!!.mainMode!!.name).isEqualTo("Blocks media, Active")
+            assertThat(blockingMedia!!.modeNames)
+                .containsExactly("Blocks media, Active", "Blocks media, Active Too")
+                .inOrder()
+        }
+
+    @Test
+    @EnableFlags(Flags.FLAG_MODES_UI)
+    fun activeModesBlockingAlarms_hasModesWithPolicyBlockingAlarms() =
+        testScope.runTest {
+            val blockingAlarms by collectLastValue(underTest.activeModesBlockingAlarms)
+
+            zenModeRepository.addModes(
+                listOf(
+                    TestModeBuilder()
+                        .setName("Blocks alarms, Not active")
+                        .setZenPolicy(ZenPolicy.Builder().allowAlarms(false).build())
+                        .setActive(false)
+                        .build(),
+                    TestModeBuilder()
+                        .setName("Allows alarms, Active")
+                        .setZenPolicy(ZenPolicy.Builder().allowAlarms(true).build())
+                        .setActive(true)
+                        .build(),
+                    TestModeBuilder()
+                        .setName("Blocks alarms, Active")
+                        .setZenPolicy(ZenPolicy.Builder().allowAlarms(false).build())
+                        .setActive(true)
+                        .build(),
+                    TestModeBuilder()
+                        .setName("Blocks alarms, Active Too")
+                        .setZenPolicy(ZenPolicy.Builder().allowAlarms(false).build())
+                        .setActive(true)
+                        .build(),
+                )
+            )
+            runCurrent()
+
+            assertThat(blockingAlarms!!.mainMode!!.name).isEqualTo("Blocks alarms, Active")
+            assertThat(blockingAlarms!!.modeNames)
+                .containsExactly("Blocks alarms, Active", "Blocks alarms, Active Too")
+                .inOrder()
+        }
+
+    @Test
     @EnableFlags(ModesEmptyShadeFix.FLAG_NAME, Flags.FLAG_MODES_UI, Flags.FLAG_MODES_API)
     fun modesHidingNotifications_onlyIncludesModesWithNotifListSuppression() =
         testScope.runTest {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/ui/dialog/ModesDialogDelegateTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/ui/dialog/ModesDialogDelegateTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/ui/dialog/ModesDialogDelegateTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/ui/dialog/ModesDialogDelegateTest.kt
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/ui/dialog/viewmodel/ModesDialogViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/ui/dialog/viewmodel/ModesDialogViewModelTest.kt
index 9d93a9c..39836e2 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/ui/dialog/viewmodel/ModesDialogViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/ui/dialog/viewmodel/ModesDialogViewModelTest.kt
@@ -19,6 +19,7 @@
 package com.android.systemui.statusbar.policy.ui.dialog.viewmodel
 
 import android.content.Intent
+import android.content.applicationContext
 import android.provider.Settings
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
@@ -38,9 +39,11 @@
 import kotlinx.coroutines.Job
 import kotlinx.coroutines.test.runCurrent
 import kotlinx.coroutines.test.runTest
+import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.mockito.Mockito.clearInvocations
+import org.mockito.MockitoAnnotations
 import org.mockito.kotlin.argumentCaptor
 import org.mockito.kotlin.times
 import org.mockito.kotlin.verify
@@ -55,14 +58,20 @@
     private val mockDialogDelegate = kosmos.mockModesDialogDelegate
     private val mockDialogEventLogger = kosmos.mockModesDialogEventLogger
 
-    private val underTest =
-        ModesDialogViewModel(
-            context,
-            interactor,
-            kosmos.testDispatcher,
-            mockDialogDelegate,
-            mockDialogEventLogger,
-        )
+    private lateinit var underTest: ModesDialogViewModel
+
+    @Before
+    fun setUp() {
+        MockitoAnnotations.initMocks(this)
+        underTest =
+            ModesDialogViewModel(
+                kosmos.applicationContext,
+                interactor,
+                kosmos.testDispatcher,
+                kosmos.mockModesDialogDelegate,
+                kosmos.mockModesDialogEventLogger,
+            )
+    }
 
     @Test
     fun tiles_filtersOutUserDisabledModes() =
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/ui/viewmodel/KeyguardStatusBarViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/ui/viewmodel/KeyguardStatusBarViewModelTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/ui/viewmodel/KeyguardStatusBarViewModelTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/ui/viewmodel/KeyguardStatusBarViewModelTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/window/StatusBarWindowStateControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/window/StatusBarWindowStateControllerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/window/StatusBarWindowStateControllerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/window/StatusBarWindowStateControllerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/window/data/repository/StatusBarWindowStatePerDisplayRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/window/data/repository/StatusBarWindowStatePerDisplayRepositoryTest.kt
similarity index 97%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/window/data/repository/StatusBarWindowStatePerDisplayRepositoryTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/window/data/repository/StatusBarWindowStatePerDisplayRepositoryTest.kt
index 0c27e58..c7c7fdc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/window/data/repository/StatusBarWindowStatePerDisplayRepositoryTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/window/data/repository/StatusBarWindowStatePerDisplayRepositoryTest.kt
@@ -21,6 +21,7 @@
 import android.app.StatusBarManager.WINDOW_STATE_HIDING
 import android.app.StatusBarManager.WINDOW_STATE_SHOWING
 import android.app.StatusBarManager.WINDOW_STATUS_BAR
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.coroutines.collectLastValue
@@ -34,11 +35,13 @@
 import kotlinx.coroutines.test.runCurrent
 import kotlinx.coroutines.test.runTest
 import org.junit.Test
+import org.junit.runner.RunWith
 import org.mockito.Mockito.verify
 import org.mockito.kotlin.argumentCaptor
 
 @SmallTest
 @OptIn(ExperimentalCoroutinesApi::class)
+@RunWith(AndroidJUnit4::class)
 class StatusBarWindowStatePerDisplayRepositoryTest : SysuiTestCase() {
     private val kosmos = testKosmos()
     private val testScope = kosmos.testScope
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/window/data/repository/StatusBarWindowStateRepositoryStoreTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/window/data/repository/StatusBarWindowStateRepositoryStoreTest.kt
similarity index 97%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/window/data/repository/StatusBarWindowStateRepositoryStoreTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/window/data/repository/StatusBarWindowStateRepositoryStoreTest.kt
index b6a3f36..e23e88c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/window/data/repository/StatusBarWindowStateRepositoryStoreTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/window/data/repository/StatusBarWindowStateRepositoryStoreTest.kt
@@ -19,6 +19,7 @@
 import android.app.StatusBarManager.WINDOW_STATE_HIDDEN
 import android.app.StatusBarManager.WINDOW_STATE_SHOWING
 import android.app.StatusBarManager.WINDOW_STATUS_BAR
+import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.coroutines.collectLastValue
@@ -33,12 +34,14 @@
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.test.runCurrent
 import kotlinx.coroutines.test.runTest
+import org.junit.runner.RunWith
 import org.mockito.Mockito.verify
 import org.mockito.kotlin.argumentCaptor
 import org.mockito.kotlin.reset
 
 @SmallTest
 @OptIn(ExperimentalCoroutinesApi::class)
+@RunWith(AndroidJUnit4::class)
 class StatusBarWindowStateRepositoryStoreTest : SysuiTestCase() {
     private val kosmos = testKosmos()
     private val testScope = kosmos.testScope
diff --git a/packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/glowboxeffect/GlowBoxEffectTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/surfaceeffects/glowboxeffect/GlowBoxEffectTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/glowboxeffect/GlowBoxEffectTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/surfaceeffects/glowboxeffect/GlowBoxEffectTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/loadingeffect/LoadingEffectTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/surfaceeffects/loadingeffect/LoadingEffectTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/loadingeffect/LoadingEffectTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/surfaceeffects/loadingeffect/LoadingEffectTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/ripple/MultiRippleControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/surfaceeffects/ripple/MultiRippleControllerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/ripple/MultiRippleControllerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/surfaceeffects/ripple/MultiRippleControllerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/ripple/RippleAnimationTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/surfaceeffects/ripple/RippleAnimationTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/ripple/RippleAnimationTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/surfaceeffects/ripple/RippleAnimationTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/ripple/RippleShaderTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/surfaceeffects/ripple/RippleShaderTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/ripple/RippleShaderTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/surfaceeffects/ripple/RippleShaderTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/ripple/RippleViewTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/surfaceeffects/ripple/RippleViewTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/ripple/RippleViewTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/surfaceeffects/ripple/RippleViewTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/shaders/SolidColorShaderTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/surfaceeffects/shaders/SolidColorShaderTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/shaders/SolidColorShaderTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/surfaceeffects/shaders/SolidColorShaderTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/shaders/SparkleShaderTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/surfaceeffects/shaders/SparkleShaderTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/shaders/SparkleShaderTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/surfaceeffects/shaders/SparkleShaderTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/turbulencenoise/TurbulenceNoiseControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/surfaceeffects/turbulencenoise/TurbulenceNoiseControllerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/turbulencenoise/TurbulenceNoiseControllerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/surfaceeffects/turbulencenoise/TurbulenceNoiseControllerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/turbulencenoise/TurbulenceNoiseShaderTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/surfaceeffects/turbulencenoise/TurbulenceNoiseShaderTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/turbulencenoise/TurbulenceNoiseShaderTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/surfaceeffects/turbulencenoise/TurbulenceNoiseShaderTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/turbulencenoise/TurbulenceNoiseViewTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/surfaceeffects/turbulencenoise/TurbulenceNoiseViewTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/turbulencenoise/TurbulenceNoiseViewTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/surfaceeffects/turbulencenoise/TurbulenceNoiseViewTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/TouchableRegionViewControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/temporarydisplay/TouchableRegionViewControllerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/TouchableRegionViewControllerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/temporarydisplay/TouchableRegionViewControllerTest.kt
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/touchpad/tutorial/ui/gesture/BackGestureMonitorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/touchpad/tutorial/ui/gesture/BackGestureRecognizerTest.kt
similarity index 77%
rename from packages/SystemUI/multivalentTests/src/com/android/systemui/touchpad/tutorial/ui/gesture/BackGestureMonitorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/touchpad/tutorial/ui/gesture/BackGestureRecognizerTest.kt
index 9064f7c..40c3f22 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/touchpad/tutorial/ui/gesture/BackGestureMonitorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/touchpad/tutorial/ui/gesture/BackGestureRecognizerTest.kt
@@ -20,40 +20,43 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
-import com.android.systemui.touchpad.tutorial.ui.gesture.GestureState.FINISHED
-import com.android.systemui.touchpad.tutorial.ui.gesture.GestureState.IN_PROGRESS
-import com.android.systemui.touchpad.tutorial.ui.gesture.GestureState.NOT_STARTED
+import com.android.systemui.touchpad.tutorial.ui.gesture.GestureState.Finished
+import com.android.systemui.touchpad.tutorial.ui.gesture.GestureState.InProgress
+import com.android.systemui.touchpad.tutorial.ui.gesture.GestureState.NotStarted
 import com.android.systemui.touchpad.tutorial.ui.gesture.MultiFingerGesture.Companion.SWIPE_DISTANCE
 import com.google.common.truth.Truth.assertThat
+import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
 
 @SmallTest
 @RunWith(AndroidJUnit4::class)
-class BackGestureMonitorTest : SysuiTestCase() {
+class BackGestureRecognizerTest : SysuiTestCase() {
 
-    private var gestureState = NOT_STARTED
-    private val gestureMonitor =
-        BackGestureMonitor(
-            gestureDistanceThresholdPx = SWIPE_DISTANCE.toInt(),
-            gestureStateChangedCallback = { gestureState = it }
-        )
+    private var gestureState: GestureState = NotStarted
+    private val gestureRecognizer =
+        BackGestureRecognizer(gestureDistanceThresholdPx = SWIPE_DISTANCE.toInt())
+
+    @Before
+    fun before() {
+        gestureRecognizer.addGestureStateCallback { gestureState = it }
+    }
 
     @Test
     fun triggersGestureFinishedForThreeFingerGestureRight() {
-        assertStateAfterEvents(events = ThreeFingerGesture.swipeRight(), expectedState = FINISHED)
+        assertStateAfterEvents(events = ThreeFingerGesture.swipeRight(), expectedState = Finished)
     }
 
     @Test
     fun triggersGestureFinishedForThreeFingerGestureLeft() {
-        assertStateAfterEvents(events = ThreeFingerGesture.swipeLeft(), expectedState = FINISHED)
+        assertStateAfterEvents(events = ThreeFingerGesture.swipeLeft(), expectedState = Finished)
     }
 
     @Test
     fun triggersGestureProgressForThreeFingerGestureStarted() {
         assertStateAfterEvents(
             events = ThreeFingerGesture.startEvents(x = 0f, y = 0f),
-            expectedState = IN_PROGRESS
+            expectedState = InProgress(),
         )
     }
 
@@ -61,28 +64,28 @@
     fun doesntTriggerGestureFinished_onGestureDistanceTooShort() {
         assertStateAfterEvents(
             events = ThreeFingerGesture.swipeLeft(distancePx = SWIPE_DISTANCE / 2),
-            expectedState = NOT_STARTED
+            expectedState = NotStarted,
         )
     }
 
     @Test
     fun doesntTriggerGestureFinished_onThreeFingersSwipeInOtherDirections() {
-        assertStateAfterEvents(events = ThreeFingerGesture.swipeUp(), expectedState = NOT_STARTED)
-        assertStateAfterEvents(events = ThreeFingerGesture.swipeDown(), expectedState = NOT_STARTED)
+        assertStateAfterEvents(events = ThreeFingerGesture.swipeUp(), expectedState = NotStarted)
+        assertStateAfterEvents(events = ThreeFingerGesture.swipeDown(), expectedState = NotStarted)
     }
 
     @Test
     fun doesntTriggerGestureFinished_onTwoFingersSwipe() {
-        assertStateAfterEvents(events = TwoFingerGesture.swipeRight(), expectedState = NOT_STARTED)
+        assertStateAfterEvents(events = TwoFingerGesture.swipeRight(), expectedState = NotStarted)
     }
 
     @Test
     fun doesntTriggerGestureFinished_onFourFingersSwipe() {
-        assertStateAfterEvents(events = FourFingerGesture.swipeRight(), expectedState = NOT_STARTED)
+        assertStateAfterEvents(events = FourFingerGesture.swipeRight(), expectedState = NotStarted)
     }
 
     private fun assertStateAfterEvents(events: List<MotionEvent>, expectedState: GestureState) {
-        events.forEach { gestureMonitor.processTouchpadEvent(it) }
+        events.forEach { gestureRecognizer.accept(it) }
         assertThat(gestureState).isEqualTo(expectedState)
     }
 }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/touchpad/tutorial/ui/gesture/EasterEggGestureTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/touchpad/tutorial/ui/gesture/EasterEggGestureTest.kt
index a83ed56..8406d3b 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/touchpad/tutorial/ui/gesture/EasterEggGestureTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/touchpad/tutorial/ui/gesture/EasterEggGestureTest.kt
@@ -36,10 +36,7 @@
     private var triggered = false
     private val handler =
         TouchpadGestureHandler(
-            BackGestureMonitor(
-                gestureDistanceThresholdPx = SWIPE_DISTANCE.toInt(),
-                gestureStateChangedCallback = {},
-            ),
+            BackGestureRecognizer(gestureDistanceThresholdPx = SWIPE_DISTANCE.toInt()),
             EasterEggGestureMonitor(callback = { triggered = true }),
         )
 
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/touchpad/tutorial/ui/gesture/HomeGestureMonitorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/touchpad/tutorial/ui/gesture/HomeGestureRecognizerTest.kt
similarity index 74%
rename from packages/SystemUI/multivalentTests/src/com/android/systemui/touchpad/tutorial/ui/gesture/HomeGestureMonitorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/touchpad/tutorial/ui/gesture/HomeGestureRecognizerTest.kt
index 6aefbe9..043b775 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/touchpad/tutorial/ui/gesture/HomeGestureMonitorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/touchpad/tutorial/ui/gesture/HomeGestureRecognizerTest.kt
@@ -20,35 +20,38 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
-import com.android.systemui.touchpad.tutorial.ui.gesture.GestureState.FINISHED
-import com.android.systemui.touchpad.tutorial.ui.gesture.GestureState.IN_PROGRESS
-import com.android.systemui.touchpad.tutorial.ui.gesture.GestureState.NOT_STARTED
+import com.android.systemui.touchpad.tutorial.ui.gesture.GestureState.Finished
+import com.android.systemui.touchpad.tutorial.ui.gesture.GestureState.InProgress
+import com.android.systemui.touchpad.tutorial.ui.gesture.GestureState.NotStarted
 import com.android.systemui.touchpad.tutorial.ui.gesture.MultiFingerGesture.Companion.SWIPE_DISTANCE
 import com.google.common.truth.Truth.assertThat
+import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
 
 @SmallTest
 @RunWith(AndroidJUnit4::class)
-class HomeGestureMonitorTest : SysuiTestCase() {
+class HomeGestureRecognizerTest : SysuiTestCase() {
 
-    private var gestureState = NOT_STARTED
-    private val gestureMonitor =
-        HomeGestureMonitor(
-            gestureDistanceThresholdPx = SWIPE_DISTANCE.toInt(),
-            gestureStateChangedCallback = { gestureState = it }
-        )
+    private var gestureState: GestureState = GestureState.NotStarted
+    private val gestureRecognizer =
+        HomeGestureRecognizer(gestureDistanceThresholdPx = SWIPE_DISTANCE.toInt())
+
+    @Before
+    fun before() {
+        gestureRecognizer.addGestureStateCallback { gestureState = it }
+    }
 
     @Test
     fun triggersGestureFinishedForThreeFingerGestureUp() {
-        assertStateAfterEvents(events = ThreeFingerGesture.swipeUp(), expectedState = FINISHED)
+        assertStateAfterEvents(events = ThreeFingerGesture.swipeUp(), expectedState = Finished)
     }
 
     @Test
     fun triggersGestureProgressForThreeFingerGestureStarted() {
         assertStateAfterEvents(
             events = ThreeFingerGesture.startEvents(x = 0f, y = 0f),
-            expectedState = IN_PROGRESS
+            expectedState = InProgress(),
         )
     }
 
@@ -56,32 +59,29 @@
     fun doesntTriggerGestureFinished_onGestureDistanceTooShort() {
         assertStateAfterEvents(
             events = ThreeFingerGesture.swipeUp(distancePx = SWIPE_DISTANCE / 2),
-            expectedState = NOT_STARTED
+            expectedState = NotStarted,
         )
     }
 
     @Test
     fun doesntTriggerGestureFinished_onThreeFingersSwipeInOtherDirections() {
-        assertStateAfterEvents(events = ThreeFingerGesture.swipeDown(), expectedState = NOT_STARTED)
-        assertStateAfterEvents(events = ThreeFingerGesture.swipeLeft(), expectedState = NOT_STARTED)
-        assertStateAfterEvents(
-            events = ThreeFingerGesture.swipeRight(),
-            expectedState = NOT_STARTED
-        )
+        assertStateAfterEvents(events = ThreeFingerGesture.swipeDown(), expectedState = NotStarted)
+        assertStateAfterEvents(events = ThreeFingerGesture.swipeLeft(), expectedState = NotStarted)
+        assertStateAfterEvents(events = ThreeFingerGesture.swipeRight(), expectedState = NotStarted)
     }
 
     @Test
     fun doesntTriggerGestureFinished_onTwoFingersSwipe() {
-        assertStateAfterEvents(events = TwoFingerGesture.swipeUp(), expectedState = NOT_STARTED)
+        assertStateAfterEvents(events = TwoFingerGesture.swipeUp(), expectedState = NotStarted)
     }
 
     @Test
     fun doesntTriggerGestureFinished_onFourFingersSwipe() {
-        assertStateAfterEvents(events = FourFingerGesture.swipeUp(), expectedState = NOT_STARTED)
+        assertStateAfterEvents(events = FourFingerGesture.swipeUp(), expectedState = NotStarted)
     }
 
     private fun assertStateAfterEvents(events: List<MotionEvent>, expectedState: GestureState) {
-        events.forEach { gestureMonitor.processTouchpadEvent(it) }
+        events.forEach { gestureRecognizer.accept(it) }
         assertThat(gestureState).isEqualTo(expectedState)
     }
 }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/touchpad/tutorial/ui/gesture/RecentAppsGestureMonitorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/touchpad/tutorial/ui/gesture/RecentAppsGestureRecognizerTest.kt
similarity index 77%
rename from packages/SystemUI/multivalentTests/src/com/android/systemui/touchpad/tutorial/ui/gesture/RecentAppsGestureMonitorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/touchpad/tutorial/ui/gesture/RecentAppsGestureRecognizerTest.kt
index d059c14..7095a91 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/touchpad/tutorial/ui/gesture/RecentAppsGestureMonitorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/touchpad/tutorial/ui/gesture/RecentAppsGestureRecognizerTest.kt
@@ -21,11 +21,12 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
-import com.android.systemui.touchpad.tutorial.ui.gesture.GestureState.FINISHED
-import com.android.systemui.touchpad.tutorial.ui.gesture.GestureState.IN_PROGRESS
-import com.android.systemui.touchpad.tutorial.ui.gesture.GestureState.NOT_STARTED
+import com.android.systemui.touchpad.tutorial.ui.gesture.GestureState.Finished
+import com.android.systemui.touchpad.tutorial.ui.gesture.GestureState.InProgress
+import com.android.systemui.touchpad.tutorial.ui.gesture.GestureState.NotStarted
 import com.android.systemui.touchpad.tutorial.ui.gesture.MultiFingerGesture.Companion.SWIPE_DISTANCE
 import com.google.common.truth.Truth.assertThat
+import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.mockito.kotlin.doReturn
@@ -34,7 +35,7 @@
 
 @SmallTest
 @RunWith(AndroidJUnit4::class)
-class RecentAppsGestureMonitorTest : SysuiTestCase() {
+class RecentAppsGestureRecognizerTest : SysuiTestCase() {
 
     companion object {
         const val THRESHOLD_VELOCITY_PX_PER_MS = 0.1f
@@ -43,36 +44,40 @@
         const val FAST = THRESHOLD_VELOCITY_PX_PER_MS * 1000 + 1
     }
 
-    private var gestureState = NOT_STARTED
-    private val velocityTracker =
+    private var gestureState: GestureState = GestureState.NotStarted
+    private val velocityTracker1D =
         mock<VelocityTracker1D> {
             // by default return correct speed for the gesture - as if pointer is slowing down
             on { calculateVelocity() } doReturn SLOW
         }
-    private val gestureMonitor =
-        RecentAppsGestureMonitor(
+    private val gestureRecognizer =
+        RecentAppsGestureRecognizer(
             gestureDistanceThresholdPx = SWIPE_DISTANCE.toInt(),
-            gestureStateChangedCallback = { gestureState = it },
             velocityThresholdPxPerMs = THRESHOLD_VELOCITY_PX_PER_MS,
-            velocityTracker = velocityTracker
+            velocityTracker = VerticalVelocityTracker(velocityTracker1D),
         )
 
+    @Before
+    fun before() {
+        gestureRecognizer.addGestureStateCallback { gestureState = it }
+    }
+
     @Test
     fun triggersGestureFinishedForThreeFingerGestureUp() {
-        assertStateAfterEvents(events = ThreeFingerGesture.swipeUp(), expectedState = FINISHED)
+        assertStateAfterEvents(events = ThreeFingerGesture.swipeUp(), expectedState = Finished)
     }
 
     @Test
     fun doesntTriggerGestureFinished_onGestureSpeedTooHigh() {
-        whenever(velocityTracker.calculateVelocity()).thenReturn(FAST)
-        assertStateAfterEvents(events = ThreeFingerGesture.swipeUp(), expectedState = NOT_STARTED)
+        whenever(velocityTracker1D.calculateVelocity()).thenReturn(FAST)
+        assertStateAfterEvents(events = ThreeFingerGesture.swipeUp(), expectedState = NotStarted)
     }
 
     @Test
     fun triggersGestureProgressForThreeFingerGestureStarted() {
         assertStateAfterEvents(
             events = ThreeFingerGesture.startEvents(x = 0f, y = 0f),
-            expectedState = IN_PROGRESS
+            expectedState = InProgress(),
         )
     }
 
@@ -80,32 +85,29 @@
     fun doesntTriggerGestureFinished_onGestureDistanceTooShort() {
         assertStateAfterEvents(
             events = ThreeFingerGesture.swipeUp(distancePx = SWIPE_DISTANCE / 2),
-            expectedState = NOT_STARTED
+            expectedState = NotStarted,
         )
     }
 
     @Test
     fun doesntTriggerGestureFinished_onThreeFingersSwipeInOtherDirections() {
-        assertStateAfterEvents(events = ThreeFingerGesture.swipeDown(), expectedState = NOT_STARTED)
-        assertStateAfterEvents(events = ThreeFingerGesture.swipeLeft(), expectedState = NOT_STARTED)
-        assertStateAfterEvents(
-            events = ThreeFingerGesture.swipeRight(),
-            expectedState = NOT_STARTED
-        )
+        assertStateAfterEvents(events = ThreeFingerGesture.swipeDown(), expectedState = NotStarted)
+        assertStateAfterEvents(events = ThreeFingerGesture.swipeLeft(), expectedState = NotStarted)
+        assertStateAfterEvents(events = ThreeFingerGesture.swipeRight(), expectedState = NotStarted)
     }
 
     @Test
     fun doesntTriggerGestureFinished_onTwoFingersSwipe() {
-        assertStateAfterEvents(events = TwoFingerGesture.swipeUp(), expectedState = NOT_STARTED)
+        assertStateAfterEvents(events = TwoFingerGesture.swipeUp(), expectedState = NotStarted)
     }
 
     @Test
     fun doesntTriggerGestureFinished_onFourFingersSwipe() {
-        assertStateAfterEvents(events = FourFingerGesture.swipeUp(), expectedState = NOT_STARTED)
+        assertStateAfterEvents(events = FourFingerGesture.swipeUp(), expectedState = NotStarted)
     }
 
     private fun assertStateAfterEvents(events: List<MotionEvent>, expectedState: GestureState) {
-        events.forEach { gestureMonitor.processTouchpadEvent(it) }
+        events.forEach { gestureRecognizer.accept(it) }
         assertThat(gestureState).isEqualTo(expectedState)
     }
 }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/touchpad/tutorial/ui/gesture/TouchpadGestureHandlerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/touchpad/tutorial/ui/gesture/TouchpadGestureHandlerTest.kt
index 466ddbe..a867eb3 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/touchpad/tutorial/ui/gesture/TouchpadGestureHandlerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/touchpad/tutorial/ui/gesture/TouchpadGestureHandlerTest.kt
@@ -25,10 +25,9 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
-import com.android.systemui.touchpad.tutorial.ui.gesture.GestureState.FINISHED
-import com.android.systemui.touchpad.tutorial.ui.gesture.GestureState.NOT_STARTED
 import com.android.systemui.touchpad.tutorial.ui.gesture.MultiFingerGesture.Companion.SWIPE_DISTANCE
 import com.google.common.truth.Truth.assertThat
+import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
 
@@ -36,15 +35,15 @@
 @RunWith(AndroidJUnit4::class)
 class TouchpadGestureHandlerTest : SysuiTestCase() {
 
-    private var gestureState = NOT_STARTED
-    private val handler =
-        TouchpadGestureHandler(
-            BackGestureMonitor(
-                gestureDistanceThresholdPx = SWIPE_DISTANCE.toInt(),
-                gestureStateChangedCallback = { gestureState = it },
-            ),
-            EasterEggGestureMonitor {},
-        )
+    private var gestureState: GestureState = GestureState.NotStarted
+    private val gestureRecognizer =
+        BackGestureRecognizer(gestureDistanceThresholdPx = SWIPE_DISTANCE.toInt())
+    private val handler = TouchpadGestureHandler(gestureRecognizer, EasterEggGestureMonitor {})
+
+    @Before
+    fun before() {
+        gestureRecognizer.addGestureStateCallback { gestureState = it }
+    }
 
     @Test
     fun handlesEventsFromTouchpad() {
@@ -82,7 +81,7 @@
     fun triggersGestureDoneForThreeFingerGesture() {
         backGestureEvents().forEach { handler.onMotionEvent(it) }
 
-        assertThat(gestureState).isEqualTo(FINISHED)
+        assertThat(gestureState).isEqualTo(GestureState.Finished)
     }
 
     private fun backGestureEvents(): List<MotionEvent> {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/unfold/UnfoldLatencyTrackerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/unfold/UnfoldLatencyTrackerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/unfold/UnfoldLatencyTrackerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/unfold/UnfoldLatencyTrackerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/unfold/progress/PhysicsBasedUnfoldTransitionProgressProviderTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/unfold/progress/PhysicsBasedUnfoldTransitionProgressProviderTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/unfold/progress/PhysicsBasedUnfoldTransitionProgressProviderTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/unfold/progress/PhysicsBasedUnfoldTransitionProgressProviderTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/unfold/progress/UnfoldRemoteFilterTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/unfold/progress/UnfoldRemoteFilterTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/unfold/progress/UnfoldRemoteFilterTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/unfold/progress/UnfoldRemoteFilterTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/unfold/util/ScaleAwareUnfoldProgressProviderTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/unfold/util/ScaleAwareUnfoldProgressProviderTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/unfold/util/ScaleAwareUnfoldProgressProviderTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/unfold/util/ScaleAwareUnfoldProgressProviderTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/usb/UsbPermissionActivityTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/usb/UsbPermissionActivityTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/usb/UsbPermissionActivityTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/usb/UsbPermissionActivityTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/user/CreateUserActivityTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/user/CreateUserActivityTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/user/CreateUserActivityTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/user/CreateUserActivityTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/user/UserCreatorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/user/UserCreatorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/user/UserCreatorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/user/UserCreatorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/user/data/repository/UserRepositoryImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/user/data/repository/UserRepositoryImplTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/user/data/repository/UserRepositoryImplTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/user/data/repository/UserRepositoryImplTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/GuestUserInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/user/domain/interactor/GuestUserInteractorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/GuestUserInteractorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/user/domain/interactor/GuestUserInteractorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/RefreshUsersSchedulerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/user/domain/interactor/RefreshUsersSchedulerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/RefreshUsersSchedulerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/user/domain/interactor/RefreshUsersSchedulerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/UserSwitcherInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/user/domain/interactor/UserSwitcherInteractorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/UserSwitcherInteractorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/user/domain/interactor/UserSwitcherInteractorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/NotificationChannelsTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/util/NotificationChannelsTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/util/NotificationChannelsTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/util/NotificationChannelsTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/kotlin/FlowUtilTests.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/util/kotlin/FlowUtilTests.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/util/kotlin/FlowUtilTests.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/util/kotlin/FlowUtilTests.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/kotlin/PackageManagerExtComponentEnabledTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/util/kotlin/PackageManagerExtComponentEnabledTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/util/kotlin/PackageManagerExtComponentEnabledTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/util/kotlin/PackageManagerExtComponentEnabledTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/leak/LeakDetectorTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/util/leak/LeakDetectorTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/util/leak/LeakDetectorTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/util/leak/LeakDetectorTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/leak/ReferenceTestUtilsTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/util/leak/ReferenceTestUtilsTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/util/leak/ReferenceTestUtilsTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/util/leak/ReferenceTestUtilsTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/leak/WeakIdentityHashMapTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/util/leak/WeakIdentityHashMapTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/util/leak/WeakIdentityHashMapTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/util/leak/WeakIdentityHashMapTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/sensors/AsyncSensorManagerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/util/sensors/AsyncSensorManagerTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/util/sensors/AsyncSensorManagerTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/util/sensors/AsyncSensorManagerTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/volume/CsdWarningDialogTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/CsdWarningDialogTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/volume/CsdWarningDialogTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/volume/CsdWarningDialogTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogControllerImplTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/VolumeDialogControllerImplTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogControllerImplTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/volume/VolumeDialogControllerImplTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogControllerImplTestKt.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/VolumeDialogControllerImplTestKt.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogControllerImplTestKt.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/volume/VolumeDialogControllerImplTestKt.kt
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/dialog/domain/interactor/VolumeDialogVisibilityInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/dialog/domain/interactor/VolumeDialogVisibilityInteractorTest.kt
index 7ce421a..31d2eb3 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/dialog/domain/interactor/VolumeDialogVisibilityInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/dialog/domain/interactor/VolumeDialogVisibilityInteractorTest.kt
@@ -27,7 +27,7 @@
 import com.android.systemui.plugins.fakeVolumeDialogController
 import com.android.systemui.testKosmos
 import com.android.systemui.volume.Events
-import com.android.systemui.volume.dialog.domain.model.VolumeDialogVisibilityModel
+import com.android.systemui.volume.dialog.shared.model.VolumeDialogVisibilityModel
 import com.google.common.truth.Truth.assertThat
 import kotlin.time.Duration.Companion.days
 import kotlin.time.Duration.Companion.seconds
@@ -44,7 +44,7 @@
 @OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
 @RunWith(AndroidJUnit4::class)
-@TestableLooper.RunWithLooper()
+@TestableLooper.RunWithLooper
 class VolumeDialogVisibilityInteractorTest : SysuiTestCase() {
 
     private val kosmos: Kosmos = testKosmos()
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/dialog/sliders/domain/interactor/VolumeDialogSlidersInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/dialog/sliders/domain/interactor/VolumeDialogSlidersInteractorTest.kt
new file mode 100644
index 0000000..7c5a487
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/dialog/sliders/domain/interactor/VolumeDialogSlidersInteractorTest.kt
@@ -0,0 +1,163 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.volume.dialog.sliders.domain.interactor
+
+import android.content.packageManager
+import android.content.pm.PackageManager
+import android.media.AudioManager
+import android.testing.TestableLooper
+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.kosmos.testScope
+import com.android.systemui.plugins.VolumeDialogController
+import com.android.systemui.plugins.fakeVolumeDialogController
+import com.android.systemui.testKosmos
+import com.android.systemui.volume.dialog.sliders.domain.model.VolumeDialogSliderType
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.kotlin.whenever
+
+private const val AUDIO_SHARING_STREAM = 99
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+@TestableLooper.RunWithLooper
+class VolumeDialogSlidersInteractorTest : SysuiTestCase() {
+
+    private val kosmos = testKosmos()
+
+    private lateinit var underTest: VolumeDialogSlidersInteractor
+
+    private var isTv: Boolean = false
+
+    @Before
+    fun setUp() {
+        with(kosmos) {
+            whenever(packageManager.hasSystemFeature(PackageManager.FEATURE_LEANBACK)).thenAnswer {
+                isTv
+            }
+
+            underTest = kosmos.volumeDialogSlidersInteractor
+        }
+    }
+
+    @Test
+    fun activeStreamIsSlider() =
+        with(kosmos) {
+            testScope.runTest {
+                runCurrent()
+                fakeVolumeDialogController.updateState {
+                    activeStream = AudioManager.STREAM_SYSTEM
+                    states.put(AudioManager.STREAM_MUSIC, buildStreamState())
+                    states.put(AudioManager.STREAM_SYSTEM, buildStreamState())
+                }
+
+                val slidersModel by collectLastValue(underTest.sliders)
+                runCurrent()
+
+                assertThat(slidersModel!!.slider)
+                    .isEqualTo(VolumeDialogSliderType.Stream(AudioManager.STREAM_SYSTEM))
+                assertThat(slidersModel!!.floatingSliders)
+                    .isEqualTo(listOf(VolumeDialogSliderType.Stream(AudioManager.STREAM_MUSIC)))
+            }
+        }
+
+    @Test
+    fun streamsOrder() =
+        with(kosmos) {
+            testScope.runTest {
+                runCurrent()
+                fakeVolumeDialogController.onAccessibilityModeChanged(true)
+                fakeVolumeDialogController.updateState {
+                    activeStream = AudioManager.STREAM_MUSIC
+                    states.put(AUDIO_SHARING_STREAM, buildStreamState { dynamic = true })
+                    states.put(AUDIO_SHARING_STREAM + 1, buildStreamState { dynamic = true })
+                    states.put(AudioManager.STREAM_MUSIC, buildStreamState())
+                    states.put(AudioManager.STREAM_ACCESSIBILITY, buildStreamState())
+                }
+
+                val slidersModel by collectLastValue(underTest.sliders)
+                runCurrent()
+
+                assertThat(slidersModel!!.slider)
+                    .isEqualTo(VolumeDialogSliderType.Stream(AudioManager.STREAM_MUSIC))
+                assertThat(slidersModel!!.floatingSliders)
+                    .isEqualTo(
+                        listOf(
+                            VolumeDialogSliderType.Stream(AudioManager.STREAM_ACCESSIBILITY),
+                            VolumeDialogSliderType.AudioSharingStream(AUDIO_SHARING_STREAM),
+                            VolumeDialogSliderType.RemoteMediaStream(AUDIO_SHARING_STREAM + 1),
+                        )
+                    )
+            }
+        }
+
+    @Test
+    fun accessibilityStreamDisabled_filteredOut() =
+        with(kosmos) {
+            testScope.runTest {
+                runCurrent()
+                fakeVolumeDialogController.onAccessibilityModeChanged(false)
+                fakeVolumeDialogController.updateState {
+                    states.put(AudioManager.STREAM_ACCESSIBILITY, buildStreamState())
+                    states.put(AudioManager.STREAM_MUSIC, buildStreamState())
+                }
+
+                val slidersModel by collectLastValue(underTest.sliders)
+                runCurrent()
+
+                assertThat(slidersModel!!.slider)
+                    .isEqualTo(VolumeDialogSliderType.Stream(AudioManager.STREAM_MUSIC))
+                assertThat(slidersModel!!.floatingSliders).isEmpty()
+            }
+        }
+
+    @Test
+    fun isTv_onlyActiveStream() =
+        with(kosmos) {
+            testScope.runTest {
+                runCurrent()
+                isTv = true
+                fakeVolumeDialogController.updateState {
+                    activeStream = AudioManager.STREAM_SYSTEM
+                    states.put(AudioManager.STREAM_MUSIC, buildStreamState())
+                    states.put(AudioManager.STREAM_SYSTEM, buildStreamState())
+                }
+
+                val slidersModel by collectLastValue(underTest.sliders)
+                runCurrent()
+
+                assertThat(slidersModel!!.slider)
+                    .isEqualTo(VolumeDialogSliderType.Stream(AudioManager.STREAM_SYSTEM))
+                assertThat(slidersModel!!.floatingSliders).isEmpty()
+            }
+        }
+
+    private fun buildStreamState(
+        build: VolumeDialogController.StreamState.() -> Unit = {}
+    ): VolumeDialogController.StreamState {
+        return VolumeDialogController.StreamState().apply(build)
+    }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/MediaOutputComponentInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/MediaOutputComponentInteractorTest.kt
index fa7f37c..449dc20 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/MediaOutputComponentInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/MediaOutputComponentInteractorTest.kt
@@ -16,11 +16,16 @@
 
 package com.android.systemui.volume.panel.component.mediaoutput.domain.interactor
 
+import android.content.mockedContext
+import android.content.packageManager
+import android.content.pm.PackageManager.FEATURE_PC
 import android.graphics.drawable.TestStubDrawable
 import android.media.AudioManager
+import android.platform.test.annotations.EnableFlags
 import android.testing.TestableLooper
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
+import com.android.media.flags.Flags;
 import com.android.settingslib.R
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.coroutines.collectLastValue
@@ -42,6 +47,7 @@
 import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
+import org.mockito.kotlin.whenever
 
 private const val builtInDeviceName = "This phone"
 
@@ -79,6 +85,8 @@
     fun inCall_stateIs_Calling() =
         with(kosmos) {
             testScope.runTest {
+                whenever(mockedContext.getPackageManager()).thenReturn(packageManager)
+                whenever(packageManager.hasSystemFeature(FEATURE_PC)).thenReturn(false)
                 with(audioRepository) {
                     setMode(AudioManager.MODE_IN_CALL)
                     setCommunicationDevice(TestAudioDevicesFactory.builtInDevice())
@@ -98,6 +106,33 @@
             }
         }
 
+    @EnableFlags(Flags.FLAG_ENABLE_AUDIO_INPUT_DEVICE_ROUTING_AND_VOLUME_CONTROL)
+    @Test
+    fun inCall_stateIs_Calling_enableInputRouting_desktop() =
+        with(kosmos) {
+            testScope.runTest {
+                whenever(mockedContext.getPackageManager()).thenReturn(packageManager)
+                whenever(packageManager.hasSystemFeature(FEATURE_PC)).thenReturn(true)
+
+                with(audioRepository) {
+                    setMode(AudioManager.MODE_IN_CALL)
+                    setCommunicationDevice(TestAudioDevicesFactory.builtInDevice())
+                }
+
+                val model by collectLastValue(underTest.mediaOutputModel.filterData())
+                runCurrent()
+
+                assertThat(model)
+                    .isEqualTo(
+                        MediaOutputComponentModel.Calling(
+                            device = AudioOutputDevice.BuiltIn(builtInDeviceName, testIcon),
+                            isInAudioSharing = false,
+                            canOpenAudioSwitcher = true,
+                        )
+                    )
+            }
+        }
+
     @Test
     fun hasSession_stateIs_MediaSession() =
         with(kosmos) {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/AudioStreamSliderViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/AudioStreamSliderViewModelTest.kt
new file mode 100644
index 0000000..f80b36a
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/AudioStreamSliderViewModelTest.kt
@@ -0,0 +1,174 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.volume.panel.component.volume.slider.ui.viewmodel
+
+import android.app.Flags
+import android.app.NotificationManager.INTERRUPTION_FILTER_NONE
+import android.media.AudioManager
+import android.platform.test.annotations.EnableFlags
+import android.service.notification.ZenPolicy
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.internal.logging.uiEventLogger
+import com.android.settingslib.notification.modes.TestModeBuilder
+import com.android.settingslib.volume.shared.model.AudioStream
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.statusbar.policy.data.repository.fakeZenModeRepository
+import com.android.systemui.statusbar.policy.domain.interactor.zenModeInteractor
+import com.android.systemui.testKosmos
+import com.android.systemui.volume.domain.interactor.audioVolumeInteractor
+import com.android.systemui.volume.shared.volumePanelLogger
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class AudioStreamSliderViewModelTest : SysuiTestCase() {
+
+    private val kosmos = testKosmos()
+    private val testScope = kosmos.testScope
+    private val zenModeRepository = kosmos.fakeZenModeRepository
+
+    private lateinit var mediaStream: AudioStreamSliderViewModel
+    private lateinit var alarmsStream: AudioStreamSliderViewModel
+    private lateinit var notificationStream: AudioStreamSliderViewModel
+    private lateinit var otherStream: AudioStreamSliderViewModel
+
+    @Before
+    fun setUp() {
+        mediaStream = audioStreamSliderViewModel(AudioManager.STREAM_MUSIC)
+        alarmsStream = audioStreamSliderViewModel(AudioManager.STREAM_ALARM)
+        notificationStream = audioStreamSliderViewModel(AudioManager.STREAM_NOTIFICATION)
+        otherStream = audioStreamSliderViewModel(AudioManager.STREAM_VOICE_CALL)
+    }
+
+    private fun audioStreamSliderViewModel(stream: Int): AudioStreamSliderViewModel {
+        return AudioStreamSliderViewModel(
+            AudioStreamSliderViewModel.FactoryAudioStreamWrapper(AudioStream(stream)),
+            testScope.backgroundScope,
+            context,
+            kosmos.audioVolumeInteractor,
+            kosmos.zenModeInteractor,
+            kosmos.uiEventLogger,
+            kosmos.volumePanelLogger,
+        )
+    }
+
+    @Test
+    @EnableFlags(Flags.FLAG_MODES_UI, Flags.FLAG_MODES_UI_ICONS)
+    fun slider_media_hasDisabledByModesText() =
+        testScope.runTest {
+            val mediaSlider by collectLastValue(mediaStream.slider)
+
+            zenModeRepository.addMode(
+                TestModeBuilder()
+                    .setName("Media is ok")
+                    .setZenPolicy(ZenPolicy.Builder().allowAllSounds().build())
+                    .setActive(true)
+                    .build()
+            )
+            zenModeRepository.addMode(
+                TestModeBuilder()
+                    .setName("No media plz")
+                    .setZenPolicy(ZenPolicy.Builder().allowMedia(false).build())
+                    .setActive(true)
+                    .build()
+            )
+            runCurrent()
+
+            assertThat(mediaSlider!!.disabledMessage)
+                .isEqualTo("Unavailable because No media plz is on")
+
+            zenModeRepository.clearModes()
+            runCurrent()
+
+            assertThat(mediaSlider!!.disabledMessage).isEqualTo("Unavailable")
+        }
+
+    @Test
+    @EnableFlags(Flags.FLAG_MODES_UI, Flags.FLAG_MODES_UI_ICONS)
+    fun slider_alarms_hasDisabledByModesText() =
+        testScope.runTest {
+            val alarmsSlider by collectLastValue(alarmsStream.slider)
+
+            zenModeRepository.addMode(
+                TestModeBuilder()
+                    .setName("Alarms are ok")
+                    .setZenPolicy(ZenPolicy.Builder().allowAllSounds().build())
+                    .setActive(true)
+                    .build()
+            )
+            zenModeRepository.addMode(
+                TestModeBuilder()
+                    .setName("Zzzzz")
+                    .setZenPolicy(ZenPolicy.Builder().allowAlarms(false).build())
+                    .setActive(true)
+                    .build()
+            )
+            runCurrent()
+
+            assertThat(alarmsSlider!!.disabledMessage).isEqualTo("Unavailable because Zzzzz is on")
+
+            zenModeRepository.clearModes()
+            runCurrent()
+
+            assertThat(alarmsSlider!!.disabledMessage).isEqualTo("Unavailable")
+        }
+
+    @Test
+    @EnableFlags(Flags.FLAG_MODES_UI, Flags.FLAG_MODES_UI_ICONS)
+    fun slider_other_hasDisabledByModesText() =
+        testScope.runTest {
+            val otherSlider by collectLastValue(otherStream.slider)
+
+            zenModeRepository.addMode(
+                TestModeBuilder()
+                    .setName("Everything blocked")
+                    .setInterruptionFilter(INTERRUPTION_FILTER_NONE)
+                    .setActive(true)
+                    .build()
+            )
+            runCurrent()
+
+            assertThat(otherSlider!!.disabledMessage)
+                .isEqualTo("Unavailable because Everything blocked is on")
+
+            zenModeRepository.clearModes()
+            runCurrent()
+
+            assertThat(otherSlider!!.disabledMessage).isEqualTo("Unavailable")
+        }
+
+    @Test
+    @EnableFlags(Flags.FLAG_MODES_UI, Flags.FLAG_MODES_UI_ICONS)
+    fun slider_notification_hasSpecialDisabledText() =
+        testScope.runTest {
+            val notificationSlider by collectLastValue(notificationStream.slider)
+            runCurrent()
+
+            assertThat(notificationSlider!!.disabledMessage)
+                .isEqualTo("Unavailable because ring is muted")
+        }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/volume/panel/ui/viewmodel/VolumePanelViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/ui/viewmodel/VolumePanelViewModelTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/volume/panel/ui/viewmodel/VolumePanelViewModelTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/ui/viewmodel/VolumePanelViewModelTest.kt
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/wallpapers/data/repository/FakeWallpaperRepository.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/wallpapers/data/repository/FakeWallpaperRepository.kt
index fe5024f..59676ce 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/wallpapers/data/repository/FakeWallpaperRepository.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/wallpapers/data/repository/FakeWallpaperRepository.kt
@@ -17,10 +17,17 @@
 package com.android.systemui.wallpapers.data.repository
 
 import android.app.WallpaperInfo
+import android.view.View
 import kotlinx.coroutines.flow.MutableStateFlow
 
 /** Fake implementation of the wallpaper repository. */
 class FakeWallpaperRepository : WallpaperRepository {
     override val wallpaperInfo = MutableStateFlow<WallpaperInfo?>(null)
     override val wallpaperSupportsAmbientMode = MutableStateFlow(false)
+    override var rootView: View? = null
+    private val _notificationStackAbsoluteBottom = MutableStateFlow(0F)
+
+    override fun setNotificationStackAbsoluteBottom(bottom: Float) {
+        _notificationStackAbsoluteBottom.value = bottom
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wallpapers/data/repository/WallpaperRepositoryImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/wallpapers/data/repository/WallpaperRepositoryImplTest.kt
similarity index 83%
rename from packages/SystemUI/tests/src/com/android/systemui/wallpapers/data/repository/WallpaperRepositoryImplTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/wallpapers/data/repository/WallpaperRepositoryImplTest.kt
index bdecf2b..b8dd334 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wallpapers/data/repository/WallpaperRepositoryImplTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/wallpapers/data/repository/WallpaperRepositoryImplTest.kt
@@ -18,18 +18,21 @@
 
 import android.app.WallpaperInfo
 import android.app.WallpaperManager
+import android.content.ComponentName
 import android.content.Intent
 import android.content.pm.UserInfo
+import android.platform.test.annotations.EnableFlags
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
+import com.android.systemui.Flags
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.keyguard.data.repository.FakeKeyguardClockRepository
+import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
 import com.android.systemui.user.data.model.SelectedUserModel
 import com.android.systemui.user.data.model.SelectionStatus
 import com.android.systemui.user.data.repository.FakeUserRepository
-import com.android.systemui.util.mockito.any
-import com.android.systemui.util.mockito.mock
-import com.android.systemui.util.mockito.whenever
+import com.android.systemui.wallpapers.data.repository.WallpaperRepositoryImpl.Companion.MAGIC_PORTRAIT_CLASSNAME
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.test.StandardTestDispatcher
@@ -39,6 +42,9 @@
 import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
+import org.mockito.kotlin.any
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.whenever
 
 @SmallTest
 @OptIn(ExperimentalCoroutinesApi::class)
@@ -48,6 +54,8 @@
     private val testDispatcher = StandardTestDispatcher()
     private val testScope = TestScope(testDispatcher)
     private val userRepository = FakeUserRepository()
+    private val keyguardClockRepository = FakeKeyguardClockRepository()
+    private val keyguardRepository = FakeKeyguardRepository()
     private val wallpaperManager: WallpaperManager = mock()
 
     private val underTest: WallpaperRepositoryImpl by lazy {
@@ -56,6 +64,8 @@
             testDispatcher,
             fakeBroadcastDispatcher,
             userRepository,
+            keyguardRepository,
+            keyguardClockRepository,
             wallpaperManager,
             context,
         )
@@ -219,7 +229,7 @@
         testScope.runTest {
             context.orCreateTestableResources.addOverride(
                 com.android.internal.R.bool.config_dozeSupportsAodWallpaper,
-                false
+                false,
             )
 
             val latest by collectLastValue(underTest.wallpaperInfo)
@@ -407,7 +417,7 @@
         testScope.runTest {
             context.orCreateTestableResources.addOverride(
                 com.android.internal.R.bool.config_dozeSupportsAodWallpaper,
-                false
+                false,
             )
 
             val latest by collectLastValue(underTest.wallpaperSupportsAmbientMode)
@@ -425,6 +435,54 @@
             assertThat(latest).isFalse()
         }
 
+    @Test
+    @EnableFlags(Flags.FLAG_MAGIC_PORTRAIT_WALLPAPERS)
+    fun shouldSendNotificationLayout_setMagicPortraitWallpaper_launchSendLayoutJob() =
+        testScope.runTest {
+            val latest by collectLastValue(underTest.shouldSendNotificationLayout)
+            val magicPortraitWallpaper =
+                mock<WallpaperInfo>().apply {
+                    whenever(this.component)
+                        .thenReturn(ComponentName(context, MAGIC_PORTRAIT_CLASSNAME))
+                }
+            whenever(wallpaperManager.getWallpaperInfoForUser(any()))
+                .thenReturn(magicPortraitWallpaper)
+            fakeBroadcastDispatcher.sendIntentToMatchingReceiversOnly(
+                context,
+                Intent(Intent.ACTION_WALLPAPER_CHANGED),
+            )
+            assertThat(latest).isTrue()
+            assertThat(underTest.sendLockscreenLayoutJob).isNotNull()
+            assertThat(underTest.sendLockscreenLayoutJob!!.isActive).isEqualTo(true)
+        }
+
+    @Test
+    @EnableFlags(Flags.FLAG_MAGIC_PORTRAIT_WALLPAPERS)
+    fun shouldSendNotificationLayout_setNotMagicPortraitWallpaper_cancelSendLayoutJob() =
+        testScope.runTest {
+            val latest by collectLastValue(underTest.shouldSendNotificationLayout)
+            val magicPortraitWallpaper = MAGIC_PORTRAIT_WP
+            whenever(wallpaperManager.getWallpaperInfoForUser(any()))
+                .thenReturn(magicPortraitWallpaper)
+            fakeBroadcastDispatcher.sendIntentToMatchingReceiversOnly(
+                context,
+                Intent(Intent.ACTION_WALLPAPER_CHANGED),
+            )
+            assertThat(latest).isTrue()
+            assertThat(underTest.sendLockscreenLayoutJob).isNotNull()
+            assertThat(underTest.sendLockscreenLayoutJob!!.isActive).isEqualTo(true)
+
+            val nonMagicPortraitWallpaper = UNSUPPORTED_WP
+            whenever(wallpaperManager.getWallpaperInfoForUser(any()))
+                .thenReturn(nonMagicPortraitWallpaper)
+            fakeBroadcastDispatcher.sendIntentToMatchingReceiversOnly(
+                context,
+                Intent(Intent.ACTION_WALLPAPER_CHANGED),
+            )
+            assertThat(latest).isFalse()
+            assertThat(underTest.sendLockscreenLayoutJob?.isCancelled).isEqualTo(true)
+        }
+
     private companion object {
         val USER_WITH_UNSUPPORTED_WP = UserInfo(/* id= */ 3, /* name= */ "user3", /* flags= */ 0)
         val UNSUPPORTED_WP =
@@ -433,5 +491,10 @@
         val USER_WITH_SUPPORTED_WP = UserInfo(/* id= */ 4, /* name= */ "user4", /* flags= */ 0)
         val SUPPORTED_WP =
             mock<WallpaperInfo>().apply { whenever(this.supportsAmbientMode()).thenReturn(true) }
+
+        val MAGIC_PORTRAIT_WP =
+            mock<WallpaperInfo>().apply {
+                whenever(this.component).thenReturn(ComponentName("", MAGIC_PORTRAIT_CLASSNAME))
+            }
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubbleEducationControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/wmshell/BubbleEducationControllerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/wmshell/BubbleEducationControllerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/wmshell/BubbleEducationControllerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTestActivity.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/wmshell/BubblesTestActivity.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTestActivity.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/wmshell/BubblesTestActivity.java
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/VolumeDialogController.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/VolumeDialogController.java
index b1736b1..c09509d 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/VolumeDialogController.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/VolumeDialogController.java
@@ -14,7 +14,6 @@
 
 package com.android.systemui.plugins;
 
-import android.annotation.IntegerRes;
 import android.content.ComponentName;
 import android.media.AudioManager;
 import android.media.AudioSystem;
@@ -22,6 +21,8 @@
 import android.os.VibrationEffect;
 import android.util.SparseArray;
 
+import androidx.annotation.StringRes;
+
 import com.android.systemui.plugins.VolumeDialogController.Callbacks;
 import com.android.systemui.plugins.VolumeDialogController.State;
 import com.android.systemui.plugins.VolumeDialogController.StreamState;
@@ -90,7 +91,7 @@
         public int levelMax;
         public boolean muted;
         public boolean muteSupported;
-        public @IntegerRes int name;
+        public @StringRes int name;
         public String remoteLabel;
         public boolean routedToBluetooth;
 
diff --git a/packages/SystemUI/res-keyguard/layout-land/keyguard_pattern_view.xml b/packages/SystemUI/res-keyguard/layout-land/keyguard_pattern_view.xml
deleted file mode 100644
index 8a77d88..0000000
--- a/packages/SystemUI/res-keyguard/layout-land/keyguard_pattern_view.xml
+++ /dev/null
@@ -1,100 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-**
-** Copyright 2024, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License")
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-
-<!-- This is the screen that shows the 9 circle unlock widget and instructs
-     the user how to unlock their device, or make an emergency call.  This
-     is the landscape layout.  -->
-<com.android.keyguard.KeyguardPatternView
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:androidprv="http://schemas.android.com/apk/res-auto"
-    android:id="@+id/keyguard_pattern_view"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:layout_gravity="center_horizontal|bottom"
-    android:clipChildren="false"
-    android:clipToPadding="false"
-    android:orientation="horizontal">
-
-    <androidx.constraintlayout.widget.ConstraintLayout
-        android:layout_width="0dp"
-        android:layout_height="match_parent"
-        android:layout_weight="2"
-        android:clipChildren="false"
-        android:clipToPadding="false"
-        android:layoutDirection="ltr"
-        android:orientation="vertical">
-
-        <include layout="@layout/keyguard_bouncer_message_area"/>
-
-        <com.android.systemui.bouncer.ui.BouncerMessageView
-            android:id="@+id/bouncer_message_view"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:orientation="vertical"
-            androidprv:layout_constraintBottom_toTopOf="@+id/lockPatternView"
-            androidprv:layout_constraintTop_toTopOf="parent"
-            androidprv:layout_constraintVertical_chainStyle="packed" />
-
-        <include
-            android:id="@+id/keyguard_selector_fade_container"
-            layout="@layout/keyguard_eca"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:layout_gravity="bottom|center_horizontal"
-            android:layout_marginBottom="@dimen/keyguard_eca_bottom_margin"
-            android:layout_marginTop="@dimen/keyguard_eca_top_margin"
-            android:gravity="center_horizontal"
-            android:orientation="vertical"
-            androidprv:layout_constraintBottom_toBottomOf="parent" />
-
-    </androidx.constraintlayout.widget.ConstraintLayout>
-
-    <androidx.constraintlayout.widget.ConstraintLayout
-        android:id="@+id/pattern_container"
-        android:layout_width="0dp"
-        android:layout_height="match_parent"
-        android:layout_weight="3"
-        android:clipChildren="false"
-        android:clipToPadding="false"
-        android:layoutDirection="ltr"
-        android:orientation="vertical">
-
-        <androidx.constraintlayout.widget.Guideline
-            android:id="@+id/pattern_top_guideline"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:orientation="horizontal"
-            androidprv:layout_constraintGuide_percent="0" />
-
-        <com.android.internal.widget.LockPatternView
-            android:id="@+id/lockPatternView"
-            android:layout_width="0dp"
-            android:layout_height="0dp"
-            android:clipChildren="false"
-            android:clipToPadding="false"
-            android:orientation="horizontal"
-            androidprv:layout_constraintDimensionRatio="1.0"
-            androidprv:layout_constraintVertical_bias="1.0"
-            androidprv:layout_constraintLeft_toLeftOf="parent"
-            androidprv:layout_constraintRight_toRightOf="parent"
-            androidprv:layout_constraintBottom_toBottomOf="parent"
-            androidprv:layout_constraintTop_toBottomOf="@id/pattern_top_guideline"/>
-
-    </androidx.constraintlayout.widget.ConstraintLayout>
-</com.android.keyguard.KeyguardPatternView>
diff --git a/packages/SystemUI/res-keyguard/layout-land/keyguard_sim_pin_view.xml b/packages/SystemUI/res-keyguard/layout-land/keyguard_sim_pin_view.xml
deleted file mode 100644
index 4b8b63f..0000000
--- a/packages/SystemUI/res-keyguard/layout-land/keyguard_sim_pin_view.xml
+++ /dev/null
@@ -1,221 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-**
-** Copyright 2024, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License")
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-<!-- This is the SIM PIN view that allows the user to enter a SIM PIN to unlock the device. -->
-<com.android.keyguard.KeyguardSimPinView xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:androidprv="http://schemas.android.com/apk/res-auto"
-    xmlns:app="http://schemas.android.com/apk/res-auto"
-    android:id="@+id/keyguard_sim_pin_view"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:layout_gravity="center_horizontal|bottom"
-    android:clipChildren="false"
-    android:clipToPadding="false"
-    android:orientation="horizontal">
-
-    <androidx.constraintlayout.widget.ConstraintLayout
-        android:layout_width="0dp"
-        android:layout_height="match_parent"
-        android:layout_weight="2"
-        android:clipChildren="false"
-        android:clipToPadding="false"
-        android:layoutDirection="ltr"
-        android:orientation="vertical">
-
-        <include layout="@layout/keyguard_bouncer_message_area"/>
-
-        <ImageView
-            android:id="@+id/keyguard_sim"
-            android:layout_width="40dp"
-            android:layout_height="40dp"
-            android:layout_marginBottom="3dp"
-            android:src="@drawable/ic_lockscreen_sim"
-            androidprv:layout_constraintBottom_toTopOf="@+id/pin_entry_area"
-            androidprv:layout_constraintLeft_toLeftOf="parent"
-            androidprv:layout_constraintRight_toRightOf="parent"
-            app:tint="@color/background_protected"/>
-
-        <include
-            android:id="@+id/keyguard_esim_area"
-            layout="@layout/keyguard_esim_area"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            androidprv:layout_constraintLeft_toLeftOf="parent"
-            androidprv:layout_constraintRight_toRightOf="parent"
-            androidprv:layout_constraintBottom_toTopOf="@+id/pin_entry_area"/>
-
-        <com.android.keyguard.AlphaOptimizedRelativeLayout
-            android:id="@+id/pin_entry_area"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:orientation="vertical"
-            android:paddingBottom="@dimen/num_pad_entry_row_margin_bottom"
-            androidprv:layout_constraintBottom_toTopOf="@+id/keyguard_selector_fade_container">
-
-            <com.android.keyguard.PasswordTextView
-                android:id="@+id/simPinEntry"
-                style="@style/Widget.TextView.Password"
-                android:layout_width="@dimen/keyguard_security_width"
-                android:layout_height="@dimen/keyguard_password_height"
-                android:layout_centerHorizontal="true"
-                android:layout_marginRight="72dp"
-                android:contentDescription="@string/keyguard_accessibility_sim_pin_area"
-                androidprv:scaledTextSize="@integer/scaled_password_text_size" />
-        </com.android.keyguard.AlphaOptimizedRelativeLayout>
-
-        <include
-            android:id="@+id/keyguard_selector_fade_container"
-            layout="@layout/keyguard_eca"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:layout_gravity="bottom|center_horizontal"
-            android:layout_marginBottom="@dimen/keyguard_eca_bottom_margin"
-            android:layout_marginTop="@dimen/keyguard_eca_top_margin"
-            android:gravity="center_horizontal"
-            android:orientation="vertical"
-            androidprv:layout_constraintBottom_toBottomOf="parent"/>
-
-    </androidx.constraintlayout.widget.ConstraintLayout>
-
-    <androidx.constraintlayout.widget.ConstraintLayout
-        android:id="@+id/sim_pin_container"
-        android:layout_width="0dp"
-        android:layout_height="match_parent"
-        android:layout_weight="3"
-        android:clipChildren="false"
-        android:clipToPadding="false"
-        android:layoutDirection="ltr"
-        android:orientation="vertical">
-
-        <androidx.constraintlayout.helper.widget.Flow
-            android:id="@+id/flow1"
-            android:layout_width="0dp"
-            android:layout_height="0dp"
-            android:clipChildren="false"
-            android:clipToPadding="false"
-            android:orientation="horizontal"
-            androidprv:constraint_referenced_ids="key1,key2,key3,key4,key5,key6,key7,key8,key9,delete_button,key0,key_enter"
-            androidprv:flow_horizontalGap="@dimen/num_pad_key_margin_end"
-            androidprv:flow_horizontalStyle="packed"
-            androidprv:flow_maxElementsWrap="3"
-            androidprv:flow_verticalBias="0.5"
-            androidprv:flow_verticalGap="@dimen/num_pad_entry_row_margin_bottom"
-            androidprv:flow_verticalStyle="packed"
-            androidprv:flow_wrapMode="aligned"
-            androidprv:layout_constraintLeft_toLeftOf="parent"
-            androidprv:layout_constraintRight_toRightOf="parent"
-            androidprv:layout_constraintTop_toTopOf="parent"
-            androidprv:layout_constraintBottom_toBottomOf="parent"/>
-
-        <com.android.keyguard.NumPadButton
-            android:id="@+id/delete_button"
-            style="@style/NumPadKey.Delete"
-            android:layout_width="0dp"
-            android:layout_height="0dp"
-            android:accessibilityTraversalBefore="@id/key0"
-            android:contentDescription="@string/keyboardview_keycode_delete" />
-
-        <com.android.keyguard.NumPadButton
-            android:id="@+id/key_enter"
-            style="@style/NumPadKey.Enter"
-            android:layout_width="0dp"
-            android:layout_height="0dp"
-            android:contentDescription="@string/keyboardview_keycode_enter" />
-
-        <com.android.keyguard.NumPadKey
-            android:id="@+id/key1"
-            android:layout_width="0dp"
-            android:layout_height="0dp"
-            android:accessibilityTraversalBefore="@id/key2"
-            androidprv:digit="1"
-            androidprv:textView="@+id/simPinEntry" />
-
-        <com.android.keyguard.NumPadKey
-            android:id="@+id/key2"
-            android:layout_width="0dp"
-            android:layout_height="0dp"
-            android:accessibilityTraversalBefore="@id/key3"
-            androidprv:digit="2"
-            androidprv:textView="@+id/simPinEntry" />
-
-        <com.android.keyguard.NumPadKey
-            android:id="@+id/key3"
-            android:layout_width="0dp"
-            android:layout_height="0dp"
-            android:accessibilityTraversalBefore="@id/key4"
-            androidprv:digit="3"
-            androidprv:textView="@+id/simPinEntry" />
-
-        <com.android.keyguard.NumPadKey
-            android:id="@+id/key4"
-            android:layout_width="0dp"
-            android:layout_height="0dp"
-            android:accessibilityTraversalBefore="@id/key5"
-            androidprv:digit="4"
-            androidprv:textView="@+id/simPinEntry" />
-
-        <com.android.keyguard.NumPadKey
-            android:id="@+id/key5"
-            android:layout_width="0dp"
-            android:layout_height="0dp"
-            android:accessibilityTraversalBefore="@id/key6"
-            androidprv:digit="5"
-            androidprv:textView="@+id/simPinEntry" />
-
-
-        <com.android.keyguard.NumPadKey
-            android:id="@+id/key6"
-            android:layout_width="0dp"
-            android:layout_height="0dp"
-            android:accessibilityTraversalBefore="@id/key7"
-            androidprv:digit="6"
-            androidprv:textView="@+id/simPinEntry" />
-
-        <com.android.keyguard.NumPadKey
-            android:id="@+id/key7"
-            android:layout_width="0dp"
-            android:layout_height="0dp"
-            android:accessibilityTraversalBefore="@id/key8"
-            androidprv:digit="7"
-            androidprv:textView="@+id/simPinEntry" />
-
-        <com.android.keyguard.NumPadKey
-            android:id="@+id/key8"
-            android:layout_width="0dp"
-            android:layout_height="0dp"
-            android:accessibilityTraversalBefore="@id/key9"
-            androidprv:digit="8"
-            androidprv:textView="@+id/simPinEntry" />
-
-        <com.android.keyguard.NumPadKey
-            android:id="@+id/key9"
-            android:layout_width="0dp"
-            android:layout_height="0dp"
-            android:accessibilityTraversalBefore="@id/delete_button"
-            androidprv:digit="9"
-            androidprv:textView="@+id/simPinEntry" />
-
-        <com.android.keyguard.NumPadKey
-            android:id="@+id/key0"
-            android:layout_width="0dp"
-            android:layout_height="0dp"
-            android:accessibilityTraversalBefore="@id/key_enter"
-            androidprv:digit="0"
-            androidprv:textView="@+id/simPinEntry" />
-    </androidx.constraintlayout.widget.ConstraintLayout>
-</com.android.keyguard.KeyguardSimPinView>
diff --git a/packages/SystemUI/res-keyguard/layout-land/keyguard_sim_puk_view.xml b/packages/SystemUI/res-keyguard/layout-land/keyguard_sim_puk_view.xml
deleted file mode 100644
index 9012856..0000000
--- a/packages/SystemUI/res-keyguard/layout-land/keyguard_sim_puk_view.xml
+++ /dev/null
@@ -1,223 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-**
-** Copyright 2024, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License")
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-<!-- This is the SIM PUK view that allows the user to recover their device by entering the
-    carrier-provided PUK code and entering a new SIM PIN for it. -->
-<com.android.keyguard.KeyguardSimPukView
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:androidprv="http://schemas.android.com/apk/res-auto"
-    xmlns:app="http://schemas.android.com/apk/res-auto"
-    android:id="@+id/keyguard_sim_puk_view"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:layout_gravity="center_horizontal|bottom"
-    android:clipChildren="false"
-    android:clipToPadding="false"
-    android:orientation="horizontal">
-
-    <androidx.constraintlayout.widget.ConstraintLayout
-        android:layout_width="0dp"
-        android:layout_height="match_parent"
-        android:layout_weight="2"
-        android:clipChildren="false"
-        android:clipToPadding="false"
-        android:layoutDirection="ltr"
-        android:orientation="vertical">
-
-        <include layout="@layout/keyguard_bouncer_message_area"/>
-
-        <ImageView
-            android:id="@+id/keyguard_sim"
-            android:layout_width="40dp"
-            android:layout_height="40dp"
-            android:layout_marginBottom="3dp"
-            android:src="@drawable/ic_lockscreen_sim"
-            androidprv:layout_constraintBottom_toTopOf="@+id/pin_entry_area"
-            androidprv:layout_constraintLeft_toLeftOf="parent"
-            androidprv:layout_constraintRight_toRightOf="parent"
-            app:tint="@color/background_protected"/>
-
-        <include
-            android:id="@+id/keyguard_esim_area"
-            layout="@layout/keyguard_esim_area"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            androidprv:layout_constraintLeft_toLeftOf="parent"
-            androidprv:layout_constraintRight_toRightOf="parent"
-            androidprv:layout_constraintBottom_toTopOf="@+id/pin_entry_area"/>
-
-        <com.android.keyguard.AlphaOptimizedRelativeLayout
-            android:id="@+id/pin_entry_area"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:orientation="vertical"
-            android:paddingBottom="@dimen/num_pad_entry_row_margin_bottom"
-            androidprv:layout_constraintBottom_toTopOf="@+id/keyguard_selector_fade_container">
-
-            <com.android.keyguard.PasswordTextView
-                android:id="@+id/pukEntry"
-                style="@style/Widget.TextView.Password"
-                android:layout_width="@dimen/keyguard_security_width"
-                android:layout_height="@dimen/keyguard_password_height"
-                android:layout_centerHorizontal="true"
-                android:layout_marginRight="72dp"
-                android:contentDescription="@string/keyguard_accessibility_sim_pin_area"
-                androidprv:scaledTextSize="@integer/scaled_password_text_size" />
-        </com.android.keyguard.AlphaOptimizedRelativeLayout>
-
-        <include
-            android:id="@+id/keyguard_selector_fade_container"
-            layout="@layout/keyguard_eca"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:layout_gravity="bottom|center_horizontal"
-            android:layout_marginBottom="@dimen/keyguard_eca_bottom_margin"
-            android:layout_marginTop="@dimen/keyguard_eca_top_margin"
-            android:gravity="center_horizontal"
-            android:orientation="vertical"
-            androidprv:layout_constraintBottom_toBottomOf="parent"/>
-
-    </androidx.constraintlayout.widget.ConstraintLayout>
-
-    <androidx.constraintlayout.widget.ConstraintLayout
-        android:id="@+id/sim_puk_container"
-        android:layout_width="0dp"
-        android:layout_height="match_parent"
-        android:layout_weight="3"
-        android:clipChildren="false"
-        android:clipToPadding="false"
-        android:layoutDirection="ltr"
-        android:orientation="vertical">
-
-        <androidx.constraintlayout.helper.widget.Flow
-            android:id="@+id/flow1"
-            android:layout_width="0dp"
-            android:layout_height="0dp"
-            android:clipChildren="false"
-            android:clipToPadding="false"
-            android:orientation="horizontal"
-            androidprv:constraint_referenced_ids="key1,key2,key3,key4,key5,key6,key7,key8,key9,delete_button,key0,key_enter"
-            androidprv:flow_horizontalGap="@dimen/num_pad_key_margin_end"
-            androidprv:flow_horizontalStyle="packed"
-            androidprv:flow_maxElementsWrap="3"
-            androidprv:flow_verticalBias="0.5"
-            androidprv:flow_verticalGap="@dimen/num_pad_entry_row_margin_bottom"
-            androidprv:flow_verticalStyle="packed"
-            androidprv:flow_wrapMode="aligned"
-            androidprv:layout_constraintLeft_toLeftOf="parent"
-            androidprv:layout_constraintRight_toRightOf="parent"
-            androidprv:layout_constraintTop_toTopOf="parent"
-            androidprv:layout_constraintBottom_toBottomOf="parent"/>
-
-        <com.android.keyguard.NumPadButton
-            android:id="@+id/delete_button"
-            style="@style/NumPadKey.Delete"
-            android:layout_width="0dp"
-            android:layout_height="0dp"
-            android:accessibilityTraversalBefore="@id/key0"
-            android:contentDescription="@string/keyboardview_keycode_delete" />
-
-        <com.android.keyguard.NumPadButton
-            android:id="@+id/key_enter"
-            style="@style/NumPadKey.Enter"
-            android:layout_width="0dp"
-            android:layout_height="0dp"
-            android:contentDescription="@string/keyboardview_keycode_enter" />
-
-        <com.android.keyguard.NumPadKey
-            android:id="@+id/key1"
-            android:layout_width="0dp"
-            android:layout_height="0dp"
-            android:accessibilityTraversalBefore="@id/key2"
-            androidprv:digit="1"
-            androidprv:textView="@+id/pukEntry" />
-
-        <com.android.keyguard.NumPadKey
-            android:id="@+id/key2"
-            android:layout_width="0dp"
-            android:layout_height="0dp"
-            android:accessibilityTraversalBefore="@id/key3"
-            androidprv:digit="2"
-            androidprv:textView="@+id/pukEntry" />
-
-        <com.android.keyguard.NumPadKey
-            android:id="@+id/key3"
-            android:layout_width="0dp"
-            android:layout_height="0dp"
-            android:accessibilityTraversalBefore="@id/key4"
-            androidprv:digit="3"
-            androidprv:textView="@+id/pukEntry" />
-
-        <com.android.keyguard.NumPadKey
-            android:id="@+id/key4"
-            android:layout_width="0dp"
-            android:layout_height="0dp"
-            android:accessibilityTraversalBefore="@id/key5"
-            androidprv:digit="4"
-            androidprv:textView="@+id/pukEntry" />
-
-        <com.android.keyguard.NumPadKey
-            android:id="@+id/key5"
-            android:layout_width="0dp"
-            android:layout_height="0dp"
-            android:accessibilityTraversalBefore="@id/key6"
-            androidprv:digit="5"
-            androidprv:textView="@+id/pukEntry" />
-
-
-        <com.android.keyguard.NumPadKey
-            android:id="@+id/key6"
-            android:layout_width="0dp"
-            android:layout_height="0dp"
-            android:accessibilityTraversalBefore="@id/key7"
-            androidprv:digit="6"
-            androidprv:textView="@+id/pukEntry" />
-
-        <com.android.keyguard.NumPadKey
-            android:id="@+id/key7"
-            android:layout_width="0dp"
-            android:layout_height="0dp"
-            android:accessibilityTraversalBefore="@id/key8"
-            androidprv:digit="7"
-            androidprv:textView="@+id/pukEntry" />
-
-        <com.android.keyguard.NumPadKey
-            android:id="@+id/key8"
-            android:layout_width="0dp"
-            android:layout_height="0dp"
-            android:accessibilityTraversalBefore="@id/key9"
-            androidprv:digit="8"
-            androidprv:textView="@+id/pukEntry" />
-
-        <com.android.keyguard.NumPadKey
-            android:id="@+id/key9"
-            android:layout_width="0dp"
-            android:layout_height="0dp"
-            android:accessibilityTraversalBefore="@id/delete_button"
-            androidprv:digit="9"
-            androidprv:textView="@+id/pukEntry" />
-
-        <com.android.keyguard.NumPadKey
-            android:id="@+id/key0"
-            android:layout_width="0dp"
-            android:layout_height="0dp"
-            android:accessibilityTraversalBefore="@id/key_enter"
-            androidprv:digit="0"
-            androidprv:textView="@+id/pukEntry" />
-    </androidx.constraintlayout.widget.ConstraintLayout>
-</com.android.keyguard.KeyguardSimPukView>
diff --git a/packages/SystemUI/res/drawable/contextual_edu_all_apps.xml b/packages/SystemUI/res/drawable/contextual_edu_all_apps.xml
new file mode 100644
index 0000000..263e11c
--- /dev/null
+++ b/packages/SystemUI/res/drawable/contextual_edu_all_apps.xml
@@ -0,0 +1,25 @@
+<!--
+  ~ Copyright 2024 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT 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="32dp"
+    android:height="32dp"
+    android:viewportHeight="32"
+    android:viewportWidth="32">
+    <path
+        android:fillColor="#001E2D"
+        android:pathData="M28.6 30.3l-4.1-4a5.2 5.2 0 0 1-2.7 0.7a5.2 5.2 0 0 1-5.3-5.3a5 5 0 0 1 1.5-3.6q1.6-1.6 3.8-1.6a5 5 0 0 1 3.7 1.6a5 5 0 0 1 1.3 5.1q-0.2 0.9-0.6 1.3l4.1 4l-1.7 1.8zm-21.7-3.3a5 5 0 0 1-3.7-1.5a5 5 0 0 1-1.5-3.7a5 5 0 0 1 1.5-3.7a5 5 0 0 1 3.7-1.6a5 5 0 0 1 3.8 1.6a5 5 0 0 1 1.5 3.7a5 5 0 0 1-1.5 3.7a5 5 0 0 1-3.8 1.5zm14.9-2.3q1 0 2-0.8q0.8-1 0.8-2q0-1.2-0.8-2t-2-0.8q-1.3 0-2 0.8q-0.9 0.8-0.9 2q0 1.1 0.9 2q0.8 0.8 2 0.8zm-14.9-12.5a5 5 0 0 1-3.7-1.5q-1.5-1.5-1.5-3.7a5 5 0 0 1 1.5-3.7a5 5 0 0 1 3.7-1.6a5 5 0 0 1 3.8 1.6a5 5 0 0 1 1.5 3.7q0 2.2-1.5 3.7a5 5 0 0 1-3.8 1.5zm14.9 0a5.2 5.2 0 0 1-5.3-5.3a5 5 0 0 1 1.5-3.6q1.6-1.6 3.8-1.6a5 5 0 0 1 3.7 1.6a5 5 0 0 1 1.5 3.7q0 2.2-1.5 3.7a5 5 0 0 1-3.7 1.5z" />
+</vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/contextual_edu_dialog_bg.xml b/packages/SystemUI/res/drawable/contextual_edu_dialog_bg.xml
new file mode 100644
index 0000000..d7000d7
--- /dev/null
+++ b/packages/SystemUI/res/drawable/contextual_edu_dialog_bg.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+  ~ Copyright 2024 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<!-- Setting insetBottom to avoid bottom elevation of dialog being clipped off -->
+<inset xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+    android:insetBottom="@dimen/contextual_edu_dialog_elevation">
+    <shape>
+        <corners android:radius="28dp" />
+        <solid android:color="?androidprv:attr/materialColorTertiaryFixed" />
+    </shape>
+</inset>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/contextual_edu_swipe_back.xml b/packages/SystemUI/res/drawable/contextual_edu_swipe_back.xml
new file mode 100644
index 0000000..8b0142c
--- /dev/null
+++ b/packages/SystemUI/res/drawable/contextual_edu_swipe_back.xml
@@ -0,0 +1,25 @@
+<!--
+  ~ Copyright 2024 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT 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="28dp"
+    android:height="32dp"
+    android:viewportHeight="32"
+    android:viewportWidth="28">
+  <path
+      android:fillColor="#001E2D"
+      android:pathData="M27.3 9.8h-6.4v-1.8h4a17.4 17.4 0 0 0-5.1-3.1a15.2 15.2 0 0 0-5.8-1.1c-2 0-4 0.4-5.9 1.1a17.6 17.6 0 0 0-5.1 3.1h4v1.8h-6.4v-6.4h1.8l0 2.8a18.6 18.6 0 0 1 11.6-4.2a18.5 18.5 0 0 1 11.6 4.2v-2.8h1.8l0 6.4zm-13.6 20.2c-0.5 0-1-0.1-1.5-0.3s-0.9-0.5-1.3-0.9l-6.8-6.9l0.8-0.9a2.4 2.4 0 0 1 2.5-0.7l2.5 0.7v-11c0-0.3 0.1-0.6 0.3-0.9c0.3-0.3 0.6-0.4 0.9-0.4s0.6 0.1 0.8 0.4c0.2 0.2 0.4 0.5 0.4 0.9v9.4h1.6v-4.3c0-0.3 0.1-0.6 0.3-0.8s0.5-0.4 0.9-0.4s0.6 0.1 0.9 0.4c0.2 0.2 0.4 0.5 0.4 0.8v4.3h1.6v-3c0-0.3 0.1-0.6 0.3-0.8s0.5-0.4 0.9-0.4c0.3 0 0.6 0.1 0.9 0.4c0.3 0.2 0.4 0.5 0.4 0.8v3h1.6v-0.3c0-0.3 0.1-0.6 0.3-0.8s0.5-0.4 0.9-0.4s0.7 0.1 0.9 0.4c0.2 0.2 0.4 0.5 0.4 0.8v5.6c0 1.5-0.5 2.7-1.6 3.8a5.1 5.1 0 0 1-3.8 1.6h-5.6z" />
+</vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/contextual_edu_swipe_up.xml b/packages/SystemUI/res/drawable/contextual_edu_swipe_up.xml
new file mode 100644
index 0000000..294b626
--- /dev/null
+++ b/packages/SystemUI/res/drawable/contextual_edu_swipe_up.xml
@@ -0,0 +1,28 @@
+<!--
+  ~ Copyright 2024 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT 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="32dp"
+    android:height="32dp"
+    android:viewportHeight="32"
+    android:viewportWidth="32">
+    <group>
+        <clip-path android:pathData="M0,0h32v32H0z" />
+        <path
+            android:fillColor="#001E2D"
+            android:pathData="M21.8 27.1a3.5 3.5 0 0 1-3-0.1l-8.8-4.1l0.5-1.2c0.2-0.4 0.5-0.8 0.8-1c0.4-0.3 0.8-0.5 1.3-0.5l2.6-0.2l-3.8-10.4a1.1 1.1 0 0 1 0-0.9c0.2-0.3 0.4-0.5 0.7-0.6s0.6-0.1 0.9 0s0.5 0.4 0.6 0.7l3.2 8.9l1.5-0.6l-1.5-4.1a1.1 1.1 0 0 1 0-0.9c0.2-0.3 0.4-0.5 0.7-0.6s0.6-0.1 0.9 0s0.5 0.4 0.6 0.7l1.5 4.1l1.5-0.6l-1-2.8a1.1 1.1 0 0 1 0-0.9c0.2-0.3 0.4-0.5 0.7-0.6s0.7-0.1 0.9 0c0.3 0.1 0.5 0.4 0.6 0.7l1 2.8l1.6-0.6l-0.1-0.3a1.1 1.1 0 0 1 0-0.9c0.2-0.3 0.4-0.5 0.7-0.7c0.3-0.1 0.6-0.1 0.9 0.1c0.3 0.1 0.5 0.4 0.6 0.7l1.9 5.2c0.5 1.4 0.5 2.8-0.2 4.1a5.1 5.1 0 0 1-3 2.7l-5.3 1.9zm-13.8-9.4a15.5 15.5 0 0 1-3.4-9.8a17.8 17.8 0 0 1 0.4-3.8l-2.4 2.4l-1.3-1.2l4.5-4.5l4.5 4.5l-1.2 1.2l-2.3-2.3c-0.2 0.6-0.3 1.2-0.4 1.8a14.1 14.1 0 0 0 0.6 6.4a13.5 13.5 0 0 0 2.2 4l-1.3 1.3z" />
+    </group>
+</vector>
diff --git a/packages/SystemUI/res/drawable/volume_dialog_background.xml b/packages/SystemUI/res/drawable/volume_dialog_background.xml
new file mode 100644
index 0000000..7d7498f
--- /dev/null
+++ b/packages/SystemUI/res/drawable/volume_dialog_background.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+    Copyright (C) 2024 The Android Open Source Project
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+    android:shape="rectangle">
+    <corners android:radius="@dimen/volume_dialog_background_corner_radius" />
+    <solid android:color="?androidprv:attr/materialColorSurface" />
+</shape>
diff --git a/packages/SystemUI/res/drawable/volume_dialog_floating_slider_background.xml b/packages/SystemUI/res/drawable/volume_dialog_floating_slider_background.xml
new file mode 100644
index 0000000..2694435
--- /dev/null
+++ b/packages/SystemUI/res/drawable/volume_dialog_floating_slider_background.xml
@@ -0,0 +1,21 @@
+<!--
+  ~ Copyright (C) 2024 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+    android:shape="rectangle">
+    <corners android:radius="20dp" />
+    <solid android:color="?androidprv:attr/colorSurface" />
+</shape>
diff --git a/packages/SystemUI/res/drawable/volume_dialog_floating_sliders_spacer.xml b/packages/SystemUI/res/drawable/volume_dialog_floating_sliders_spacer.xml
new file mode 100644
index 0000000..66a205a
--- /dev/null
+++ b/packages/SystemUI/res/drawable/volume_dialog_floating_sliders_spacer.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+    Copyright (C) 2024 The Android Open Source Project
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="rectangle">
+    <size
+        android:width="@dimen/volume_dialog_floating_sliders_spacing"
+        android:height="@dimen/volume_dialog_floating_sliders_spacing" />
+    <solid android:color="@color/transparent" />
+</shape>
diff --git a/packages/SystemUI/res/drawable/volume_dialog_spacer.xml b/packages/SystemUI/res/drawable/volume_dialog_spacer.xml
new file mode 100644
index 0000000..3c60784
--- /dev/null
+++ b/packages/SystemUI/res/drawable/volume_dialog_spacer.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+    Copyright (C) 2024 The Android Open Source Project
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="rectangle">
+    <size
+        android:width="@dimen/volume_dialog_spacing"
+        android:height="@dimen/volume_dialog_spacing" />
+    <solid android:color="@color/transparent" />
+</shape>
diff --git a/packages/SystemUI/res/drawable/volume_row_seekbar_progress.xml b/packages/SystemUI/res/drawable/volume_row_seekbar_progress.xml
index 21b177b..fa06bd6 100644
--- a/packages/SystemUI/res/drawable/volume_row_seekbar_progress.xml
+++ b/packages/SystemUI/res/drawable/volume_row_seekbar_progress.xml
@@ -22,7 +22,7 @@
     android:autoMirrored="true">
     <item android:id="@+id/volume_seekbar_progress_solid">
         <shape>
-            <size android:height="@dimen/volume_dialog_slider_width" />
+            <size android:height="@dimen/volume_dialog_slider_width_legacy" />
             <solid android:color="?android:attr/colorAccent" />
             <corners android:radius="@dimen/volume_dialog_slider_corner_radius"/>
         </shape>
diff --git a/packages/SystemUI/res/layout-land-television/volume_dialog.xml b/packages/SystemUI/res/layout-land-television/volume_dialog.xml
index 0fbc519..f77db95 100644
--- a/packages/SystemUI/res/layout-land-television/volume_dialog.xml
+++ b/packages/SystemUI/res/layout-land-television/volume_dialog.xml
@@ -1,92 +1,67 @@
 <!--
-  ~ 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
-  -->
-<FrameLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:sysui="http://schemas.android.com/apk/res-auto"
+     Copyright (C) 2024 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
     android:id="@+id/volume_dialog_container"
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
-    android:background="@android:color/transparent"
+    android:layout_gravity="right"
+    android:divider="@drawable/volume_dialog_floating_sliders_spacer"
+    android:orientation="horizontal"
+    android:showDividers="middle|end|beginning"
     android:theme="@style/volume_dialog_theme">
 
-    <FrameLayout
-        android:id="@+id/volume_dialog"
+    <LinearLayout
+        android:id="@+id/volume_dialog_floating_sliders_container"
         android:layout_width="wrap_content"
+        android:layout_height="match_parent"
+        android:background="@drawable/volume_dialog_background"
+        android:divider="@drawable/volume_dialog_floating_sliders_spacer"
+        android:gravity="bottom"
+        android:orientation="horizontal"
+        android:paddingBottom="@dimen/volume_dialog_floating_sliders_bottom_padding"
+        android:showDividers="middle" />
+
+    <LinearLayout
+        android:layout_width="@dimen/volume_dialog_width"
         android:layout_height="wrap_content"
-        android:layout_gravity="right"
-        android:background="@android:color/transparent"
-        android:padding="@dimen/volume_dialog_panel_transparent_padding"
-        android:clipToPadding="false">
-
-        <LinearLayout
-            android:id="@+id/volume_dialog_rows_container"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_gravity="right"
-            android:orientation="vertical"
-            android:translationZ="@dimen/volume_dialog_elevation"
-            android:clipChildren="false"
-            android:clipToPadding="false"
-            android:background="@android:color/transparent">
-
-            <LinearLayout
-                android:id="@+id/volume_dialog_rows"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:gravity="center"
-                android:orientation="horizontal"
-                android:background="@drawable/tv_volume_dialog_background">
-                <!-- volume rows added and removed here! :-) -->
-            </LinearLayout>
-
-        </LinearLayout>
+        android:background="@drawable/volume_dialog_background"
+        android:divider="@drawable/volume_dialog_spacer"
+        android:gravity="center_horizontal"
+        android:orientation="vertical"
+        android:paddingVertical="@dimen/volume_dialog_vertical_padding"
+        android:showDividers="middle">
 
         <FrameLayout
-            android:id="@+id/odi_captions"
-            android:layout_width="@dimen/volume_dialog_caption_size"
-            android:layout_height="@dimen/volume_dialog_caption_size"
-            android:layout_marginRight="68dp"
-            android:layout_gravity="right"
-            android:clipToPadding="false"
-            android:translationZ="@dimen/volume_dialog_elevation"
-            android:background="@drawable/rounded_bg_full">
+            android:id="@+id/volume_dialog_ringer_button"
+            android:layout_width="@dimen/volume_dialog_button_size"
+            android:layout_height="@dimen/volume_dialog_button_size" />
 
-            <com.android.systemui.volume.CaptionsToggleImageButton
-                android:id="@+id/odi_captions_icon"
-                android:src="@drawable/ic_volume_odi_captions_disabled"
-                style="@style/VolumeButtons"
-                android:background="@drawable/rounded_ripple"
-                android:layout_width="match_parent"
-                android:layout_height="match_parent"
-                android:tint="@color/caption_tint_color_selector"
-                android:layout_gravity="center"
-                android:soundEffectsEnabled="false"/>
+        <include
+            android:id="@+id/volume_dialog_slider"
+            layout="@layout/volume_dialog_slider" />
 
-        </FrameLayout>
-
-        <ViewStub
-            android:id="@+id/odi_captions_tooltip_stub"
-            android:inflatedId="@+id/odi_captions_tooltip_view"
-            android:layout="@layout/volume_tool_tip_view"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_marginRight="@dimen/volume_tool_tip_right_margin"
-            android:layout_marginTop="@dimen/volume_tool_tip_top_margin"
-            android:layout_gravity="right"/>
-
-    </FrameLayout>
-
-</FrameLayout>
+        <Button
+            android:id="@+id/volume_dialog_settings"
+            android:layout_width="@dimen/volume_dialog_button_size"
+            android:layout_height="@dimen/volume_dialog_button_size"
+            android:background="@drawable/ripple_drawable_20dp"
+            android:contentDescription="@string/accessibility_volume_settings"
+            android:soundEffectsEnabled="false"
+            android:src="@drawable/horizontal_ellipsis"
+            android:tint="?androidprv:attr/materialColorPrimary" />
+    </LinearLayout>
+</LinearLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout-land-television/volume_dialog_legacy.xml b/packages/SystemUI/res/layout-land-television/volume_dialog_legacy.xml
new file mode 100644
index 0000000..0fbc519
--- /dev/null
+++ b/packages/SystemUI/res/layout-land-television/volume_dialog_legacy.xml
@@ -0,0 +1,92 @@
+<!--
+  ~ 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
+  -->
+<FrameLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:sysui="http://schemas.android.com/apk/res-auto"
+    android:id="@+id/volume_dialog_container"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:background="@android:color/transparent"
+    android:theme="@style/volume_dialog_theme">
+
+    <FrameLayout
+        android:id="@+id/volume_dialog"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="right"
+        android:background="@android:color/transparent"
+        android:padding="@dimen/volume_dialog_panel_transparent_padding"
+        android:clipToPadding="false">
+
+        <LinearLayout
+            android:id="@+id/volume_dialog_rows_container"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="right"
+            android:orientation="vertical"
+            android:translationZ="@dimen/volume_dialog_elevation"
+            android:clipChildren="false"
+            android:clipToPadding="false"
+            android:background="@android:color/transparent">
+
+            <LinearLayout
+                android:id="@+id/volume_dialog_rows"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:gravity="center"
+                android:orientation="horizontal"
+                android:background="@drawable/tv_volume_dialog_background">
+                <!-- volume rows added and removed here! :-) -->
+            </LinearLayout>
+
+        </LinearLayout>
+
+        <FrameLayout
+            android:id="@+id/odi_captions"
+            android:layout_width="@dimen/volume_dialog_caption_size"
+            android:layout_height="@dimen/volume_dialog_caption_size"
+            android:layout_marginRight="68dp"
+            android:layout_gravity="right"
+            android:clipToPadding="false"
+            android:translationZ="@dimen/volume_dialog_elevation"
+            android:background="@drawable/rounded_bg_full">
+
+            <com.android.systemui.volume.CaptionsToggleImageButton
+                android:id="@+id/odi_captions_icon"
+                android:src="@drawable/ic_volume_odi_captions_disabled"
+                style="@style/VolumeButtons"
+                android:background="@drawable/rounded_ripple"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"
+                android:tint="@color/caption_tint_color_selector"
+                android:layout_gravity="center"
+                android:soundEffectsEnabled="false"/>
+
+        </FrameLayout>
+
+        <ViewStub
+            android:id="@+id/odi_captions_tooltip_stub"
+            android:inflatedId="@+id/odi_captions_tooltip_view"
+            android:layout="@layout/volume_tool_tip_view"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginRight="@dimen/volume_tool_tip_right_margin"
+            android:layout_marginTop="@dimen/volume_tool_tip_top_margin"
+            android:layout_gravity="right"/>
+
+    </FrameLayout>
+
+</FrameLayout>
diff --git a/packages/SystemUI/res/layout-land-television/volume_dialog_row.xml b/packages/SystemUI/res/layout-land-television/volume_dialog_row.xml
index cf301c9..eb89489 100644
--- a/packages/SystemUI/res/layout-land-television/volume_dialog_row.xml
+++ b/packages/SystemUI/res/layout-land-television/volume_dialog_row.xml
@@ -63,8 +63,8 @@
                 android:layout_height="match_parent"
                 android:layout_gravity="center"
                 android:layoutDirection="ltr"
-                android:maxHeight="@dimen/volume_dialog_slider_width"
-                android:minHeight="@dimen/volume_dialog_slider_width"
+                android:maxHeight="@dimen/volume_dialog_slider_width_legacy"
+                android:minHeight="@dimen/volume_dialog_slider_width_legacy"
                 android:progressDrawable="@drawable/volume_row_seekbar"
                 android:thumb="@drawable/tv_volume_row_seek_thumb"
                 android:splitTrack="false"
diff --git a/packages/SystemUI/res/layout-land/volume_dialog.xml b/packages/SystemUI/res/layout-land/volume_dialog.xml
index 08edf59..f77db95 100644
--- a/packages/SystemUI/res/layout-land/volume_dialog.xml
+++ b/packages/SystemUI/res/layout-land/volume_dialog.xml
@@ -1,146 +1,67 @@
 <!--
-  ~ 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
-  -->
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+     Copyright (C) 2024 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
     android:id="@+id/volume_dialog_container"
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
-    android:gravity="right"
     android:layout_gravity="right"
-    android:background="@android:color/transparent"
+    android:divider="@drawable/volume_dialog_floating_sliders_spacer"
+    android:orientation="horizontal"
+    android:showDividers="middle|end|beginning"
     android:theme="@style/volume_dialog_theme">
 
-    <!-- right-aligned to be physically near volume button -->
     <LinearLayout
-        android:id="@+id/volume_dialog"
+        android:id="@+id/volume_dialog_floating_sliders_container"
         android:layout_width="wrap_content"
+        android:layout_height="match_parent"
+        android:background="@drawable/volume_dialog_background"
+        android:divider="@drawable/volume_dialog_floating_sliders_spacer"
+        android:gravity="bottom"
+        android:orientation="horizontal"
+        android:paddingBottom="@dimen/volume_dialog_floating_sliders_bottom_padding"
+        android:showDividers="middle" />
+
+    <LinearLayout
+        android:layout_width="@dimen/volume_dialog_width"
         android:layout_height="wrap_content"
-        android:gravity="right"
-        android:layout_gravity="right"
-        android:layout_marginRight="@dimen/volume_dialog_panel_transparent_padding_right"
+        android:background="@drawable/volume_dialog_background"
+        android:divider="@drawable/volume_dialog_spacer"
+        android:gravity="center_horizontal"
         android:orientation="vertical"
-        android:clipToPadding="false"
-        android:clipChildren="false">
-
-
-        <LinearLayout
-            android:id="@+id/volume_dialog_top_container"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:orientation="vertical"
-            android:clipChildren="false"
-            android:gravity="right">
-
-            <include layout="@layout/volume_ringer_drawer" />
-
-            <FrameLayout
-                android:visibility="gone"
-                android:id="@+id/ringer"
-                android:layout_width="@dimen/volume_dialog_ringer_size"
-                android:layout_height="@dimen/volume_dialog_ringer_size"
-                android:layout_marginBottom="@dimen/volume_dialog_spacer"
-                android:gravity="right"
-                android:layout_gravity="right"
-                android:translationZ="@dimen/volume_dialog_elevation"
-                android:clipToPadding="false"
-                android:background="@drawable/rounded_bg_full">
-                <com.android.keyguard.AlphaOptimizedImageButton
-                    android:id="@+id/ringer_icon"
-                    style="@style/VolumeButtons"
-                    android:background="@drawable/rounded_ripple"
-                    android:layout_width="match_parent"
-                    android:layout_height="match_parent"
-                    android:scaleType="fitCenter"
-                    android:padding="@dimen/volume_dialog_ringer_icon_padding"
-                    android:tint="?android:attr/textColorPrimary"
-                    android:layout_gravity="center"
-                    android:soundEffectsEnabled="false" />
-            </FrameLayout>
-
-            <LinearLayout
-                android:id="@+id/volume_dialog_rows_container"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:gravity="right"
-                android:layout_gravity="right"
-                android:orientation="vertical"
-                android:clipChildren="false"
-                android:clipToPadding="false" >
-                <LinearLayout
-                    android:id="@+id/volume_dialog_rows"
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content"
-                    android:gravity="center"
-                    android:orientation="horizontal">
-                    <!-- volume rows added and removed here! :-) -->
-                </LinearLayout>
-                <FrameLayout
-                    android:id="@+id/settings_container"
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content"
-                    android:background="@drawable/volume_background_bottom"
-                    android:paddingLeft="@dimen/volume_dialog_ringer_rows_padding"
-                    android:paddingBottom="@dimen/volume_dialog_ringer_rows_padding"
-                    android:paddingRight="@dimen/volume_dialog_ringer_rows_padding">
-
-                    <com.android.keyguard.AlphaOptimizedImageButton
-                        android:id="@+id/settings"
-                        android:layout_width="@dimen/volume_dialog_tap_target_size"
-                        android:layout_height="@dimen/volume_dialog_tap_target_size"
-                        android:layout_gravity="center"
-                        android:background="@drawable/ripple_drawable_20dp"
-                        android:contentDescription="@string/accessibility_volume_settings"
-                        android:scaleType="centerInside"
-                        android:soundEffectsEnabled="false"
-                        android:src="@drawable/horizontal_ellipsis"
-                        android:tint="?androidprv:attr/colorAccent" />
-                </FrameLayout>
-            </LinearLayout>
-
-        </LinearLayout>
+        android:paddingVertical="@dimen/volume_dialog_vertical_padding"
+        android:showDividers="middle">
 
         <FrameLayout
-            android:id="@+id/odi_captions"
-            android:layout_width="@dimen/volume_dialog_caption_size"
-            android:layout_height="@dimen/volume_dialog_caption_size"
-            android:layout_marginTop="@dimen/volume_dialog_row_margin_bottom"
-            android:gravity="right"
-            android:layout_gravity="right"
-            android:clipToPadding="false"
-            android:clipToOutline="true"
-            android:background="@drawable/volume_row_rounded_background">
-            <com.android.systemui.volume.CaptionsToggleImageButton
-                android:id="@+id/odi_captions_icon"
-                android:src="@drawable/ic_volume_odi_captions_disabled"
-                style="@style/VolumeButtons"
-                android:layout_width="match_parent"
-                android:layout_height="match_parent"
-                android:tint="?android:attr/colorAccent"
-                android:layout_gravity="center"
-                android:soundEffectsEnabled="false" />
-        </FrameLayout>
+            android:id="@+id/volume_dialog_ringer_button"
+            android:layout_width="@dimen/volume_dialog_button_size"
+            android:layout_height="@dimen/volume_dialog_button_size" />
+
+        <include
+            android:id="@+id/volume_dialog_slider"
+            layout="@layout/volume_dialog_slider" />
+
+        <Button
+            android:id="@+id/volume_dialog_settings"
+            android:layout_width="@dimen/volume_dialog_button_size"
+            android:layout_height="@dimen/volume_dialog_button_size"
+            android:background="@drawable/ripple_drawable_20dp"
+            android:contentDescription="@string/accessibility_volume_settings"
+            android:soundEffectsEnabled="false"
+            android:src="@drawable/horizontal_ellipsis"
+            android:tint="?androidprv:attr/materialColorPrimary" />
     </LinearLayout>
-
-    <ViewStub
-        android:id="@+id/odi_captions_tooltip_stub"
-        android:inflatedId="@+id/odi_captions_tooltip_view"
-        android:layout="@layout/volume_tool_tip_view"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_gravity="bottom | right"
-        android:layout_marginRight="@dimen/volume_tool_tip_right_margin"/>
-
-</FrameLayout>
\ No newline at end of file
+</LinearLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout-land/volume_dialog_legacy.xml b/packages/SystemUI/res/layout-land/volume_dialog_legacy.xml
new file mode 100644
index 0000000..08edf59
--- /dev/null
+++ b/packages/SystemUI/res/layout-land/volume_dialog_legacy.xml
@@ -0,0 +1,146 @@
+<!--
+  ~ 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
+  -->
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+    android:id="@+id/volume_dialog_container"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:gravity="right"
+    android:layout_gravity="right"
+    android:background="@android:color/transparent"
+    android:theme="@style/volume_dialog_theme">
+
+    <!-- right-aligned to be physically near volume button -->
+    <LinearLayout
+        android:id="@+id/volume_dialog"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:gravity="right"
+        android:layout_gravity="right"
+        android:layout_marginRight="@dimen/volume_dialog_panel_transparent_padding_right"
+        android:orientation="vertical"
+        android:clipToPadding="false"
+        android:clipChildren="false">
+
+
+        <LinearLayout
+            android:id="@+id/volume_dialog_top_container"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:orientation="vertical"
+            android:clipChildren="false"
+            android:gravity="right">
+
+            <include layout="@layout/volume_ringer_drawer" />
+
+            <FrameLayout
+                android:visibility="gone"
+                android:id="@+id/ringer"
+                android:layout_width="@dimen/volume_dialog_ringer_size"
+                android:layout_height="@dimen/volume_dialog_ringer_size"
+                android:layout_marginBottom="@dimen/volume_dialog_spacer"
+                android:gravity="right"
+                android:layout_gravity="right"
+                android:translationZ="@dimen/volume_dialog_elevation"
+                android:clipToPadding="false"
+                android:background="@drawable/rounded_bg_full">
+                <com.android.keyguard.AlphaOptimizedImageButton
+                    android:id="@+id/ringer_icon"
+                    style="@style/VolumeButtons"
+                    android:background="@drawable/rounded_ripple"
+                    android:layout_width="match_parent"
+                    android:layout_height="match_parent"
+                    android:scaleType="fitCenter"
+                    android:padding="@dimen/volume_dialog_ringer_icon_padding"
+                    android:tint="?android:attr/textColorPrimary"
+                    android:layout_gravity="center"
+                    android:soundEffectsEnabled="false" />
+            </FrameLayout>
+
+            <LinearLayout
+                android:id="@+id/volume_dialog_rows_container"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:gravity="right"
+                android:layout_gravity="right"
+                android:orientation="vertical"
+                android:clipChildren="false"
+                android:clipToPadding="false" >
+                <LinearLayout
+                    android:id="@+id/volume_dialog_rows"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:gravity="center"
+                    android:orientation="horizontal">
+                    <!-- volume rows added and removed here! :-) -->
+                </LinearLayout>
+                <FrameLayout
+                    android:id="@+id/settings_container"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:background="@drawable/volume_background_bottom"
+                    android:paddingLeft="@dimen/volume_dialog_ringer_rows_padding"
+                    android:paddingBottom="@dimen/volume_dialog_ringer_rows_padding"
+                    android:paddingRight="@dimen/volume_dialog_ringer_rows_padding">
+
+                    <com.android.keyguard.AlphaOptimizedImageButton
+                        android:id="@+id/settings"
+                        android:layout_width="@dimen/volume_dialog_tap_target_size"
+                        android:layout_height="@dimen/volume_dialog_tap_target_size"
+                        android:layout_gravity="center"
+                        android:background="@drawable/ripple_drawable_20dp"
+                        android:contentDescription="@string/accessibility_volume_settings"
+                        android:scaleType="centerInside"
+                        android:soundEffectsEnabled="false"
+                        android:src="@drawable/horizontal_ellipsis"
+                        android:tint="?androidprv:attr/colorAccent" />
+                </FrameLayout>
+            </LinearLayout>
+
+        </LinearLayout>
+
+        <FrameLayout
+            android:id="@+id/odi_captions"
+            android:layout_width="@dimen/volume_dialog_caption_size"
+            android:layout_height="@dimen/volume_dialog_caption_size"
+            android:layout_marginTop="@dimen/volume_dialog_row_margin_bottom"
+            android:gravity="right"
+            android:layout_gravity="right"
+            android:clipToPadding="false"
+            android:clipToOutline="true"
+            android:background="@drawable/volume_row_rounded_background">
+            <com.android.systemui.volume.CaptionsToggleImageButton
+                android:id="@+id/odi_captions_icon"
+                android:src="@drawable/ic_volume_odi_captions_disabled"
+                style="@style/VolumeButtons"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"
+                android:tint="?android:attr/colorAccent"
+                android:layout_gravity="center"
+                android:soundEffectsEnabled="false" />
+        </FrameLayout>
+    </LinearLayout>
+
+    <ViewStub
+        android:id="@+id/odi_captions_tooltip_stub"
+        android:inflatedId="@+id/odi_captions_tooltip_view"
+        android:layout="@layout/volume_tool_tip_view"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="bottom | right"
+        android:layout_marginRight="@dimen/volume_tool_tip_right_margin"/>
+
+</FrameLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/audio_sharing_dialog.xml b/packages/SystemUI/res/layout/audio_sharing_dialog.xml
new file mode 100644
index 0000000..7534e15
--- /dev/null
+++ b/packages/SystemUI/res/layout/audio_sharing_dialog.xml
@@ -0,0 +1,115 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+  ~ Copyright (C) 2024 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<androidx.constraintlayout.widget.ConstraintLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:id="@+id/root"
+    style="@style/Widget.SliceView.Panel"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content">
+
+    <ImageView android:id="@+id/icon"
+        android:layout_width="28dp"
+        android:layout_height="28dp"
+        android:src="@drawable/ic_bt_le_audio_sharing"
+        android:layout_marginTop="5dp"
+        android:layout_marginBottom="20dp"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintBottom_toTopOf="@id/title"
+        app:layout_constraintTop_toTopOf="parent" />
+
+    <TextView
+        android:id="@+id/title"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginBottom="20dp"
+        android:gravity="center_vertical|center_horizontal"
+        android:maxLines="1"
+        android:ellipsize="end"
+        android:text="@string/quick_settings_bluetooth_audio_sharing_dialog_title"
+        android:textAppearance="@style/TextAppearance.Dialog.Title"
+        android:textSize="24sp"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintBottom_toTopOf="@id/subtitle"
+        app:layout_constraintTop_toBottomOf="@id/icon" />
+
+    <TextView
+        android:id="@+id/subtitle"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginBottom="20dp"
+        android:gravity="center_vertical|center_horizontal"
+        android:ellipsize="end"
+        android:maxLines="2"
+        android:textAppearance="@style/TextAppearance.Dialog.Body.Message"
+        android:textFontWeight="500"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintBottom_toTopOf="@id/message"
+        app:layout_constraintTop_toBottomOf="@id/title" />
+
+    <TextView
+        android:id="@+id/message"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginBottom="20dp"
+        android:gravity="center_vertical|center_horizontal"
+        android:ellipsize="end"
+        android:maxLines="2"
+        android:text="@string/quick_settings_bluetooth_audio_sharing_dialog_message"
+        android:textAppearance="@style/TextAppearance.Dialog.Body.Message"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintBottom_toTopOf="@id/share_audio_button"
+        app:layout_constraintTop_toBottomOf="@id/subtitle" />
+
+    <Button
+        android:id="@+id/share_audio_button"
+        style="@style/SettingsLibActionButton"
+        android:textColor="?androidprv:attr/textColorOnAccent"
+        android:background="@drawable/audio_sharing_rounded_bg_ripple"
+        android:layout_marginBottom="4dp"
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:minHeight="64dp"
+        android:contentDescription="@string/accessibility_bluetooth_device_settings_see_all"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintTop_toBottomOf="@+id/message"
+        app:layout_constraintBottom_toTopOf="@+id/switch_active_button"
+        android:text="@string/quick_settings_bluetooth_audio_sharing_button"
+        android:maxLines="2" />
+
+    <Button
+        android:id="@+id/switch_active_button"
+        style="@style/SettingsLibActionButton"
+        android:textColor="?androidprv:attr/textColorOnAccent"
+        android:background="@drawable/audio_sharing_rounded_bg_ripple"
+        android:layout_marginBottom="20dp"
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:minHeight="64dp"
+        android:contentDescription="@string/accessibility_bluetooth_device_settings_pair_new_device"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintTop_toBottomOf="@+id/share_audio_button"
+        app:layout_constraintBottom_toBottomOf="parent"
+        android:maxLines="2" />
+</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/contextual_edu_dialog.xml b/packages/SystemUI/res/layout/contextual_edu_dialog.xml
new file mode 100644
index 0000000..ee42b23
--- /dev/null
+++ b/packages/SystemUI/res/layout/contextual_edu_dialog.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+  ~ Copyright 2024 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:background="@drawable/contextual_edu_dialog_bg"
+    android:elevation="@dimen/contextual_edu_dialog_elevation"
+    android:gravity="center_vertical"
+    android:orientation="horizontal"
+    android:padding="12dp">
+
+    <ImageView
+        android:id="@+id/edu_icon"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:contentDescription="@null"
+        android:importantForAccessibility="no"
+        android:paddingRight="16dp" />
+
+    <TextView
+        android:id="@+id/edu_message"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:background="@color/transparent"
+        android:ellipsize="end"
+        android:fontFamily="google-sans-medium"
+        android:maxWidth="280dp"
+        android:textColor="?androidprv:attr/materialColorOnTertiaryFixed"
+        android:textSize="14sp"
+        android:textStyle="bold" />
+</LinearLayout>
diff --git a/packages/SystemUI/res/layout/volume_dialog.xml b/packages/SystemUI/res/layout/volume_dialog.xml
index 39a1f1f..f77db95 100644
--- a/packages/SystemUI/res/layout/volume_dialog.xml
+++ b/packages/SystemUI/res/layout/volume_dialog.xml
@@ -1,5 +1,5 @@
 <!--
-     Copyright (C) 2015 The Android Open Source Project
+     Copyright (C) 2024 The Android Open Source Project
 
      Licensed under the Apache License, Version 2.0 (the "License");
      you may not use this file except in compliance with the License.
@@ -13,133 +13,55 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<FrameLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:sysui="http://schemas.android.com/apk/res-auto"
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
     android:id="@+id/volume_dialog_container"
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
-    android:gravity="right"
     android:layout_gravity="right"
-    android:clipToPadding="false"
+    android:divider="@drawable/volume_dialog_floating_sliders_spacer"
+    android:orientation="horizontal"
+    android:showDividers="middle|end|beginning"
     android:theme="@style/volume_dialog_theme">
 
-    <!-- right-aligned to be physically near volume button -->
     <LinearLayout
-        android:id="@+id/volume_dialog"
+        android:id="@+id/volume_dialog_floating_sliders_container"
         android:layout_width="wrap_content"
+        android:layout_height="match_parent"
+        android:background="@drawable/volume_dialog_background"
+        android:divider="@drawable/volume_dialog_floating_sliders_spacer"
+        android:gravity="bottom"
+        android:orientation="horizontal"
+        android:paddingBottom="@dimen/volume_dialog_floating_sliders_bottom_padding"
+        android:showDividers="middle" />
+
+    <LinearLayout
+        android:layout_width="@dimen/volume_dialog_width"
         android:layout_height="wrap_content"
-        android:gravity="right"
-        android:layout_gravity="right"
-        android:layout_marginRight="@dimen/volume_dialog_panel_transparent_padding_right"
+        android:background="@drawable/volume_dialog_background"
+        android:divider="@drawable/volume_dialog_spacer"
+        android:gravity="center_horizontal"
         android:orientation="vertical"
-        android:clipToPadding="false"
-        android:clipChildren="false">
-
-        <LinearLayout
-            android:id="@+id/volume_dialog_top_container"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:clipChildren="false"
-            android:orientation="vertical"
-            android:gravity="right">
-
-            <include layout="@layout/volume_ringer_drawer" />
-
-            <FrameLayout
-                android:visibility="gone"
-                android:id="@+id/ringer"
-                android:layout_width="@dimen/volume_dialog_ringer_size"
-                android:layout_height="@dimen/volume_dialog_ringer_size"
-                android:layout_marginBottom="@dimen/volume_dialog_spacer"
-                android:gravity="right"
-                android:layout_gravity="right"
-                android:translationZ="@dimen/volume_dialog_elevation"
-                android:clipToPadding="false"
-                android:background="@drawable/rounded_bg_full">
-                <com.android.keyguard.AlphaOptimizedImageButton
-                    android:id="@+id/ringer_icon"
-                    style="@style/VolumeButtons"
-                    android:background="@drawable/rounded_ripple"
-                    android:layout_width="match_parent"
-                    android:layout_height="match_parent"
-                    android:scaleType="fitCenter"
-                    android:padding="@dimen/volume_dialog_ringer_icon_padding"
-                    android:tint="?android:attr/textColorPrimary"
-                    android:layout_gravity="center"
-                    android:soundEffectsEnabled="false" />
-            </FrameLayout>
-
-            <LinearLayout
-                android:id="@+id/volume_dialog_rows_container"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:gravity="right"
-                android:layout_gravity="right"
-                android:orientation="vertical"
-                android:clipChildren="false"
-                android:clipToPadding="false" >
-                <LinearLayout
-                    android:id="@+id/volume_dialog_rows"
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content"
-                    android:gravity="center"
-                    android:orientation="horizontal">
-                        <!-- volume rows added and removed here! :-) -->
-                </LinearLayout>
-                <FrameLayout
-                    android:id="@+id/settings_container"
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content"
-                    android:background="@drawable/volume_background_bottom"
-                    android:paddingLeft="@dimen/volume_dialog_ringer_rows_padding"
-                    android:paddingBottom="@dimen/volume_dialog_ringer_rows_padding"
-                    android:paddingRight="@dimen/volume_dialog_ringer_rows_padding">
-                    <com.android.keyguard.AlphaOptimizedImageButton
-                        android:id="@+id/settings"
-                        android:src="@drawable/horizontal_ellipsis"
-                        android:layout_width="@dimen/volume_dialog_tap_target_size"
-                        android:layout_height="@dimen/volume_dialog_tap_target_size"
-                        android:layout_gravity="center"
-                        android:contentDescription="@string/accessibility_volume_settings"
-                        android:background="@drawable/ripple_drawable_20dp"
-                        android:tint="?androidprv:attr/colorAccent"
-                        android:soundEffectsEnabled="false" />
-                </FrameLayout>
-            </LinearLayout>
-
-        </LinearLayout>
+        android:paddingVertical="@dimen/volume_dialog_vertical_padding"
+        android:showDividers="middle">
 
         <FrameLayout
-            android:id="@+id/odi_captions"
-            android:layout_width="@dimen/volume_dialog_caption_size"
-            android:layout_height="@dimen/volume_dialog_caption_size"
-            android:layout_marginTop="@dimen/volume_dialog_row_margin_bottom"
-            android:gravity="right"
-            android:layout_gravity="right"
-            android:clipToPadding="false"
-            android:clipToOutline="true"
-            android:background="@drawable/volume_row_rounded_background">
-            <com.android.systemui.volume.CaptionsToggleImageButton
-                android:id="@+id/odi_captions_icon"
-                android:src="@drawable/ic_volume_odi_captions_disabled"
-                style="@style/VolumeButtons"
-                android:layout_width="match_parent"
-                android:layout_height="match_parent"
-                android:tint="?android:attr/colorAccent"
-                android:layout_gravity="center"
-                android:soundEffectsEnabled="false"/>
-        </FrameLayout>
+            android:id="@+id/volume_dialog_ringer_button"
+            android:layout_width="@dimen/volume_dialog_button_size"
+            android:layout_height="@dimen/volume_dialog_button_size" />
+
+        <include
+            android:id="@+id/volume_dialog_slider"
+            layout="@layout/volume_dialog_slider" />
+
+        <Button
+            android:id="@+id/volume_dialog_settings"
+            android:layout_width="@dimen/volume_dialog_button_size"
+            android:layout_height="@dimen/volume_dialog_button_size"
+            android:background="@drawable/ripple_drawable_20dp"
+            android:contentDescription="@string/accessibility_volume_settings"
+            android:soundEffectsEnabled="false"
+            android:src="@drawable/horizontal_ellipsis"
+            android:tint="?androidprv:attr/materialColorPrimary" />
     </LinearLayout>
-
-    <ViewStub
-        android:id="@+id/odi_captions_tooltip_stub"
-        android:inflatedId="@+id/odi_captions_tooltip_view"
-        android:layout="@layout/volume_tool_tip_view"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_gravity="bottom | right"
-        android:layout_marginRight="@dimen/volume_tool_tip_right_margin"/>
-
-</FrameLayout>
\ No newline at end of file
+</LinearLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/volume_dialog_legacy.xml b/packages/SystemUI/res/layout/volume_dialog_legacy.xml
new file mode 100644
index 0000000..39a1f1f
--- /dev/null
+++ b/packages/SystemUI/res/layout/volume_dialog_legacy.xml
@@ -0,0 +1,145 @@
+<!--
+     Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<FrameLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:sysui="http://schemas.android.com/apk/res-auto"
+    xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+    android:id="@+id/volume_dialog_container"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:gravity="right"
+    android:layout_gravity="right"
+    android:clipToPadding="false"
+    android:theme="@style/volume_dialog_theme">
+
+    <!-- right-aligned to be physically near volume button -->
+    <LinearLayout
+        android:id="@+id/volume_dialog"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:gravity="right"
+        android:layout_gravity="right"
+        android:layout_marginRight="@dimen/volume_dialog_panel_transparent_padding_right"
+        android:orientation="vertical"
+        android:clipToPadding="false"
+        android:clipChildren="false">
+
+        <LinearLayout
+            android:id="@+id/volume_dialog_top_container"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:clipChildren="false"
+            android:orientation="vertical"
+            android:gravity="right">
+
+            <include layout="@layout/volume_ringer_drawer" />
+
+            <FrameLayout
+                android:visibility="gone"
+                android:id="@+id/ringer"
+                android:layout_width="@dimen/volume_dialog_ringer_size"
+                android:layout_height="@dimen/volume_dialog_ringer_size"
+                android:layout_marginBottom="@dimen/volume_dialog_spacer"
+                android:gravity="right"
+                android:layout_gravity="right"
+                android:translationZ="@dimen/volume_dialog_elevation"
+                android:clipToPadding="false"
+                android:background="@drawable/rounded_bg_full">
+                <com.android.keyguard.AlphaOptimizedImageButton
+                    android:id="@+id/ringer_icon"
+                    style="@style/VolumeButtons"
+                    android:background="@drawable/rounded_ripple"
+                    android:layout_width="match_parent"
+                    android:layout_height="match_parent"
+                    android:scaleType="fitCenter"
+                    android:padding="@dimen/volume_dialog_ringer_icon_padding"
+                    android:tint="?android:attr/textColorPrimary"
+                    android:layout_gravity="center"
+                    android:soundEffectsEnabled="false" />
+            </FrameLayout>
+
+            <LinearLayout
+                android:id="@+id/volume_dialog_rows_container"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:gravity="right"
+                android:layout_gravity="right"
+                android:orientation="vertical"
+                android:clipChildren="false"
+                android:clipToPadding="false" >
+                <LinearLayout
+                    android:id="@+id/volume_dialog_rows"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:gravity="center"
+                    android:orientation="horizontal">
+                        <!-- volume rows added and removed here! :-) -->
+                </LinearLayout>
+                <FrameLayout
+                    android:id="@+id/settings_container"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:background="@drawable/volume_background_bottom"
+                    android:paddingLeft="@dimen/volume_dialog_ringer_rows_padding"
+                    android:paddingBottom="@dimen/volume_dialog_ringer_rows_padding"
+                    android:paddingRight="@dimen/volume_dialog_ringer_rows_padding">
+                    <com.android.keyguard.AlphaOptimizedImageButton
+                        android:id="@+id/settings"
+                        android:src="@drawable/horizontal_ellipsis"
+                        android:layout_width="@dimen/volume_dialog_tap_target_size"
+                        android:layout_height="@dimen/volume_dialog_tap_target_size"
+                        android:layout_gravity="center"
+                        android:contentDescription="@string/accessibility_volume_settings"
+                        android:background="@drawable/ripple_drawable_20dp"
+                        android:tint="?androidprv:attr/colorAccent"
+                        android:soundEffectsEnabled="false" />
+                </FrameLayout>
+            </LinearLayout>
+
+        </LinearLayout>
+
+        <FrameLayout
+            android:id="@+id/odi_captions"
+            android:layout_width="@dimen/volume_dialog_caption_size"
+            android:layout_height="@dimen/volume_dialog_caption_size"
+            android:layout_marginTop="@dimen/volume_dialog_row_margin_bottom"
+            android:gravity="right"
+            android:layout_gravity="right"
+            android:clipToPadding="false"
+            android:clipToOutline="true"
+            android:background="@drawable/volume_row_rounded_background">
+            <com.android.systemui.volume.CaptionsToggleImageButton
+                android:id="@+id/odi_captions_icon"
+                android:src="@drawable/ic_volume_odi_captions_disabled"
+                style="@style/VolumeButtons"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"
+                android:tint="?android:attr/colorAccent"
+                android:layout_gravity="center"
+                android:soundEffectsEnabled="false"/>
+        </FrameLayout>
+    </LinearLayout>
+
+    <ViewStub
+        android:id="@+id/odi_captions_tooltip_stub"
+        android:inflatedId="@+id/odi_captions_tooltip_view"
+        android:layout="@layout/volume_tool_tip_view"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="bottom | right"
+        android:layout_marginRight="@dimen/volume_tool_tip_right_margin"/>
+
+</FrameLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/volume_dialog_slider.xml b/packages/SystemUI/res/layout/volume_dialog_slider.xml
new file mode 100644
index 0000000..8acdd39
--- /dev/null
+++ b/packages/SystemUI/res/layout/volume_dialog_slider.xml
@@ -0,0 +1,27 @@
+<!--
+     Copyright (C) 2024 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="@dimen/volume_dialog_slider_width"
+    android:layout_height="@dimen/volume_dialog_slider_height">
+
+    <com.google.android.material.slider.Slider
+        android:id="@+id/volume_dialog_slider"
+        android:layout_width="@dimen/volume_dialog_slider_height"
+        android:layout_height="match_parent"
+        android:layout_gravity="center"
+        android:rotation="270"
+        android:theme="@style/Theme.MaterialComponents.DayNight" />
+</FrameLayout>
diff --git a/packages/SystemUI/res/layout/volume_dialog_slider_floating.xml b/packages/SystemUI/res/layout/volume_dialog_slider_floating.xml
new file mode 100644
index 0000000..db800aa
--- /dev/null
+++ b/packages/SystemUI/res/layout/volume_dialog_slider_floating.xml
@@ -0,0 +1,24 @@
+<!--
+     Copyright (C) 2024 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:background="@drawable/volume_dialog_floating_slider_background"
+    android:paddingHorizontal="@dimen/volume_dialog_floating_sliders_horizontal_padding"
+    android:paddingVertical="@dimen/volume_dialog_floating_sliders_vertical_padding">
+
+    <include layout="@layout/volume_dialog_slider" />
+</FrameLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index a9f9faf..62bff957 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -440,7 +440,7 @@
     <string name="zen_mode_on" msgid="9085304934016242591">"Aan"</string>
     <string name="zen_mode_on_with_details" msgid="7416143430557895497">"Op • <xliff:g id="TRIGGER_DESCRIPTION">%1$s</xliff:g>"</string>
     <string name="zen_mode_off" msgid="1736604456618147306">"Af"</string>
-    <string name="zen_mode_set_up" msgid="7457957033034460064">"Stel op"</string>
+    <string name="zen_mode_set_up" msgid="8231201163894922821">"Nie gestel nie"</string>
     <string name="zen_mode_no_manual_invocation" msgid="1769975741344633672">"Bestuur in instellings"</string>
     <string name="zen_mode_active_modes" msgid="1625850411578488856">"{count,plural, =0{Geen aktiewe modusse nie}=1{{mode} is aktief}other{# modusse is aktief}}"</string>
     <string name="zen_priority_introduction" msgid="3159291973383796646">"Jy sal nie deur geluide en vibrasies gepla word nie, behalwe deur wekkers, herinneringe, geleenthede en bellers wat jy spesifiseer. Jy sal steeds enigiets hoor wat jy kies om te speel, insluitend musiek, video\'s en speletjies."</string>
@@ -573,8 +573,7 @@
     <string name="notification_section_header_conversations" msgid="821834744538345661">"Gesprekke"</string>
     <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Vee alle stil kennisgewings uit"</string>
     <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Kennisgewings onderbreek deur Moenie Steur Nie"</string>
-    <!-- no translation found for modes_suppressing_shade_text (6037581130837903239) -->
-    <skip />
+    <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{Geen kennisgewings nie}=1{Kennisgewings is deur {mode} onderbreek}=2{Kennisgewings is deur {mode} en een ander modus onderbreek}other{Kennisgewings is deur {mode} en # ander modusse onderbreek}}"</string>
     <string name="media_projection_action_text" msgid="3634906766918186440">"Begin nou"</string>
     <string name="empty_shade_text" msgid="8935967157319717412">"Geen kennisgewings nie"</string>
     <string name="no_unseen_notif_text" msgid="395512586119868682">"Geen nuwe kennisgewings nie"</string>
@@ -673,6 +672,10 @@
     <string name="stream_notification_unavailable" msgid="4313854556205836435">"Onbeskikbaar omdat luitoon gedemp is"</string>
     <string name="stream_alarm_unavailable" msgid="4059817189292197839">"Onbeskikbaar want Moenie Steur Nie is aan"</string>
     <string name="stream_media_unavailable" msgid="6823020894438959853">"Onbeskikbaar want Moenie Steur Nie is aan"</string>
+    <!-- no translation found for stream_unavailable_by_modes (3674139029490353683) -->
+    <skip />
+    <!-- no translation found for stream_unavailable_by_unknown (6908434629318171588) -->
+    <skip />
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Tik om te ontdemp."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Tik om op vibreer te stel. Toeganklikheidsdienste kan dalk gedemp wees."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Tik om te demp. Toeganklikheidsdienste kan dalk gedemp wees."</string>
@@ -706,6 +709,7 @@
     <string name="show_demo_mode" msgid="3677956462273059726">"Wys demonstrasiemodus"</string>
     <string name="status_bar_ethernet" msgid="5690979758988647484">"Ethernet"</string>
     <string name="status_bar_alarm" msgid="87160847643623352">"Wekker"</string>
+    <string name="active_mode_content_description" msgid="1627555562186515927">"<xliff:g id="MODENAME">%1$s</xliff:g> is aan"</string>
     <string name="wallet_title" msgid="5369767670735827105">"Wallet"</string>
     <string name="wallet_empty_state_label" msgid="7776761245237530394">"Stel op om vinniger, veiliger aankope met jou foon te doen"</string>
     <string name="wallet_app_button_label" msgid="7123784239111190992">"Wys alles"</string>
@@ -1405,26 +1409,26 @@
     <string name="launch_touchpad_tutorial_notification_content" msgid="7931085031240753226">"Leer raakpaneelgebare"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_title" msgid="1940023776496198762">"Navigeer met jou sleutelbord en raakpaneel"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Leer raakpaneelgebare, kortpadsleutels en meer"</string>
-    <string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Teruggebaar"</string>
-    <string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Tuisgebaar"</string>
+    <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"Gaan terug"</string>
+    <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Gaan na tuisskerm"</string>
     <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Bekyk onlangse apps"</string>
     <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Klaar"</string>
     <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Gaan terug"</string>
-    <string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"Swiep enige plek op die raakpaneel links of regs met drie vingers om terug te gaan.\n\nJy kan ook die kortpadsleutelhandeling + Esc hiervoor gebruik."</string>
-    <string name="touchpad_back_gesture_success_title" msgid="7240576648330612171">"Knap gedaan!"</string>
+    <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"Swiep links of regs met drie vingers op jou raakpaneel"</string>
+    <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"Mooi so!"</string>
     <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"Jy het die Gaan Terug-gebaar voltooi."</string>
     <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"Gaan na tuisskerm"</string>
-    <string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"Swiep enige tyd van die onderkant van jou skerm af op met drie vingers om na jou tuisskerm toe te gaan."</string>
-    <string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Mooi so!"</string>
-    <string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Jy het die Gaan na Tuisskerm-gebaar voltooi."</string>
+    <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"Swiep op met drie vingers op jou raakpaneel"</string>
+    <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"Uitstekende werk!"</string>
+    <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"Jy het die Gaan na Tuisskerm-gebaar voltooi"</string>
     <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"Bekyk onlangse apps"</string>
-    <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"Swiep op en hou met drie vingers op jou raakpaneel."</string>
+    <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"Swiep op en hou met drie vingers op jou raakpaneel"</string>
     <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Knap gedaan!"</string>
     <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Jy het die Bekyk Onlangse Apps-gebaar voltooi."</string>
-    <string name="tutorial_action_key_title" msgid="2659466586996495447">"Handelingsleutel"</string>
-    <string name="tutorial_action_key_guidance" msgid="5718948664616999196">"Druk die handelingsleutel op jou sleutelbord om toegang tot jou apps te kry."</string>
-    <string name="tutorial_action_key_success_title" msgid="466467860120112933">"Geluk!"</string>
-    <string name="tutorial_action_key_success_body" msgid="7201991081652850430">"Jy het die Handelingsleutel-gebaar voltooi.\n\nHandeling + / wys al die kortpaaie wat vir jou beskikbaar is."</string>
+    <string name="tutorial_action_key_title" msgid="8172535792469008169">"Bekyk alle apps"</string>
+    <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Druk die handelingsleutel op jou sleutelbord"</string>
+    <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Welgedaan!"</string>
+    <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Jy het die Bekyk Onlangse Apps-gebaar voltooi"</string>
     <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Sleutelbordlig"</string>
     <string name="keyboard_backlight_value" msgid="7336398765584393538">"Vlak %1$d van %2$d"</string>
     <string name="home_controls_dream_label" msgid="6567105701292324257">"Huiskontroles"</string>
@@ -1436,6 +1440,7 @@
     <string name="all_apps_edu_toast_content" msgid="8807496014667211562">"Druk die handelingsleutel op jou sleutelbord om al jou apps te bekyk"</string>
     <string name="redacted_notification_single_line_title" msgid="212019960919261670">"Gewysig"</string>
     <string name="redacted_notification_single_line_text" msgid="8684166405005242945">"Ontsluit om te kyk"</string>
+    <string name="contextual_education_dialog_title" msgid="4630392552837487324">"Kontekstuele opvoeding"</string>
     <string name="back_edu_notification_title" msgid="5624780717751357278">"Gebruik jou raakpaneel om terug te gaan"</string>
     <string name="back_edu_notification_content" msgid="2497557451540954068">"Swiep links of regs met drie vingers. Tik om meer gebare te leer."</string>
     <string name="home_edu_notification_title" msgid="6097902076909654045">"Gebruik jou raakpaneel om na die tuisskerm toe te gaan"</string>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index 704bdca..74e072b 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -440,7 +440,7 @@
     <string name="zen_mode_on" msgid="9085304934016242591">"በርቷል"</string>
     <string name="zen_mode_on_with_details" msgid="7416143430557895497">"በርቷል • <xliff:g id="TRIGGER_DESCRIPTION">%1$s</xliff:g>"</string>
     <string name="zen_mode_off" msgid="1736604456618147306">"ጠፍቷል"</string>
-    <string name="zen_mode_set_up" msgid="7457957033034460064">"አዋቅር"</string>
+    <string name="zen_mode_set_up" msgid="8231201163894922821">"አልተቀናበረም"</string>
     <string name="zen_mode_no_manual_invocation" msgid="1769975741344633672">"በቅንብሮች ውስጥ አስተዳድር"</string>
     <string name="zen_mode_active_modes" msgid="1625850411578488856">"{count,plural, =0{ምንም ገቢር ሁነታዎች የሉም}=1{{mode} ገቢር ነው}one{# ሁኔታ ገቢር ነው}other{# ሁኔታዎች ገቢር ናቸው}}"</string>
     <string name="zen_priority_introduction" msgid="3159291973383796646">"እርስዎ ከወሰንዋቸው ማንቂያዎች፣ አስታዋሾች፣ ክስተቶች እና ደዋዮች በስተቀር፣ በድምጾች እና ንዝረቶች አይረበሹም። ሙዚቃ፣ ቪዲዮዎች እና ጨዋታዎች ጨምሮ ለመጫወት የሚመርጡትን ማንኛውም ነገር አሁንም ይሰማሉ።"</string>
@@ -573,8 +573,7 @@
     <string name="notification_section_header_conversations" msgid="821834744538345661">"ውይይቶች"</string>
     <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"ሁሉንም ጸጥ ያሉ ማሳወቂያዎችን ያጽዱ"</string>
     <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"ማሳወቂያዎች በአትረብሽ ባሉበት ቆመዋል"</string>
-    <!-- no translation found for modes_suppressing_shade_text (6037581130837903239) -->
-    <skip />
+    <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{ምንም ማሳወቂያዎች የሉም}=1{ማሳወቂያዎች በ{mode} ባሉበት ቆመዋል}=2{ማሳወቂያዎች በ{mode} እና አንድ ሌላ ሁነታ ባሉበት ቆመዋል}one{ማሳወቂያዎች በ{mode} እና # ሌላ ሁነታ ባሉበት ቆመዋል}other{ማሳወቂያዎች በ{mode} እና # ሌላ ሁነታዎች ባሉበት ቆመዋል}}"</string>
     <string name="media_projection_action_text" msgid="3634906766918186440">"አሁን ጀምር"</string>
     <string name="empty_shade_text" msgid="8935967157319717412">"ምንም ማሳወቂያ የለም"</string>
     <string name="no_unseen_notif_text" msgid="395512586119868682">"ምንም አዲስ ማሳወቂያዎች የሉም"</string>
@@ -673,6 +672,10 @@
     <string name="stream_notification_unavailable" msgid="4313854556205836435">"የጥሪ ድምጽ ስለተዘጋ አይገኝም"</string>
     <string name="stream_alarm_unavailable" msgid="4059817189292197839">"አትረብሽ ስለበራ አይገኝም"</string>
     <string name="stream_media_unavailable" msgid="6823020894438959853">"አትረብሽ ስለበራ አይገኝም"</string>
+    <!-- no translation found for stream_unavailable_by_modes (3674139029490353683) -->
+    <skip />
+    <!-- no translation found for stream_unavailable_by_unknown (6908434629318171588) -->
+    <skip />
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s። ድምጸ-ከል ለማድረግ መታ ያድርጉ"</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s። ወደ ንዝረት ለማቀናበር መታ ያድርጉ። የተደራሽነት አገልግሎቶች ድምጸ-ከል ሊደረግባቸው ይችላል።"</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s። ድምጸ-ከል ለማድረግ መታ ያድርጉ። የተደራሽነት አገልግሎቶች ድምጸ-ከል ሊደረግባቸው ይችላል።"</string>
@@ -706,6 +709,7 @@
     <string name="show_demo_mode" msgid="3677956462273059726">"ማሳያ ሁነታን አሳይ"</string>
     <string name="status_bar_ethernet" msgid="5690979758988647484">"ኤተርኔት"</string>
     <string name="status_bar_alarm" msgid="87160847643623352">"ማንቂያ"</string>
+    <string name="active_mode_content_description" msgid="1627555562186515927">"<xliff:g id="MODENAME">%1$s</xliff:g> በርቷል"</string>
     <string name="wallet_title" msgid="5369767670735827105">"Wallet"</string>
     <string name="wallet_empty_state_label" msgid="7776761245237530394">"በስልክዎ በመጠቀም ፈጣን እና የበለጠ ደህንነቱ በተጠበቀ መንገድ ግዢዎችን ለመፈጸም ዝግጁ ይሁኑ"</string>
     <string name="wallet_app_button_label" msgid="7123784239111190992">"ሁሉንም አሳይ"</string>
@@ -1405,26 +1409,26 @@
     <string name="launch_touchpad_tutorial_notification_content" msgid="7931085031240753226">"የመዳሰሻ ሰሌዳ ምልክቶችን ይወቁ"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_title" msgid="1940023776496198762">"የእርስዎን የቁልፍ ሰሌዳ እና የመዳሰሻ ሰሌዳ በመጠቀም ያስሱ"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"የመዳሰሻ ሰሌዳ ምልክቶችን፣ የቁልፍ ሰሌዳ አቋራጮችን እና ሌሎችን ይወቁ"</string>
-    <string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"የተመለስ ምልክት"</string>
-    <string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"የቤት ምልክት"</string>
+    <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"ወደኋላ ተመለስ"</string>
+    <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"ወደ መነሻ ሂድ"</string>
     <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"የቅርብ ጊዜ መተግበሪያዎችን አሳይ"</string>
     <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"ተከናውኗል"</string>
     <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"ወደኋላ ተመለስ"</string>
-    <string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"ወደኋላ ለመመለስ የመዳሰሻ ሰሌዳው ላይ የትኛውም ቦታ በሦስት ጣቶች ወደግራ ወይም ወደቀኝ ያንሸራትቱ።\n\nእንዲሁም የቁልፍ ሰሌዳ አቋራጭ + ESC ለዚህ መጠቀም ይችላሉ።"</string>
-    <string name="touchpad_back_gesture_success_title" msgid="7240576648330612171">"ጥሩ ሠርተዋል!"</string>
+    <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"የመዳሰሻ ሰሌዳዎ ላይ ሦስት ጣቶችን በመጠቀም ወደ ግራ ወይም ወደ ቀኝ ያንሸራትቱ"</string>
+    <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"አሪፍ!"</string>
     <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"ወደኋላ የመመለስ ምልክትን አጠናቅቀዋል።"</string>
     <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"ወደ መነሻ ሂድ"</string>
-    <string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"በማንኛውም ጊዜ ወደ መነሻ ማያ ገፅዎ ለመሄድ ከማያ ገፅዎ ታች በሦስት ጣቶች ወደላይ ያሸብልሉ።"</string>
-    <string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"አሪፍ!"</string>
-    <string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"ወደ መነሻ ሂድ ምልክትን አጠናቅቀዋል።"</string>
+    <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"በመዳሰሻ ሰሌዳዎ ላይ በሦስት ጣቶች ወደ ላይ ያንሸራትቱ"</string>
+    <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"ጥሩ ሥራ!"</string>
+    <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"ወደ መነሻ ሂድ ምልክትን አጠናቅቀዋል"</string>
     <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"የቅርብ ጊዜ መተግበሪያዎችን አሳይ"</string>
-    <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"የመዳሰሻ ሰሌዳዎ ላይ ሦስት ጣቶችን በመጠቀም ወደ ላይ ያንሸራትቱ እና ይያዙ።"</string>
+    <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"የመዳሰሻ ሰሌዳዎ ላይ ሦስት ጣቶችን በመጠቀም ወደላይ ያንሸራትቱ እና ይያዙ"</string>
     <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"ጥሩ ሠርተዋል!"</string>
     <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"የቅርብ ጊዜ መተግበሪያዎች አሳይ ምልክትን አጠናቅቀዋል።"</string>
-    <string name="tutorial_action_key_title" msgid="2659466586996495447">"የተግባር ቁልፍ"</string>
-    <string name="tutorial_action_key_guidance" msgid="5718948664616999196">"መተግበሪያዎችዎን ለመድረስ በቁልፍ ሰሌዳዎ ላይ የእርምጃ ቁልፉን ይጫኑ።"</string>
-    <string name="tutorial_action_key_success_title" msgid="466467860120112933">"እንኳን ደስ አለዎት!"</string>
-    <string name="tutorial_action_key_success_body" msgid="7201991081652850430">"የተግባር ቁልፍ ምልክቱን አጠናቅቀዋል።\n\nእርምጃ + / ለእርስዎ ተገኚ የሆኑትን አቋራጮች በሙሉ ያሳያል።"</string>
+    <string name="tutorial_action_key_title" msgid="8172535792469008169">"ሁሉንም መተግበሪያዎች ይመልከቱ"</string>
+    <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"በቁልፍ ሰሌዳዎ ላይ ያለውን የተግባር ቁልፍ ይጫኑ"</string>
+    <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"ጥሩ ሠርተዋል!"</string>
+    <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"የሁሉንም መተግበሪያዎች አሳይ ምልክትን አጠናቅቀዋል"</string>
     <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"የቁልፍ ሰሌዳ የጀርባ ብርሃን"</string>
     <string name="keyboard_backlight_value" msgid="7336398765584393538">"ደረጃ %1$d ከ %2$d"</string>
     <string name="home_controls_dream_label" msgid="6567105701292324257">"የቤት ውስጥ ቁጥጥሮች"</string>
@@ -1436,6 +1440,7 @@
     <string name="all_apps_edu_toast_content" msgid="8807496014667211562">"ሁሉንም መተግበሪያዎችዎን ለማየት በቁልፍ ሰሌዳዎ ላይ ያለውን የተግባር ቁልፍ ይጫኑ"</string>
     <string name="redacted_notification_single_line_title" msgid="212019960919261670">"ጽሁፍ ተቀይሯል"</string>
     <string name="redacted_notification_single_line_text" msgid="8684166405005242945">"ለመመልከት ይክፈቱ"</string>
+    <string name="contextual_education_dialog_title" msgid="4630392552837487324">"የዓውድ ትምህርት"</string>
     <string name="back_edu_notification_title" msgid="5624780717751357278">"ለመመለስ የመዳሰሻ ሰሌዳዎን ይጠቀሙ"</string>
     <string name="back_edu_notification_content" msgid="2497557451540954068">"ሦስት ጣቶችን በመጠቀም ወደ ግራ ወይም ወደ ቀኝ ያንሸራትቱ። ምልክቶችን የበለጠ ለማወቅ መታ ያድርጉ።"</string>
     <string name="home_edu_notification_title" msgid="6097902076909654045">"ወደ መነሻ ለመመለስ የመዳሰሻ ሰሌዳዎን ይጠቀሙ"</string>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index 8ed225d..922caea 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -440,7 +440,7 @@
     <string name="zen_mode_on" msgid="9085304934016242591">"مفعَّل"</string>
     <string name="zen_mode_on_with_details" msgid="7416143430557895497">"مفعّل • <xliff:g id="TRIGGER_DESCRIPTION">%1$s</xliff:g>"</string>
     <string name="zen_mode_off" msgid="1736604456618147306">"غير مفعَّل"</string>
-    <string name="zen_mode_set_up" msgid="7457957033034460064">"إعداد"</string>
+    <string name="zen_mode_set_up" msgid="8231201163894922821">"لم يتم ضبط الوضع"</string>
     <string name="zen_mode_no_manual_invocation" msgid="1769975741344633672">"الإدارة في الإعدادات"</string>
     <string name="zen_mode_active_modes" msgid="1625850411578488856">"{count,plural, =0{ما مِن أوضاع مفعَّلة}=1{الوضع \"{mode}\" مفعَّل}two{وضعان مفعَّلان}few{‫# أوضاع مفعَّلة}many{‫# وضعًا مفعَّلاً}other{‫# وضع مفعَّل}}"</string>
     <string name="zen_priority_introduction" msgid="3159291973383796646">"لن يتم إزعاجك بالأصوات والاهتزاز، باستثناء المُنبِّهات والتذكيرات والأحداث والمتصلين الذين تحددهم. وسيظل بإمكانك سماع أي عناصر أخرى تختار تشغيلها، بما في ذلك الموسيقى والفيديوهات والألعاب."</string>
@@ -573,8 +573,7 @@
     <string name="notification_section_header_conversations" msgid="821834744538345661">"المحادثات"</string>
     <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"محو جميع الإشعارات الصامتة"</string>
     <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"تم إيقاف الإشعارات مؤقتًا وفقًا لإعداد \"عدم الإزعاج\""</string>
-    <!-- no translation found for modes_suppressing_shade_text (6037581130837903239) -->
-    <skip />
+    <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{ما مِن إشعارات}=1{تم إيقاف الإشعارات مؤقتًا بواسطة \"{mode}\"}=2{تم إيقاف الإشعارات مؤقتًا بواسطة \"{mode}\" ووضع واحد آخر}few{تم إيقاف الإشعارات مؤقتًا بواسطة \"{mode}\" و# أوضاع أخرى}many{تم إيقاف الإشعارات مؤقتًا بواسطة \"{mode}\" و# وضعًا آخر}other{تم إيقاف الإشعارات مؤقتًا بواسطة \"{mode}\" و# وضع آخر}}"</string>
     <string name="media_projection_action_text" msgid="3634906766918186440">"البدء الآن"</string>
     <string name="empty_shade_text" msgid="8935967157319717412">"ما مِن إشعارات"</string>
     <string name="no_unseen_notif_text" msgid="395512586119868682">"ما مِن إشعارات جديدة"</string>
@@ -673,6 +672,10 @@
     <string name="stream_notification_unavailable" msgid="4313854556205836435">"غير متاح بسبب كتم صوت الرنين"</string>
     <string name="stream_alarm_unavailable" msgid="4059817189292197839">"مستوى الصوت غير متاح بسبب تفعيل وضع \"عدم الإزعاج\""</string>
     <string name="stream_media_unavailable" msgid="6823020894438959853">"مستوى الصوت غير متاح لأنّ وضع \"عدم الإزعاج\" مفعّل"</string>
+    <!-- no translation found for stream_unavailable_by_modes (3674139029490353683) -->
+    <skip />
+    <!-- no translation found for stream_unavailable_by_unknown (6908434629318171588) -->
+    <skip />
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"‏%1$s. انقر لإلغاء التجاهل."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"‏%1$s. انقر للتعيين على الاهتزاز. قد يتم تجاهل خدمات \"سهولة الاستخدام\"."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"‏%1$s. انقر للتجاهل. قد يتم تجاهل خدمات \"سهولة الاستخدام\"."</string>
@@ -706,6 +709,7 @@
     <string name="show_demo_mode" msgid="3677956462273059726">"عرض الوضع التجريبي"</string>
     <string name="status_bar_ethernet" msgid="5690979758988647484">"إيثرنت"</string>
     <string name="status_bar_alarm" msgid="87160847643623352">"المنبّه"</string>
+    <string name="active_mode_content_description" msgid="1627555562186515927">"وضع \"<xliff:g id="MODENAME">%1$s</xliff:g>\" مفعَّل"</string>
     <string name="wallet_title" msgid="5369767670735827105">"‏محفظة Google"</string>
     <string name="wallet_empty_state_label" msgid="7776761245237530394">"يمكنك إعداد طريقة دفع لإجراء عمليات شراء بسرعة وأمان أكبر باستخدام هاتفك."</string>
     <string name="wallet_app_button_label" msgid="7123784239111190992">"عرض الكل"</string>
@@ -1405,26 +1409,26 @@
     <string name="launch_touchpad_tutorial_notification_content" msgid="7931085031240753226">"تعرَّف على إيماءات لوحة اللمس"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_title" msgid="1940023776496198762">"التنقّل باستخدام لوحة المفاتيح ولوحة اللمس"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"تعرَّف على إيماءات لوحة اللمس واختصارات لوحة المفاتيح والمزيد"</string>
-    <string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"إيماءة الرجوع"</string>
-    <string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"إيماءة الانتقال إلى الشاشة الرئيسية"</string>
+    <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"رجوع"</string>
+    <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"الانتقال إلى الصفحة الرئيسية"</string>
     <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"عرض التطبيقات المستخدَمة مؤخرًا"</string>
     <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"تم"</string>
     <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"رجوع"</string>
-    <string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"‏للرجوع، مرِّر سريعًا لليمين أو لليسار باستخدام ثلاثة أصابع في أي مكان على لوحة اللمس.\n\nيمكنك أيضًا الرجوع باستخدام اختصار لوحة المفاتيح \"مفتاح الإجراء + ESC\"."</string>
-    <string name="touchpad_back_gesture_success_title" msgid="7240576648330612171">"أحسنت"</string>
+    <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"مرِّر سريعًا لليمين أو لليسار باستخدام 3 أصابع على لوحة اللمس"</string>
+    <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"أحسنت."</string>
     <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"لقد أكملت التدريب على إيماءة الرجوع."</string>
     <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"الانتقال إلى الشاشة الرئيسية"</string>
-    <string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"للانتقال إلى الشاشة الرئيسية في أي وقت، مرِّر سريعًا من أسفل الشاشة إلى أعلاها بثلاثة أصابع."</string>
-    <string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"أحسنت"</string>
-    <string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"لقد أكملت التدريب على إيماءة الانتقال إلى الشاشة الرئيسية."</string>
+    <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"مرّر سريعًا للأعلى باستخدام 3 أصابع على لوحة اللمس"</string>
+    <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"أحسنت صنعًا."</string>
+    <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"لقد أكملت الدليل التوجيهي عن إيماءة \"الانتقال إلى الشاشة الرئيسية\""</string>
     <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"عرض التطبيقات المستخدَمة مؤخرًا"</string>
-    <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"مرِّر سريعًا للأعلى مع استمرار الضغط باستخدام ثلاثة أصابع على لوحة اللمس."</string>
+    <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"مرِّر سريعًا للأعلى مع الاستمرار باستخدام 3 أصابع على لوحة اللمس"</string>
     <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"أحسنت."</string>
     <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"لقد أكملْت الدليل التوجيهي على إيماءة \"عرض التطبيقات المستخدَمة مؤخرًا\"."</string>
-    <string name="tutorial_action_key_title" msgid="2659466586996495447">"مفتاح الإجراء"</string>
-    <string name="tutorial_action_key_guidance" msgid="5718948664616999196">"للوصول إلى التطبيقات، اضغط على مفتاح الإجراء في لوحة المفاتيح."</string>
-    <string name="tutorial_action_key_success_title" msgid="466467860120112933">"تهانينا!"</string>
-    <string name="tutorial_action_key_success_body" msgid="7201991081652850430">"لقد أكملت التدريب على إيماءة مفتاح الإجراء.\n\nيؤدي الضغط على مفتاح الإجراء + / إلى عرض جميع الاختصارات المتاحة."</string>
+    <string name="tutorial_action_key_title" msgid="8172535792469008169">"عرض جميع التطبيقات"</string>
+    <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"اضغط على مفتاح الإجراء في لوحة المفاتيح"</string>
+    <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"أحسنت!"</string>
+    <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"لقد أكملْت الدليل التوجيهي عن إيماءة \"عرض جميع التطبيقات\""</string>
     <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"الإضاءة الخلفية للوحة المفاتيح"</string>
     <string name="keyboard_backlight_value" msgid="7336398765584393538">"‏مستوى الإضاءة: %1$d من %2$d"</string>
     <string name="home_controls_dream_label" msgid="6567105701292324257">"إدارة المنزل آليًّا"</string>
@@ -1436,6 +1440,7 @@
     <string name="all_apps_edu_toast_content" msgid="8807496014667211562">"لعرض جميع التطبيقات، اضغط على مفتاح الإجراء في لوحة المفاتيح"</string>
     <string name="redacted_notification_single_line_title" msgid="212019960919261670">"إشعار مخفي"</string>
     <string name="redacted_notification_single_line_text" msgid="8684166405005242945">"افتح القفل لعرض المعلومات"</string>
+    <string name="contextual_education_dialog_title" msgid="4630392552837487324">"التعليم السياقي"</string>
     <string name="back_edu_notification_title" msgid="5624780717751357278">"استخدِم لوحة اللمس للرجوع"</string>
     <string name="back_edu_notification_content" msgid="2497557451540954068">"مرِّر سريعًا لليمين أو لليسار باستخدام 3 أصابع. انقر للتعرّف على المزيد من الإيماءات."</string>
     <string name="home_edu_notification_title" msgid="6097902076909654045">"استخدِم لوحة اللمس للانتقال إلى الشاشة الرئيسية"</string>
diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml
index 07c6f73..f353428 100644
--- a/packages/SystemUI/res/values-as/strings.xml
+++ b/packages/SystemUI/res/values-as/strings.xml
@@ -440,7 +440,7 @@
     <string name="zen_mode_on" msgid="9085304934016242591">"অন আছে"</string>
     <string name="zen_mode_on_with_details" msgid="7416143430557895497">"অন আছে • <xliff:g id="TRIGGER_DESCRIPTION">%1$s</xliff:g>"</string>
     <string name="zen_mode_off" msgid="1736604456618147306">"অফ আছে"</string>
-    <string name="zen_mode_set_up" msgid="7457957033034460064">"ছেট আপ কৰক"</string>
+    <string name="zen_mode_set_up" msgid="8231201163894922821">"ছেট কৰা হোৱা নাই"</string>
     <string name="zen_mode_no_manual_invocation" msgid="1769975741344633672">"ছেটিঙত পৰিচালনা কৰক"</string>
     <string name="zen_mode_active_modes" msgid="1625850411578488856">"{count,plural, =0{কোনো সক্ৰিয় ম’ড নাই}=1{{mode} সক্ৰিয় আছে}one{# টা ম’ড সক্ৰিয় আছে}other{# টা ম’ড সক্ৰিয় আছে}}"</string>
     <string name="zen_priority_introduction" msgid="3159291973383796646">"আপুনি নিৰ্দিষ্ট কৰা এলাৰ্ম, ৰিমাইণ্ডাৰ, ইভেন্ট আৰু কল কৰোঁতাৰ বাহিৰে আন কোনো শব্দৰ পৰা আপুনি অসুবিধা নাপাব। কিন্তু, সংগীত, ভিডিঅ\' আৰু খেলসমূহকে ধৰি আপুনি প্লে কৰিব খোজা যিকোনো বস্তু তথাপি শুনিব পাৰিব।"</string>
@@ -573,8 +573,7 @@
     <string name="notification_section_header_conversations" msgid="821834744538345661">"বাৰ্তালাপ"</string>
     <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"আটাইবোৰ নীৰৱ জাননী মচক"</string>
     <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"অসুবিধা নিদিব-ই জাননী পজ কৰিছে"</string>
-    <!-- no translation found for modes_suppressing_shade_text (6037581130837903239) -->
-    <skip />
+    <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{কোনো জাননী নাই}=1{{mode}এ জাননী পজ কৰিছে}=2{{mode} আৰু আন এটা ম’ডে জাননী পজ কৰিছে}one{{mode} আৰু আন # টা ম’ডে জাননী পজ কৰিছে}other{{mode} আৰু আন # টা ম’ডে জাননী পজ কৰিছে}}"</string>
     <string name="media_projection_action_text" msgid="3634906766918186440">"এতিয়াই আৰম্ভ কৰক"</string>
     <string name="empty_shade_text" msgid="8935967157319717412">"কোনো জাননী নাই"</string>
     <string name="no_unseen_notif_text" msgid="395512586119868682">"কোনো নতুন জাননী নাই"</string>
@@ -673,6 +672,10 @@
     <string name="stream_notification_unavailable" msgid="4313854556205836435">"ৰিং মিউট কৰি থোৱাৰ বাবে উপলব্ধ নহয়"</string>
     <string name="stream_alarm_unavailable" msgid="4059817189292197839">"অসুবিধা নিদিব অন থকাৰ কাৰণে উপলব্ধ নহয়"</string>
     <string name="stream_media_unavailable" msgid="6823020894438959853">"অসুবিধা নিদিব অন থকাৰ কাৰণে উপলব্ধ নহয়"</string>
+    <!-- no translation found for stream_unavailable_by_modes (3674139029490353683) -->
+    <skip />
+    <!-- no translation found for stream_unavailable_by_unknown (6908434629318171588) -->
+    <skip />
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s। আনমিউট কৰিবৰ বাবে টিপক।"</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s। কম্পনৰ বাবে টিপক। দিব্য়াংগসকলৰ বাবে থকা সেৱা মিউট হৈ থাকিব পাৰে।"</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s। মিউট কৰিবলৈ টিপক। দিব্য়াংগসকলৰ বাবে থকা সেৱা মিউট হৈ থাকিব পাৰে।"</string>
@@ -706,6 +709,7 @@
     <string name="show_demo_mode" msgid="3677956462273059726">"ডেম\' ম\'ড দেখুৱাওক"</string>
     <string name="status_bar_ethernet" msgid="5690979758988647484">"ইথাৰনেট"</string>
     <string name="status_bar_alarm" msgid="87160847643623352">"এলাৰ্ম"</string>
+    <string name="active_mode_content_description" msgid="1627555562186515927">"<xliff:g id="MODENAME">%1$s</xliff:g> অন আছে"</string>
     <string name="wallet_title" msgid="5369767670735827105">"ৱালেট"</string>
     <string name="wallet_empty_state_label" msgid="7776761245237530394">"আপোনাৰ ফ’নটোৰে দ্ৰুত তথা অধিক সুৰক্ষিত ক্ৰয় কৰিবলৈ ছেট আপ পাওক"</string>
     <string name="wallet_app_button_label" msgid="7123784239111190992">"আটাইবোৰ দেখুৱাওক"</string>
@@ -1405,26 +1409,26 @@
     <string name="launch_touchpad_tutorial_notification_content" msgid="7931085031240753226">"টাচ্চপেডৰ নিৰ্দেশসমূহ জানক"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_title" msgid="1940023776496198762">"আপোনাৰ কীব’ৰ্ড আৰু টাচ্চপেড ব্যৱহাৰ কৰি নেভিগে’ট কৰক"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"টাচ্চপেডৰ নিৰ্দেশ, কীব’ৰ্ডৰ শ্বৰ্টকাট আৰু অধিকৰ বিষয়ে জানক"</string>
-    <string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"উভতি যাওক নিৰ্দেশ"</string>
-    <string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"গৃহ স্ক্ৰীনলৈ যোৱাৰ নিৰ্দেশ"</string>
+    <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"উভতি যাওক"</string>
+    <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"গৃহ পৃষ্ঠালৈ যাওক"</string>
     <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"শেহতীয়া এপ্‌সমূহ চাওক"</string>
     <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"হ’ল"</string>
     <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"উভতি যাওক"</string>
-    <string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"উভতি যাবলৈ, টাচ্চপেডৰ যিকোনো স্থানত তিনিটা আঙুলি ব্যৱহাৰ কৰি বাওঁ বা সোঁফালে ছোৱাইপ কৰক।\n\nইয়াৰ বাবে আপুনি কীব’ৰ্ড শ্বৰ্টকাট কাৰ্য + ESC ব্যৱহাৰ কৰিবও পাৰে।"</string>
-    <string name="touchpad_back_gesture_success_title" msgid="7240576648330612171">"বঢ়িয়া!"</string>
+    <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"আপোনাৰ টাচ্চপেডত তিনিটা আঙুলি ব্যৱহাৰ কৰি বাওঁফাললৈ বা সোঁফাললৈ ছোৱাইপ কৰক"</string>
+    <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"সুন্দৰ!"</string>
     <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"আপুনি উভতি যোৱাৰ নিৰ্দেশটো সম্পূৰ্ণ কৰিলে।"</string>
     <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"গৃহ পৃষ্ঠালৈ যাওক"</string>
-    <string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"যিকোনো সময়তে আপোনাৰ গৃহ স্ক্ৰীনলৈ যাবলৈ, আপোনাৰ স্ক্ৰীনখনৰ একেবাৰে তলৰ পৰা ওপৰলৈ তিনিটা আঙুলিৰে ছোৱাইপ কৰক।"</string>
-    <string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"সুন্দৰ!"</string>
-    <string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"আপুনি গৃহ স্ক্ৰীনলৈ উভতি যোৱাৰ নিৰ্দেশটো সম্পূৰ্ণ কৰিলে।"</string>
+    <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"আপোনাৰ টাচ্চপেডৰ তিনিটা আঙুলিৰে ওপৰলৈ ছোৱাইপ কৰক"</string>
+    <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"বঢ়িয়া!"</string>
+    <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"আপুনি গৃহ স্ক্ৰীনলৈ যোৱাৰ নিৰ্দেশটো সম্পূৰ্ণ কৰিলে"</string>
     <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"শেহতীয়া এপ্‌সমূহ চাওক"</string>
-    <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"আপোনাৰ টাচ্চপেডত তিনিটা আঙুলি ব্যৱহাৰ কৰি ওপৰলৈ ছোৱাইপ কৰি কিছু সময় ধৰি ৰাখক।"</string>
+    <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"আপোনাৰ টাচ্চপেডত তিনিটা আঙুলি ব্যৱহাৰ কৰি ওপৰলৈ ছোৱাইপ কৰি ধৰি ৰাখক"</string>
     <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"বঢ়িয়া!"</string>
     <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"আপুনি শেহতীয়া এপ্ চোৱাৰ নিৰ্দেশনাটো সম্পূৰ্ণ কৰিছে।"</string>
-    <string name="tutorial_action_key_title" msgid="2659466586996495447">"কাৰ্য কী"</string>
-    <string name="tutorial_action_key_guidance" msgid="5718948664616999196">"আপোনাৰ এপ্‌সমূহ এক্সেছ কৰিবলৈ আপোনাৰ কীব’ৰ্ডৰ কাৰ্য কীটোত টিপক।"</string>
-    <string name="tutorial_action_key_success_title" msgid="466467860120112933">"অভিনন্দন!"</string>
-    <string name="tutorial_action_key_success_body" msgid="7201991081652850430">"আপুনি কাৰ্য কীৰ নিৰ্দেশটো সম্পূৰ্ণ কৰিলে।\n\nকাৰ্য + /এ আপোনাৰ বাবে উপলব্ধ আটাইবোৰ শ্বৰ্টকাট দেখুৱায়।"</string>
+    <string name="tutorial_action_key_title" msgid="8172535792469008169">"আটাইবোৰ এপ্ চাওক"</string>
+    <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"আপোনাৰ কীব’ৰ্ডৰ কাৰ্য কীটোত টিপক"</string>
+    <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"বঢ়িয়া!"</string>
+    <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"আপুনি আটাইবোৰ এপ্ চোৱাৰ নিৰ্দেশনাটো সম্পূৰ্ণ কৰিছে"</string>
     <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"কীব’ৰ্ডৰ বেকলাইট"</string>
     <string name="keyboard_backlight_value" msgid="7336398765584393538">"%2$dৰ %1$d স্তৰ"</string>
     <string name="home_controls_dream_label" msgid="6567105701292324257">"ঘৰৰ সা-সৰঞ্জামৰ নিয়ন্ত্ৰণ"</string>
@@ -1436,6 +1440,7 @@
     <string name="all_apps_edu_toast_content" msgid="8807496014667211562">"আপোনাৰ আটাইবোৰ এপ্‌ চাবলৈ আপোনাৰ কীব’ৰ্ডৰ কাৰ্য কীটোত টিপক"</string>
     <string name="redacted_notification_single_line_title" msgid="212019960919261670">"সম্পাদনা কৰা হৈছে"</string>
     <string name="redacted_notification_single_line_text" msgid="8684166405005242945">"চাবলৈ আনলক কৰক"</string>
+    <string name="contextual_education_dialog_title" msgid="4630392552837487324">"প্ৰাসংগিক শিক্ষা"</string>
     <string name="back_edu_notification_title" msgid="5624780717751357278">"উভতি যাবলৈ আপোনাৰ টাচ্চপেড ব্যৱহাৰ কৰক"</string>
     <string name="back_edu_notification_content" msgid="2497557451540954068">"তিনিটা আঙুলি ব্যৱহাৰ কৰি বাওঁফাললৈ বা সোঁফাললৈ ছোৱাইপ কৰক। অধিক নিৰ্দেশ শিকিবলৈ টিপক।"</string>
     <string name="home_edu_notification_title" msgid="6097902076909654045">"গৃহপৃষ্ঠালৈ যাবলৈ আপোনাৰ টাচ্চপেড ব্যৱহাৰ কৰক"</string>
diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml
index 551ec5c..6d2ec46 100644
--- a/packages/SystemUI/res/values-az/strings.xml
+++ b/packages/SystemUI/res/values-az/strings.xml
@@ -440,7 +440,7 @@
     <string name="zen_mode_on" msgid="9085304934016242591">"Aktiv"</string>
     <string name="zen_mode_on_with_details" msgid="7416143430557895497">"Aktiv • <xliff:g id="TRIGGER_DESCRIPTION">%1$s</xliff:g>"</string>
     <string name="zen_mode_off" msgid="1736604456618147306">"Deaktiv"</string>
-    <string name="zen_mode_set_up" msgid="7457957033034460064">"Ayarlayın"</string>
+    <string name="zen_mode_set_up" msgid="8231201163894922821">"Ayarlanmayıb"</string>
     <string name="zen_mode_no_manual_invocation" msgid="1769975741344633672">"Ayarlarda idarə edin"</string>
     <string name="zen_mode_active_modes" msgid="1625850411578488856">"{count,plural, =0{Aktiv rejim yoxdur}=1{{mode} aktivdir}other{# rejim aktivdir}}"</string>
     <string name="zen_priority_introduction" msgid="3159291973383796646">"Seçdiyiniz siqnal, xatırladıcı, tədbir və zənglər istisna olmaqla səslər və vibrasiyalar Sizi narahat etməyəcək. Musiqi, video və oyunlar da daxil olmaqla oxutmaq istədiyiniz hər şeyi eşidəcəksiniz."</string>
@@ -573,8 +573,7 @@
     <string name="notification_section_header_conversations" msgid="821834744538345661">"Söhbətlər"</string>
     <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Səssiz bildirişlərin hamısını silin"</string>
     <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Bildirişlər \"Narahat Etməyin\" rejimi tərəfindən dayandırıldı"</string>
-    <!-- no translation found for modes_suppressing_shade_text (6037581130837903239) -->
-    <skip />
+    <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{Bildiriş yoxdur}=1{Bildirişlər {mode} tərəfindən dayandırıldı}=2{Bildirişlər {mode} və digər rejim tərəfindən dayandırıldı}other{Bildirişlər {mode} və # digər rejim tərəfindən dayandırıldı}}"</string>
     <string name="media_projection_action_text" msgid="3634906766918186440">"İndi başlayın"</string>
     <string name="empty_shade_text" msgid="8935967157319717412">"Heç bir bildiriş yoxdur"</string>
     <string name="no_unseen_notif_text" msgid="395512586119868682">"Yeni bildiriş yoxdur"</string>
@@ -673,6 +672,10 @@
     <string name="stream_notification_unavailable" msgid="4313854556205836435">"Zəng səssiz edildiyi üçün əlçatan deyil"</string>
     <string name="stream_alarm_unavailable" msgid="4059817189292197839">"Narahat Etməyin aktiv olduğu üçün əlçatan deyil"</string>
     <string name="stream_media_unavailable" msgid="6823020894438959853">"Narahat Etməyin aktiv olduğu üçün əlçatan deyil"</string>
+    <!-- no translation found for stream_unavailable_by_modes (3674139029490353683) -->
+    <skip />
+    <!-- no translation found for stream_unavailable_by_unknown (6908434629318171588) -->
+    <skip />
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Səsli etmək üçün tıklayın."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Vibrasiyanı ayarlamaq üçün tıklayın. Əlçatımlılıq xidmətləri səssiz edilmiş ola bilər."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Səssiz etmək üçün tıklayın. Əlçatımlılıq xidmətləri səssiz edilmiş ola bilər."</string>
@@ -706,6 +709,7 @@
     <string name="show_demo_mode" msgid="3677956462273059726">"Demo rejimini göstərin"</string>
     <string name="status_bar_ethernet" msgid="5690979758988647484">"Ethernet"</string>
     <string name="status_bar_alarm" msgid="87160847643623352">"Zəngli saat"</string>
+    <string name="active_mode_content_description" msgid="1627555562186515927">"<xliff:g id="MODENAME">%1$s</xliff:g> aktivdir"</string>
     <string name="wallet_title" msgid="5369767670735827105">"Pulqabı"</string>
     <string name="wallet_empty_state_label" msgid="7776761245237530394">"Telefonunuzla daha sürətli və təhlükəsiz satınalmalar etmək üçün ayarlayın"</string>
     <string name="wallet_app_button_label" msgid="7123784239111190992">"Hamısını göstər"</string>
@@ -1405,26 +1409,26 @@
     <string name="launch_touchpad_tutorial_notification_content" msgid="7931085031240753226">"Taçped jestlərini öyrənin"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_title" msgid="1940023776496198762">"Klaviatura və taçpeddən istifadə edərək hərəkət edin"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Taçped jestləri, klaviatura qısayolları və s. haqqında öyrənin"</string>
-    <string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Geri jesti"</string>
-    <string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Əsas ekran jesti"</string>
+    <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"Geri qayıdın"</string>
+    <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Əsas səhifəyə qayıdın"</string>
     <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Son tətbiqlərə baxın"</string>
     <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Hazırdır"</string>
     <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Geri qayıdın"</string>
-    <string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"Geri getmək üçün taçpeddə istənilən yerdə üç barmaqla sola və ya sağa çəkin.\n\nBunun üçün Action + ESC klaviatura qısayolundan da istifadə edə bilərsiniz."</string>
-    <string name="touchpad_back_gesture_success_title" msgid="7240576648330612171">"Əla!"</string>
+    <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"Taçpeddə üç barmaqla sola və ya sağa sürüşdürün"</string>
+    <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"Əla!"</string>
     <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"Geri getmə jestini tamamladınız."</string>
     <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"Ana ekrana qayıdın"</string>
-    <string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"İstənilən vaxt ana ekrana keçmək üçün ekranın aşağısından üç barmağınızla yuxarı çəkin."</string>
-    <string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Əla!"</string>
-    <string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Əsas ekrana keçid jestini tamamladınız."</string>
+    <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"Taçpeddə üç barmaqla yuxarı sürüşdürün"</string>
+    <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"Əla!"</string>
+    <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"Əsas səhifəyə keçid jestini tamamladınız"</string>
     <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"Son tətbiqlərə baxın"</string>
-    <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"Taçpeddə üç barmaq ilə yuxarı çəkib saxlayın."</string>
+    <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"Taçpeddə üç barmaqla yuxarı çəkib saxlayın"</string>
     <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Əla!"</string>
     <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Son tətbiqlərə baxmaq jestini tamamladınız."</string>
-    <string name="tutorial_action_key_title" msgid="2659466586996495447">"Fəaliyyət açarı"</string>
-    <string name="tutorial_action_key_guidance" msgid="5718948664616999196">"Tətbiqlərə daxil olmaq üçün klaviaturada fəaliyyət açarını basın."</string>
-    <string name="tutorial_action_key_success_title" msgid="466467860120112933">"Təbriklər!"</string>
-    <string name="tutorial_action_key_success_body" msgid="7201991081652850430">"Fəaliyyət açarı jestini tamamladınız.\n\nFəaliyyət + / əlçatan bütün qısayolları göstərir."</string>
+    <string name="tutorial_action_key_title" msgid="8172535792469008169">"Bütün tətbiqlərə baxın"</string>
+    <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Klaviaturada fəaliyyət açarına basın"</string>
+    <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Əla!"</string>
+    <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"\"Bütün tətbiqlərə baxın\" jestini tamamladınız"</string>
     <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Klaviatura işığı"</string>
     <string name="keyboard_backlight_value" msgid="7336398765584393538">"Səviyyə %1$d/%2$d"</string>
     <string name="home_controls_dream_label" msgid="6567105701292324257">"Ev nizamlayıcıları"</string>
@@ -1436,6 +1440,7 @@
     <string name="all_apps_edu_toast_content" msgid="8807496014667211562">"Bütün tətbiqlərə baxmaq üçün klaviaturada fəaliyyət açarını basın"</string>
     <string name="redacted_notification_single_line_title" msgid="212019960919261670">"Çıxarılıb"</string>
     <string name="redacted_notification_single_line_text" msgid="8684166405005242945">"Baxmaq üçün kiliddən çıxarın"</string>
+    <string name="contextual_education_dialog_title" msgid="4630392552837487324">"Kontekstual təhsil"</string>
     <string name="back_edu_notification_title" msgid="5624780717751357278">"Geri qayıtmaq üçün taçped istifadə edin"</string>
     <string name="back_edu_notification_content" msgid="2497557451540954068">"Üç barmaqla sola və ya sağa çəkin. Daha çox jest öyrənmək üçün toxunun."</string>
     <string name="home_edu_notification_title" msgid="6097902076909654045">"Ana səhifəyə keçmək üçün taçped istifadə edin"</string>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
index 20dee46..b2a983e 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
@@ -440,7 +440,7 @@
     <string name="zen_mode_on" msgid="9085304934016242591">"Uključeno"</string>
     <string name="zen_mode_on_with_details" msgid="7416143430557895497">"Uklj. • <xliff:g id="TRIGGER_DESCRIPTION">%1$s</xliff:g>"</string>
     <string name="zen_mode_off" msgid="1736604456618147306">"Isključeno"</string>
-    <string name="zen_mode_set_up" msgid="7457957033034460064">"Podesi"</string>
+    <string name="zen_mode_set_up" msgid="8231201163894922821">"Nije podešeno"</string>
     <string name="zen_mode_no_manual_invocation" msgid="1769975741344633672">"Upravljajte u podešavanjima"</string>
     <string name="zen_mode_active_modes" msgid="1625850411578488856">"{count,plural, =0{Nema aktivnih režima}=1{Aktivan je {mode} režim}one{Aktivan je # režim}few{Aktivna su # režima}other{Aktivno je # režima}}"</string>
     <string name="zen_priority_introduction" msgid="3159291973383796646">"Neće vas uznemiravati zvukovi i vibracije osim za alarme, podsetnike, događaje i pozivaoce koje navedete. I dalje ćete čuti sve što odaberete da pustite, uključujući muziku, video snimke i igre."</string>
@@ -573,8 +573,7 @@
     <string name="notification_section_header_conversations" msgid="821834744538345661">"Konverzacije"</string>
     <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Obrišite sva nečujna obaveštenja"</string>
     <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Obaveštenja su pauzirana režimom Ne uznemiravaj"</string>
-    <!-- no translation found for modes_suppressing_shade_text (6037581130837903239) -->
-    <skip />
+    <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{Nema obaveštenja}=1{Obaveštenja je pauzirao {mode}}=2{Obaveštenja su pauzirali {mode} i još jedan režim}one{Obaveštenja su pauzirali {mode} i još # režim}few{Obaveštenja su pauzirali {mode} i još # režima}other{Obaveštenja su pauzirali {mode} i još # režima}}"</string>
     <string name="media_projection_action_text" msgid="3634906766918186440">"Započni"</string>
     <string name="empty_shade_text" msgid="8935967157319717412">"Nema obaveštenja"</string>
     <string name="no_unseen_notif_text" msgid="395512586119868682">"Nema novih obaveštenja"</string>
@@ -673,6 +672,10 @@
     <string name="stream_notification_unavailable" msgid="4313854556205836435">"Nedostupno jer je zvuk isključen"</string>
     <string name="stream_alarm_unavailable" msgid="4059817189292197839">"Nedostupno jer je uključen režim Ne uznemiravaj"</string>
     <string name="stream_media_unavailable" msgid="6823020894438959853">"Nedostupno jer je uključen režim Ne uznemiravaj"</string>
+    <!-- no translation found for stream_unavailable_by_modes (3674139029490353683) -->
+    <skip />
+    <!-- no translation found for stream_unavailable_by_unknown (6908434629318171588) -->
+    <skip />
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Dodirnite da biste uključili zvuk."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Dodirnite da biste podesili na vibraciju. Zvuk usluga pristupačnosti će možda biti isključen."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Dodirnite da biste isključili zvuk. Zvuk usluga pristupačnosti će možda biti isključen."</string>
@@ -706,6 +709,7 @@
     <string name="show_demo_mode" msgid="3677956462273059726">"Prikaži režim demonstracije"</string>
     <string name="status_bar_ethernet" msgid="5690979758988647484">"Eternet"</string>
     <string name="status_bar_alarm" msgid="87160847643623352">"Alarm"</string>
+    <string name="active_mode_content_description" msgid="1627555562186515927">"<xliff:g id="MODENAME">%1$s</xliff:g>: uključeno"</string>
     <string name="wallet_title" msgid="5369767670735827105">"Novčanik"</string>
     <string name="wallet_empty_state_label" msgid="7776761245237530394">"Obavite konfigurisanje da biste mogli brže i sigurnije da kupujete pomoću telefona"</string>
     <string name="wallet_app_button_label" msgid="7123784239111190992">"Prikaži sve"</string>
@@ -1405,26 +1409,26 @@
     <string name="launch_touchpad_tutorial_notification_content" msgid="7931085031240753226">"Naučite pokrete za tačped"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_title" msgid="1940023776496198762">"Krećite se pomoću tastature i tačpeda"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Naučite pokrete za tačped, tasterske prečice i drugo"</string>
-    <string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Pokret za vraćanje"</string>
-    <string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Pokret za početnu stranicu"</string>
+    <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"Nazad"</string>
+    <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Idi na početni ekran"</string>
     <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Prikaži nedavno korišćene aplikacije"</string>
     <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Gotovo"</string>
     <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Nazad"</string>
-    <string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"Da biste se vratili, prevucite ulevo sa tri prsta bilo gde na tačpedu.\n\nMožete da koristite i tastersku prečicu Alt + ESC za ovo."</string>
-    <string name="touchpad_back_gesture_success_title" msgid="7240576648330612171">"Odlično!"</string>
+    <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"Prevucite ulevo ili udesno sa tri prsta na tačpedu"</string>
+    <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"Svaka čast!"</string>
     <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"Dovršili ste pokret za povratak."</string>
     <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"Idi na početni ekran"</string>
-    <string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"Da biste otišli na početni ekran u bilo kom trenutku, prevucite nagore od dna ekrana pomoću tri prsta."</string>
-    <string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Svaka čast!"</string>
-    <string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Dovršili ste pokret za povratak na početnu stranicu."</string>
+    <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"Prevucite nagore sa tri prsta na tačpedu"</string>
+    <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"Odlično!"</string>
+    <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"Dovršili ste pokret za povratak na početnu stranicu."</string>
     <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"Prikaži nedavno korišćene aplikacije"</string>
-    <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"Prevucite nagore i zadržite pomoću tri prsta na tačpedu."</string>
+    <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"Prevucite nagore i zadržite sa tri prsta na tačpedu"</string>
     <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Odlično!"</string>
     <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Dovršili ste pokret za prikazivanje nedavno korišćenih aplikacija."</string>
-    <string name="tutorial_action_key_title" msgid="2659466586996495447">"Taster radnji"</string>
-    <string name="tutorial_action_key_guidance" msgid="5718948664616999196">"Da biste pristupili aplikacijama, pritisnite taster radnji na tastaturi."</string>
-    <string name="tutorial_action_key_success_title" msgid="466467860120112933">"Čestitamo!"</string>
-    <string name="tutorial_action_key_success_body" msgid="7201991081652850430">"Dovršili ste pokret pomoću tastera radnji.\n\nRadnja + / prikazuje sve prečice koje su vam dostupne."</string>
+    <string name="tutorial_action_key_title" msgid="8172535792469008169">"Prikaži sve aplikacije"</string>
+    <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Pritisnite taster radnji na tastaturi"</string>
+    <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Odlično!"</string>
+    <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Dovršili ste pokret za prikazivanje svih aplikacija."</string>
     <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Pozadinsko osvetljenje tastature"</string>
     <string name="keyboard_backlight_value" msgid="7336398765584393538">"%1$d. nivo od %2$d"</string>
     <string name="home_controls_dream_label" msgid="6567105701292324257">"Kontrole za dom"</string>
@@ -1436,6 +1440,7 @@
     <string name="all_apps_edu_toast_content" msgid="8807496014667211562">"Da biste pogledali sve aplikacije, pritisnite taster radnji na tastaturi"</string>
     <string name="redacted_notification_single_line_title" msgid="212019960919261670">"Redigovano"</string>
     <string name="redacted_notification_single_line_text" msgid="8684166405005242945">"Otključajte za prikaz"</string>
+    <string name="contextual_education_dialog_title" msgid="4630392552837487324">"Kontekstualno obrazovanje"</string>
     <string name="back_edu_notification_title" msgid="5624780717751357278">"Koristite tačped da biste se vratili"</string>
     <string name="back_edu_notification_content" msgid="2497557451540954068">"Prevucite ulevo ili udesno sa tri prsta. Dodirnite da biste videli više pokreta."</string>
     <string name="home_edu_notification_title" msgid="6097902076909654045">"Koristite tačped da biste otišli na početni ekran"</string>
diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml
index ba0a8b4..a0e536b 100644
--- a/packages/SystemUI/res/values-be/strings.xml
+++ b/packages/SystemUI/res/values-be/strings.xml
@@ -440,7 +440,7 @@
     <string name="zen_mode_on" msgid="9085304934016242591">"Уключана"</string>
     <string name="zen_mode_on_with_details" msgid="7416143430557895497">"Уключана • <xliff:g id="TRIGGER_DESCRIPTION">%1$s</xliff:g>"</string>
     <string name="zen_mode_off" msgid="1736604456618147306">"Выключана"</string>
-    <string name="zen_mode_set_up" msgid="7457957033034460064">"Наладзіць"</string>
+    <string name="zen_mode_set_up" msgid="8231201163894922821">"Не зададзена"</string>
     <string name="zen_mode_no_manual_invocation" msgid="1769975741344633672">"Адкрыць налады"</string>
     <string name="zen_mode_active_modes" msgid="1625850411578488856">"{count,plural, =0{Актыўных рэжымаў няма}=1{Рэжым \"{mode}\" актыўны}one{# рэжым актыўны}few{# рэжымы актыўныя}many{# рэжымаў актыўныя}other{# рэжыму актыўныя}}"</string>
     <string name="zen_priority_introduction" msgid="3159291973383796646">"Вас не будуць турбаваць гукі і вібрацыя, за выключэннем будзільнікаў, напамінаў, падзей і выбраных вамі абанентаў. Вы будзеце чуць усё, што ўключыце, у тым ліку музыку, відэа і гульні."</string>
@@ -573,8 +573,7 @@
     <string name="notification_section_header_conversations" msgid="821834744538345661">"Размовы"</string>
     <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Выдаліць усе апавяшчэнні без гуку"</string>
     <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Паказ апавяшчэнняў прыпынены ў рэжыме \"Не турбаваць\""</string>
-    <!-- no translation found for modes_suppressing_shade_text (6037581130837903239) -->
-    <skip />
+    <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{Апавяшчэнняў няма}=1{Атрыманне апавяшчэнняў прыпынена рэжымам \"{mode}\"}=2{Атрыманне апавяшчэнняў прыпынена рэжымам \"{mode}\" і яшчэ адным рэжымам}one{Атрыманне апавяшчэнняў прыпынена рэжымам \"{mode}\" і яшчэ # рэжымам}few{Атрыманне апавяшчэнняў прыпынена рэжымам \"{mode}\" і яшчэ # рэжымамі}many{Атрыманне апавяшчэнняў прыпынена рэжымам \"{mode}\" і яшчэ # рэжымамі}other{Атрыманне апавяшчэнняў прыпынена рэжымам \"{mode}\" і яшчэ # рэжыму}}"</string>
     <string name="media_projection_action_text" msgid="3634906766918186440">"Пачаць зараз"</string>
     <string name="empty_shade_text" msgid="8935967157319717412">"Апавяшчэнняў няма"</string>
     <string name="no_unseen_notif_text" msgid="395512586119868682">"Няма новых апавяшчэнняў"</string>
@@ -673,6 +672,10 @@
     <string name="stream_notification_unavailable" msgid="4313854556205836435">"Недаступна, бо выключаны гук выклікаў"</string>
     <string name="stream_alarm_unavailable" msgid="4059817189292197839">"Недаступна, бо ўключаны рэжым \"Не турбаваць\""</string>
     <string name="stream_media_unavailable" msgid="6823020894438959853">"Недаступна, бо ўключаны рэжым \"Не турбаваць\""</string>
+    <!-- no translation found for stream_unavailable_by_modes (3674139029490353683) -->
+    <skip />
+    <!-- no translation found for stream_unavailable_by_unknown (6908434629318171588) -->
+    <skip />
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Дакраніцеся, каб уключыць гук."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Дакраніцеся, каб уключыць вібрацыю. Можа быць адключаны гук службаў спецыяльных магчымасцей."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Дакраніцеся, каб адключыць гук. Можа быць адключаны гук службаў спецыяльных магчымасцей."</string>
@@ -706,6 +709,7 @@
     <string name="show_demo_mode" msgid="3677956462273059726">"Паказваць дэманстрацыйны рэжым"</string>
     <string name="status_bar_ethernet" msgid="5690979758988647484">"Ethernet"</string>
     <string name="status_bar_alarm" msgid="87160847643623352">"Будзільнік"</string>
+    <string name="active_mode_content_description" msgid="1627555562186515927">"Уключаны рэжым \"<xliff:g id="MODENAME">%1$s</xliff:g>\""</string>
     <string name="wallet_title" msgid="5369767670735827105">"Кашалёк"</string>
     <string name="wallet_empty_state_label" msgid="7776761245237530394">"Наладзьце картку, каб рабіць больш хуткія і бяспечныя куплі з дапамогай тэлефона"</string>
     <string name="wallet_app_button_label" msgid="7123784239111190992">"Паказаць усе"</string>
@@ -1405,26 +1409,26 @@
     <string name="launch_touchpad_tutorial_notification_content" msgid="7931085031240753226">"Азнаёмцеся з жэстамі для сэнсарнай панэлі"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_title" msgid="1940023776496198762">"Навігацыя з дапамогай клавіятуры і сэнсарнай панэлі"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Азнаёмцеся з жэстамі для сэнсарнай панэлі, спалучэннямі клавіш і г. д."</string>
-    <string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Жэст для вяртання на папярэдні экран"</string>
-    <string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Жэст для вяртання на галоўны экран"</string>
+    <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"Назад"</string>
+    <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"На галоўную старонку"</string>
     <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Прагляд нядаўніх праграм"</string>
     <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Гатова"</string>
     <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Назад"</string>
-    <string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"Каб вярнуцца, правядзіце трыма пальцамі ўлева ці ўправа ў любым месцы сэнсарнай панэлі.\n\nТаксама можна выкарыстоўваць спалучэнне \"клавіша дзеяння + ESC\"."</string>
-    <string name="touchpad_back_gesture_success_title" msgid="7240576648330612171">"Выдатная праца!"</string>
+    <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"Правядзіце па сэнсарнай панэлі трыма пальцамі ўлева ці ўправа"</string>
+    <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"Выдатна!"</string>
     <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"Вы навучыліся рабіць жэст вяртання."</string>
     <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"На галоўны экран"</string>
-    <string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"Каб у любы момант перайсці на галоўны экран, правядзіце па экране трыма пальцамі знізу ўверх."</string>
-    <string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Выдатна!"</string>
-    <string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Вы навучыліся рабіць жэст для пераходу на галоўны экран."</string>
+    <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"Правядзіце па сэнсарнай панэлі трыма пальцамі ўверх"</string>
+    <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"Выдатная праца!"</string>
+    <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"Вы навучыліся рабіць жэст для пераходу на галоўны экран"</string>
     <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"Прагляд нядаўніх праграм"</string>
-    <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"Правядзіце па сэнсарнай панэлі трыма пальцамі ўверх і затрымайце пальцы."</string>
+    <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"Правядзіце па сэнсарнай панэлі трыма пальцамі ўверх і затрымайце пальцы"</string>
     <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Выдатная праца!"</string>
     <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Вы скончылі вывучэнне жэсту для прагляду нядаўніх праграм."</string>
-    <string name="tutorial_action_key_title" msgid="2659466586996495447">"Клавіша дзеяння"</string>
-    <string name="tutorial_action_key_guidance" msgid="5718948664616999196">"Каб атрымаць доступ да праграм, націсніце клавішу дзеяння на клавіятуры."</string>
-    <string name="tutorial_action_key_success_title" msgid="466467860120112933">"Віншуем!"</string>
-    <string name="tutorial_action_key_success_body" msgid="7201991081652850430">"Вы навучыліся рабіць жэст з клавішай дзеяння.\n\nКалі націснуць клавішу дзеяння разам з \"/\", будуць паказаны ўсе даступныя спалучэнні клавіш."</string>
+    <string name="tutorial_action_key_title" msgid="8172535792469008169">"Глядзець усе праграмы"</string>
+    <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Націсніце клавішу дзеяння на клавіятуры"</string>
+    <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Выдатна!"</string>
+    <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Вы навучыліся рабіць жэст для прагляду ўсіх праграм"</string>
     <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Падсветка клавіятуры"</string>
     <string name="keyboard_backlight_value" msgid="7336398765584393538">"Узровень %1$d з %2$d"</string>
     <string name="home_controls_dream_label" msgid="6567105701292324257">"Кіраванне домам"</string>
@@ -1436,6 +1440,7 @@
     <string name="all_apps_edu_toast_content" msgid="8807496014667211562">"Каб праглядзець усе праграмы, націсніце на клавішу дзеяння на клавіятуры"</string>
     <string name="redacted_notification_single_line_title" msgid="212019960919261670">"Схавана"</string>
     <string name="redacted_notification_single_line_text" msgid="8684166405005242945">"Разблакіруйце экран, каб праглядзець"</string>
+    <string name="contextual_education_dialog_title" msgid="4630392552837487324">"Кантэкстнае навучанне"</string>
     <string name="back_edu_notification_title" msgid="5624780717751357278">"Выкарыстайце сэнсарную панэль для вяртання"</string>
     <string name="back_edu_notification_content" msgid="2497557451540954068">"Правядзіце ўлева ці ўправа трыма пальцамі. Націсніце, каб азнаёміцца з іншымі жэстамі."</string>
     <string name="home_edu_notification_title" msgid="6097902076909654045">"Выкарыстайце сэнсарную панэль для вяртання на галоўны экран"</string>
@@ -1445,7 +1450,7 @@
     <string name="all_apps_edu_notification_title" msgid="372262997265569063">"Выкарыстайце клавіятуру для прагляду ўсіх праграм"</string>
     <string name="all_apps_edu_notification_content" msgid="3255070575694025585">"Можна націснуць на клавішу дзеяння ў любы момант. Націсніце, каб азнаёміцца з іншымі жэстамі."</string>
     <string name="accessibility_deprecate_extra_dim_dialog_title" msgid="910988771011857460">"Цяпер кіраваць дадатковым памяншэннем яркасці можна з дапамогай паўзунка яркасці"</string>
-    <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="4453123359258743230">"Цяпер вы можаце дадаткова зацямніць экран, яшчэ больш панізіўшы ўзровень яркасці.\n\nПаколькі гэта функцыя цяпер уваходзіць у склад паўзунка яркасці, хуткія каманды для дадатковага памяншэння яркасці былі выдалены."</string>
+    <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="4453123359258743230">"Цяпер вы можаце дадаткова зацямніць экран, яшчэ больш панізіўшы ўзровень яркасці.\n\nПаколькі гэта функцыя цяпер уваходзіць у склад паўзунка яркасці, хуткія каманды для дадатковага памяншэння яркасці будуць выдалены."</string>
     <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="3947537827396916005">"Выдаліць хуткія каманды для дадатковага памяншэння яркасці"</string>
     <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="165474092660941104">"Хуткія каманды для дадатковага памяншэння яркасці выдалены"</string>
     <string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"Магчымасць падключэння"</string>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index bf558eb..1702b83 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -440,7 +440,7 @@
     <string name="zen_mode_on" msgid="9085304934016242591">"Вкл."</string>
     <string name="zen_mode_on_with_details" msgid="7416143430557895497">"Вкл. • <xliff:g id="TRIGGER_DESCRIPTION">%1$s</xliff:g>"</string>
     <string name="zen_mode_off" msgid="1736604456618147306">"Изкл."</string>
-    <string name="zen_mode_set_up" msgid="7457957033034460064">"Настройване"</string>
+    <string name="zen_mode_set_up" msgid="8231201163894922821">"Не е зададено"</string>
     <string name="zen_mode_no_manual_invocation" msgid="1769975741344633672">"Управление от настройките"</string>
     <string name="zen_mode_active_modes" msgid="1625850411578488856">"{count,plural, =0{Няма активни режими}=1{Режимът „{mode}“ е активен}other{# активни режима}}"</string>
     <string name="zen_priority_introduction" msgid="3159291973383796646">"Няма да бъдете обезпокоявани от звуци и вибрирания освен от будилници, напомняния, събития и обаждания от посочени от вас контакти. Пак ще чувате всичко, което изберете да се пусне, включително музика, видеоклипове и игри."</string>
@@ -573,8 +573,7 @@
     <string name="notification_section_header_conversations" msgid="821834744538345661">"Разговори"</string>
     <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Изчистване на всички беззвучни известия"</string>
     <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Известията са поставени на пауза от режима „Не безпокойте“"</string>
-    <!-- no translation found for modes_suppressing_shade_text (6037581130837903239) -->
-    <skip />
+    <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{Няма известия}=1{Известията са поставени на пауза от {mode}}=2{Известията са поставени на пауза от {mode} и един друг режим}other{Известията са поставени на пауза от {mode} и # други режима}}"</string>
     <string name="media_projection_action_text" msgid="3634906766918186440">"Стартиране сега"</string>
     <string name="empty_shade_text" msgid="8935967157319717412">"Няма известия"</string>
     <string name="no_unseen_notif_text" msgid="395512586119868682">"Няма нови известия"</string>
@@ -673,6 +672,10 @@
     <string name="stream_notification_unavailable" msgid="4313854556205836435">"Не е налице, защото звъненето е спряно"</string>
     <string name="stream_alarm_unavailable" msgid="4059817189292197839">"Не е налице, защото режимът „Не безпокойте“ е вкл."</string>
     <string name="stream_media_unavailable" msgid="6823020894438959853">"Не е налице, защото „Не безпокойте“ е вкл."</string>
+    <!-- no translation found for stream_unavailable_by_modes (3674139029490353683) -->
+    <skip />
+    <!-- no translation found for stream_unavailable_by_unknown (6908434629318171588) -->
+    <skip />
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Докоснете, за да включите отново звука."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Докоснете, за да зададете вибриране. Възможно е звукът на услугите за достъпност да бъде заглушен."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Докоснете, за да заглушите звука. Възможно е звукът на услугите за достъпност да бъде заглушен."</string>
@@ -706,6 +709,7 @@
     <string name="show_demo_mode" msgid="3677956462273059726">"Показване на демонстрационния режим"</string>
     <string name="status_bar_ethernet" msgid="5690979758988647484">"Ethernet"</string>
     <string name="status_bar_alarm" msgid="87160847643623352">"Будилник"</string>
+    <string name="active_mode_content_description" msgid="1627555562186515927">"Режимът „<xliff:g id="MODENAME">%1$s</xliff:g>“ е включен"</string>
     <string name="wallet_title" msgid="5369767670735827105">"Портфейл"</string>
     <string name="wallet_empty_state_label" msgid="7776761245237530394">"Купувайте по-бързо и по-сигурно с телефона си"</string>
     <string name="wallet_app_button_label" msgid="7123784239111190992">"Показване на всички"</string>
@@ -1405,26 +1409,26 @@
     <string name="launch_touchpad_tutorial_notification_content" msgid="7931085031240753226">"Научете за жестовете със сензорния панел"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_title" msgid="1940023776496198762">"Навигирайте посредством клавиатурата и сензорния панел"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Научете за жестовете със сензорния панел, клавишните комбинации и др."</string>
-    <string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Жест за връщане назад"</string>
-    <string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Жест за преминаване към началния екран"</string>
+    <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"Назад"</string>
+    <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Към началния екран"</string>
     <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Преглед на скорошните приложения"</string>
     <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Готово"</string>
     <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Назад"</string>
-    <string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"За да се върнете назад, прекарайте три пръста наляво или надясно по сензорния панел.\n\nЗа целта можете също да използвате комбинацията с клавиша за действия + ESC."</string>
-    <string name="touchpad_back_gesture_success_title" msgid="7240576648330612171">"Отлично!"</string>
+    <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"Прекарайте три пръста наляво или надясно по сензорния панел"</string>
+    <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"Чудесно!"</string>
     <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"Изпълнихте жеста за връщане назад."</string>
     <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"Към началния екран"</string>
-    <string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"За да преминете към началния екран по всяко време, прекарайте три пръста нагоре от долната част на екрана."</string>
-    <string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Чудесно!"</string>
-    <string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Изпълнихте жеста за преминаване към началния екран."</string>
+    <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"Прекарайте три пръста нагоре по сензорния панел"</string>
+    <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"Отлично!"</string>
+    <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"Изпълнихте жеста за преминаване към началния екран"</string>
     <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"Преглед на скорошните приложения"</string>
-    <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"Плъзнете нагоре с три пръста по сензорния панел и задръжте."</string>
+    <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"Прекарайте три пръста нагоре по сензорния панел и задръжте"</string>
     <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Отлично!"</string>
     <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Изпълнихте жеста за преглед на скорошните приложения."</string>
-    <string name="tutorial_action_key_title" msgid="2659466586996495447">"Клавиш за действия"</string>
-    <string name="tutorial_action_key_guidance" msgid="5718948664616999196">"За да осъществите достъп до приложенията, натиснете клавиша за действия на клавиатурата си."</string>
-    <string name="tutorial_action_key_success_title" msgid="466467860120112933">"Поздравления!"</string>
-    <string name="tutorial_action_key_success_body" msgid="7201991081652850430">"Изпълнихте жеста с клавиша за действия.\n\nНатискането на клавиша за действия и / показва всички налични клавишни комбинации."</string>
+    <string name="tutorial_action_key_title" msgid="8172535792469008169">"Преглед на всички приложения"</string>
+    <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Натиснете клавиша за действия на клавиатурата си"</string>
+    <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Браво!"</string>
+    <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Изпълнихте жеста за преглед на всички приложения"</string>
     <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Подсветка на клавиатурата"</string>
     <string name="keyboard_backlight_value" msgid="7336398765584393538">"Ниво %1$d от %2$d"</string>
     <string name="home_controls_dream_label" msgid="6567105701292324257">"Контроли за дома"</string>
@@ -1436,6 +1440,7 @@
     <string name="all_apps_edu_toast_content" msgid="8807496014667211562">"За да прегледате всичките си приложения, натиснете клавиша за действия на клавиатурата си"</string>
     <string name="redacted_notification_single_line_title" msgid="212019960919261670">"Скрито"</string>
     <string name="redacted_notification_single_line_text" msgid="8684166405005242945">"Отключете за преглед"</string>
+    <string name="contextual_education_dialog_title" msgid="4630392552837487324">"Контекстуално обучение"</string>
     <string name="back_edu_notification_title" msgid="5624780717751357278">"Използвайте сензорния панел, за да се върнете назад"</string>
     <string name="back_edu_notification_content" msgid="2497557451540954068">"Плъзнете три пръста наляво или надясно. Докоснете, за да научите повече жестове."</string>
     <string name="home_edu_notification_title" msgid="6097902076909654045">"Използвайте сензорния панел, за да преминете към началния екран"</string>
diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml
index cf55feb..a36fe05 100644
--- a/packages/SystemUI/res/values-bn/strings.xml
+++ b/packages/SystemUI/res/values-bn/strings.xml
@@ -440,7 +440,8 @@
     <string name="zen_mode_on" msgid="9085304934016242591">"চালু আছে"</string>
     <string name="zen_mode_on_with_details" msgid="7416143430557895497">"চালু আছে • <xliff:g id="TRIGGER_DESCRIPTION">%1$s</xliff:g>"</string>
     <string name="zen_mode_off" msgid="1736604456618147306">"বন্ধ আছে"</string>
-    <string name="zen_mode_set_up" msgid="7457957033034460064">"সেট-আপ করুন"</string>
+    <!-- no translation found for zen_mode_set_up (8231201163894922821) -->
+    <skip />
     <string name="zen_mode_no_manual_invocation" msgid="1769975741344633672">"সেটিংসে গিয়ে ম্যানেজ করুন"</string>
     <string name="zen_mode_active_modes" msgid="1625850411578488856">"{count,plural, =0{কোনও মোড চালু নেই}=1{{mode} চালু আছে}one{# মোড চালু আছে}other{# মোড চালু আছে}}"</string>
     <string name="zen_priority_introduction" msgid="3159291973383796646">"অ্যালার্ম, রিমাইন্ডার, ইভেন্ট, এবং আপনার নির্দিষ্ট করে দেওয়া ব্যক্তিদের কল ছাড়া অন্য কোনও আওয়াজ বা ভাইব্রেশন হবে না। তবে সঙ্গীত, ভিডিও, এবং গেম সহ আপনি যা কিছু চালাবেন তার আওয়াজ শুনতে পাবেন।"</string>
@@ -573,8 +574,7 @@
     <string name="notification_section_header_conversations" msgid="821834744538345661">"কথোপকথন"</string>
     <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"সব নীরব বিজ্ঞপ্তি মুছুন"</string>
     <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"\'বিরক্ত করবে না\' দিয়ে বিজ্ঞপ্তি পজ করা হয়েছে"</string>
-    <!-- no translation found for modes_suppressing_shade_text (6037581130837903239) -->
-    <skip />
+    <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{কোনও বিজ্ঞপ্তি নেই}=1{{mode}-এর জন্য বিজ্ঞপ্তি পজ করা হয়েছে}=2{{mode} ও অন্য আরেকটি মোডের জন্য বিজ্ঞপ্তি পজ করা হয়েছে}one{{mode} ও অন্য #টি মোডের জন্য বিজ্ঞপ্তি পজ করা হয়েছে}other{{mode} ও অন্য #টি মোডের জন্য বিজ্ঞপ্তি পজ করা হয়েছে}}"</string>
     <string name="media_projection_action_text" msgid="3634906766918186440">"এখন শুরু করুন"</string>
     <string name="empty_shade_text" msgid="8935967157319717412">"কোনও বিজ্ঞপ্তি নেই"</string>
     <string name="no_unseen_notif_text" msgid="395512586119868682">"নতুন কোনও বিজ্ঞপ্তি নেই"</string>
@@ -673,6 +673,10 @@
     <string name="stream_notification_unavailable" msgid="4313854556205836435">"রিং মিউট করা হয়েছে বলে উপলভ্য নেই"</string>
     <string name="stream_alarm_unavailable" msgid="4059817189292197839">"\'বিরক্ত করবে না\' মোড চালু থাকার জন্য উপলভ্য নেই"</string>
     <string name="stream_media_unavailable" msgid="6823020894438959853">"\'বিরক্ত করবে না\' মোড চালু থাকার জন্য উপলভ্য নেই"</string>
+    <!-- no translation found for stream_unavailable_by_modes (3674139029490353683) -->
+    <skip />
+    <!-- no translation found for stream_unavailable_by_unknown (6908434629318171588) -->
+    <skip />
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s। সশব্দ করতে আলতো চাপুন।"</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s। কম্পন এ সেট করতে আলতো চাপুন। অ্যাক্সেসযোগ্যতার পরিষেবাগুলিকে মিউট করা হতে পারে।"</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s। মিউট করতে আলতো চাপুন। অ্যাক্সেসযোগ্যতার পরিষেবাগুলিকে মিউট করা হতে পারে।"</string>
@@ -706,6 +710,7 @@
     <string name="show_demo_mode" msgid="3677956462273059726">"ডেমো মোড দেখান"</string>
     <string name="status_bar_ethernet" msgid="5690979758988647484">"ইথারনেট"</string>
     <string name="status_bar_alarm" msgid="87160847643623352">"অ্যালার্ম"</string>
+    <string name="active_mode_content_description" msgid="1627555562186515927">"<xliff:g id="MODENAME">%1$s</xliff:g> চালু আছে"</string>
     <string name="wallet_title" msgid="5369767670735827105">"Wallet"</string>
     <string name="wallet_empty_state_label" msgid="7776761245237530394">"ফোন ব্যবহার করে আরও দ্রুত ও আরও নিরাপদে কেনাকাটা করার জন্য সেট-আপ করুন"</string>
     <string name="wallet_app_button_label" msgid="7123784239111190992">"সবকটি দেখুন"</string>
@@ -1405,26 +1410,38 @@
     <string name="launch_touchpad_tutorial_notification_content" msgid="7931085031240753226">"টাচপ্যাডের জেসচার সম্পর্কে জানুন"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_title" msgid="1940023776496198762">"আপনার কীবোর্ড এবং টাচপ্যাড ব্যবহার করে নেভিগেট করুন"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"টাচপ্যাড জেসচার, কীবোর্ড শর্টকাট এবং আরও অনেক কিছু সম্পর্কে জানুন"</string>
-    <string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"ফিরে যাওয়ার জেসচার"</string>
-    <string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"হোমপেজে যাওয়ার জেসচার"</string>
+    <!-- no translation found for touchpad_tutorial_back_gesture_button (3104716365403620315) -->
+    <skip />
+    <!-- no translation found for touchpad_tutorial_home_gesture_button (8023973153559885624) -->
+    <skip />
     <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"সম্প্রতি ব্যবহার করা হয়েছে এমন অ্যাপ দেখুন"</string>
     <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"হয়ে গেছে"</string>
     <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"ফিরে যান"</string>
-    <string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"ফিরে যেতে, টাচপ্যাডে যেকোনও জায়গায় তিনটি আঙুল দিয়ে বাঁদিক বা ডানদিকে সোয়াইপ করুন।\n\nএছাড়া, এটির জন্য আপনি কীবোর্ড শর্টকাট অ্যাকশন + ESC বোতাম প্রেস করতে পারবেন।"</string>
-    <string name="touchpad_back_gesture_success_title" msgid="7240576648330612171">"অসাধারণ!"</string>
+    <!-- no translation found for touchpad_back_gesture_guidance (5352221087725906542) -->
+    <skip />
+    <!-- no translation found for touchpad_back_gesture_success_title (7370719098633023496) -->
+    <skip />
     <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"জেসচার ব্যবহার করে কীভাবে ফিরে যাওয়া যায় সেই সম্পর্কে আপনি জেনেছেন।"</string>
     <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"হোমে যান"</string>
-    <string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"যেকোনও সময়ে আপনার হোম স্ক্রিনে যেতে, আপনার স্ক্রিনের একদম নিচের থেকে তিনটি আঙুল দিয়ে উপরের দিকে সোয়াইপ করুন।"</string>
-    <string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"সাবাস!"</string>
-    <string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"জেসচার ব্যবহার করে কীভাবে হোমে ফিরে যাওয়া যায় সেই সম্পর্কে আপনি জেনেছেন।"</string>
+    <!-- no translation found for touchpad_home_gesture_guidance (4178219118381915899) -->
+    <skip />
+    <!-- no translation found for touchpad_home_gesture_success_title (3648264553645798470) -->
+    <skip />
+    <!-- no translation found for touchpad_home_gesture_success_body (2590690589194027059) -->
+    <skip />
     <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"সম্প্রতি ব্যবহার করা হয়েছে এমন অ্যাপ দেখুন"</string>
-    <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"আপনার টাচপ্যাডে তিনটি আঙুল ব্যবহার করে উপরের দিকে সোয়াইপ করে ধরে রাখুন।"</string>
+    <!-- no translation found for touchpad_recent_apps_gesture_guidance (6304446013842271822) -->
+    <skip />
     <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"অসাধারণ!"</string>
     <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"সম্প্রতি ব্যবহার করা হয়েছে এমন অ্যাপের জেসচার দেখা সম্পূর্ণ করেছেন।"</string>
-    <string name="tutorial_action_key_title" msgid="2659466586996495447">"অ্যাকশন কী"</string>
-    <string name="tutorial_action_key_guidance" msgid="5718948664616999196">"আপনার অ্যাপ অ্যাক্সেস করতে, কীবোর্ডে অ্যাকশন কী প্রেস করুন"</string>
-    <string name="tutorial_action_key_success_title" msgid="466467860120112933">"অভিনন্দন!"</string>
-    <string name="tutorial_action_key_success_body" msgid="7201991081652850430">"অ্যাকশন কী জেসচার সম্পর্কে আপনি জেনেছেন।\n\nঅ্যাকশন + / প্রেস করলে আপনার কাছে উপলভ্য থাকা সব শর্টকাট দেখতে পাবেন।"</string>
+    <!-- no translation found for tutorial_action_key_title (8172535792469008169) -->
+    <skip />
+    <!-- no translation found for tutorial_action_key_guidance (5040613427202799294) -->
+    <skip />
+    <!-- no translation found for tutorial_action_key_success_title (2371827347071979571) -->
+    <skip />
+    <!-- no translation found for tutorial_action_key_success_body (1688986269491357832) -->
+    <skip />
     <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"কীবোর্ড ব্যাকলাইট"</string>
     <string name="keyboard_backlight_value" msgid="7336398765584393538">"%2$d-এর মধ্যে %1$d লেভেল"</string>
     <string name="home_controls_dream_label" msgid="6567105701292324257">"হোম কন্ট্রোল"</string>
@@ -1436,6 +1453,7 @@
     <string name="all_apps_edu_toast_content" msgid="8807496014667211562">"আপনার সব অ্যাপ দেখতে, কীবোর্ডে অ্যাকশন কী প্রেস করুন"</string>
     <string name="redacted_notification_single_line_title" msgid="212019960919261670">"রিড্যাক্ট করা হয়েছে"</string>
     <string name="redacted_notification_single_line_text" msgid="8684166405005242945">"দেখার জন্য আনলক করুন"</string>
+    <string name="contextual_education_dialog_title" msgid="4630392552837487324">"প্রাসঙ্গিক শিক্ষা"</string>
     <string name="back_edu_notification_title" msgid="5624780717751357278">"ফিরে যেতে টাচপ্যাড ব্যবহার করুন"</string>
     <string name="back_edu_notification_content" msgid="2497557451540954068">"তিনটি আঙুলের ব্যবহার করে ডান বা বাঁদিকে সোয়াইপ করুন। আরও জেসচার সম্পর্কে জানতে ট্যাপ করুন।"</string>
     <string name="home_edu_notification_title" msgid="6097902076909654045">"হোমে যেতে টাচপ্যাড ব্যবহার করুন"</string>
@@ -1450,7 +1468,7 @@
     <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="165474092660941104">"\'অতিরিক্ত কম ব্রাইটনেস\' ফিচারের শর্টকাট সরানো হয়েছে"</string>
     <string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"কানেক্টিভিটি"</string>
     <string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"অ্যাক্সেসিবিলিটি"</string>
-    <string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"উপযোগিতা"</string>
+    <string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"ইউটিলিটি"</string>
     <string name="qs_edit_mode_category_privacy" msgid="6577774443194551775">"গোপনীয়তা"</string>
     <string name="qs_edit_mode_category_providedByApps" msgid="8346112074897919019">"অ্যাপের তরফ থেকে দেওয়া"</string>
     <string name="qs_edit_mode_category_display" msgid="4749511439121053942">"ডিসপ্লে"</string>
diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml
index 679bece..13a933e 100644
--- a/packages/SystemUI/res/values-bs/strings.xml
+++ b/packages/SystemUI/res/values-bs/strings.xml
@@ -440,7 +440,7 @@
     <string name="zen_mode_on" msgid="9085304934016242591">"Uključeno"</string>
     <string name="zen_mode_on_with_details" msgid="7416143430557895497">"Uključeno • <xliff:g id="TRIGGER_DESCRIPTION">%1$s</xliff:g>"</string>
     <string name="zen_mode_off" msgid="1736604456618147306">"Isključeno"</string>
-    <string name="zen_mode_set_up" msgid="7457957033034460064">"Postavite"</string>
+    <string name="zen_mode_set_up" msgid="8231201163894922821">"Nije postavljeno"</string>
     <string name="zen_mode_no_manual_invocation" msgid="1769975741344633672">"Upravljajte opcijom u postavkama"</string>
     <string name="zen_mode_active_modes" msgid="1625850411578488856">"{count,plural, =0{Nema aktivnih načina rada}=1{Način rada {mode} je aktivan}one{# način rada je aktivan}few{# načina rada su aktivna}other{# načina rada je aktivno}}"</string>
     <string name="zen_priority_introduction" msgid="3159291973383796646">"Neće vas ometati zvukovi i vibracije, osim alarma, podsjetnika, događaja i pozivalaca koje odredite. I dalje ćete čuti sve što ste odabrali za reprodukciju, uključujući muziku, videozapise i igre."</string>
@@ -573,8 +573,7 @@
     <string name="notification_section_header_conversations" msgid="821834744538345661">"Razgovori"</string>
     <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Obriši sva nečujna obavještenja"</string>
     <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Obavještenja su pauzirana načinom rada Ne ometaj"</string>
-    <!-- no translation found for modes_suppressing_shade_text (6037581130837903239) -->
-    <skip />
+    <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{Nema obavještenja}=1{Obavještenja su pauzirana putem načina rada {mode}}=2{Obavještenja su pauzirana putem načina rada {mode} i još jednog načina rada}one{Obavještenja su pauzirana putem načina rada {mode} i još # načina rada}few{Obavještenja su pauzirana putem načina rada {mode} i još # načina rada}other{Obavještenja su pauzirana putem načina rada {mode} i još # načina rada}}"</string>
     <string name="media_projection_action_text" msgid="3634906766918186440">"Započni odmah"</string>
     <string name="empty_shade_text" msgid="8935967157319717412">"Nema obavještenja"</string>
     <string name="no_unseen_notif_text" msgid="395512586119868682">"Nema novih obavještenja"</string>
@@ -673,6 +672,10 @@
     <string name="stream_notification_unavailable" msgid="4313854556205836435">"Nedostupno zbog isključenog zvona"</string>
     <string name="stream_alarm_unavailable" msgid="4059817189292197839">"Nedostupno jer je funkcija Ne ometaj uključena"</string>
     <string name="stream_media_unavailable" msgid="6823020894438959853">"Nedostupno jer je funkcija Ne ometaj uključena"</string>
+    <!-- no translation found for stream_unavailable_by_modes (3674139029490353683) -->
+    <skip />
+    <!-- no translation found for stream_unavailable_by_unknown (6908434629318171588) -->
+    <skip />
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Dodirnite da uključite zvukove."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Dodirnite za postavljanje vibracije. Zvukovi usluga pristupačnosti mogu biti isključeni."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Dodirnite da isključite zvuk. Zvukovi usluga pristupačnosti mogu biti isključeni."</string>
@@ -706,6 +709,7 @@
     <string name="show_demo_mode" msgid="3677956462273059726">"Prikaži način rada za demonstraciju"</string>
     <string name="status_bar_ethernet" msgid="5690979758988647484">"Ethernet"</string>
     <string name="status_bar_alarm" msgid="87160847643623352">"Alarm"</string>
+    <string name="active_mode_content_description" msgid="1627555562186515927">"Način rada <xliff:g id="MODENAME">%1$s</xliff:g> je uključen"</string>
     <string name="wallet_title" msgid="5369767670735827105">"Novčanik"</string>
     <string name="wallet_empty_state_label" msgid="7776761245237530394">"Postavite aplikaciju za brže i sigurnije kupovine putem telefona"</string>
     <string name="wallet_app_button_label" msgid="7123784239111190992">"Prikaži sve"</string>
@@ -1405,26 +1409,26 @@
     <string name="launch_touchpad_tutorial_notification_content" msgid="7931085031240753226">"Saznajte više o pokretima na dodirnoj podlozi"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_title" msgid="1940023776496198762">"Krećite se pomoću tastature i dodirne podloge"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Saznajte više o pokretima na dodirnoj podlozi, prečicama tastature i drugim opcijama"</string>
-    <string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Pokret za povratak"</string>
-    <string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Pokret za povratak na početni ekran"</string>
+    <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"Nazad"</string>
+    <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Odlazak na početni ekran"</string>
     <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Prikaži nedavne aplikacije"</string>
     <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Gotovo"</string>
     <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Nazad"</string>
-    <string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"Da se vratite, prevucite ulijevo ili udesno s tri prsta bilo gdje na dodirnoj podlozi.\n\nZa ovo možete koristiti i radnju za prečicu i Esc na tastaturi."</string>
-    <string name="touchpad_back_gesture_success_title" msgid="7240576648330612171">"Sjajno!"</string>
+    <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"Prevucite ulijevo ili udesno s tri prsta na dodirnoj podlozi"</string>
+    <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"Lijepo!"</string>
     <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"Savladali ste pokret za vraćanje."</string>
     <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"Odlazak na početni ekran"</string>
-    <string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"Da odete na početni ekran bilo kada, prevucite s dna ekrana nagore s tri prsta."</string>
-    <string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Lijepo!"</string>
-    <string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Savladali ste pokret za odlazak na početni ekran."</string>
+    <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"Prevucite nagore s tri prsta na dodirnoj podlozi"</string>
+    <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"Sjajno!"</string>
+    <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"Savladali ste pokret za otvaranje početnog ekrana"</string>
     <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"Prikaz nedavnih aplikacija"</string>
-    <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"Prevucite nagore i zadržite s tri prsta na dodirnoj podlozi."</string>
+    <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"Prevucite nagore i zadržite s tri prsta na dodirnoj podlozi"</string>
     <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Sjajno!"</string>
     <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Izvršili ste pokret za prikaz nedavnih aplikacija."</string>
-    <string name="tutorial_action_key_title" msgid="2659466586996495447">"Tipka radnji"</string>
-    <string name="tutorial_action_key_guidance" msgid="5718948664616999196">"Da pristupite aplikacijama, pritisnite tipku radnji na tastaturi."</string>
-    <string name="tutorial_action_key_success_title" msgid="466467860120112933">"Čestitamo!"</string>
-    <string name="tutorial_action_key_success_body" msgid="7201991081652850430">"Savladali ste pokret za tipku radnji.\n\nRadnja + / prikazuje sve prečice koje su vam dostupne."</string>
+    <string name="tutorial_action_key_title" msgid="8172535792469008169">"Pogledajte sve aplikacije"</string>
+    <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Pritisnite tipku radnji na tastaturi"</string>
+    <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Odlično!"</string>
+    <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Izvršili ste pokret za prikaz svih aplikacija"</string>
     <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Pozadinsko osvjetljenje tastature"</string>
     <string name="keyboard_backlight_value" msgid="7336398765584393538">"%1$d. nivo od %2$d"</string>
     <string name="home_controls_dream_label" msgid="6567105701292324257">"Kontrole za dom"</string>
@@ -1436,6 +1440,7 @@
     <string name="all_apps_edu_toast_content" msgid="8807496014667211562">"Da pregledate sve aplikacije, pritisnite tipku radnji na tastaturi"</string>
     <string name="redacted_notification_single_line_title" msgid="212019960919261670">"Redigovano"</string>
     <string name="redacted_notification_single_line_text" msgid="8684166405005242945">"Otključajte da pregledate"</string>
+    <string name="contextual_education_dialog_title" msgid="4630392552837487324">"Kontekstualno obrazovanje"</string>
     <string name="back_edu_notification_title" msgid="5624780717751357278">"Koristite dodirnu podlogu da se vratite"</string>
     <string name="back_edu_notification_content" msgid="2497557451540954068">"Prevucite ulijevo ili udesno s tri prsta. Dodirnite da saznate za više pokreta."</string>
     <string name="home_edu_notification_title" msgid="6097902076909654045">"Koristite dodirnu podlogu da se vratite na početnu stranicu"</string>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index a0c0bf9..0767849 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -440,7 +440,7 @@
     <string name="zen_mode_on" msgid="9085304934016242591">"Activat"</string>
     <string name="zen_mode_on_with_details" msgid="7416143430557895497">"Activat • <xliff:g id="TRIGGER_DESCRIPTION">%1$s</xliff:g>"</string>
     <string name="zen_mode_off" msgid="1736604456618147306">"Desactivat"</string>
-    <string name="zen_mode_set_up" msgid="7457957033034460064">"Configura"</string>
+    <string name="zen_mode_set_up" msgid="8231201163894922821">"No definit"</string>
     <string name="zen_mode_no_manual_invocation" msgid="1769975741344633672">"Gestiona a la configuració"</string>
     <string name="zen_mode_active_modes" msgid="1625850411578488856">"{count,plural, =0{No hi ha cap mode actiu}=1{{mode} està actiu}many{Hi ha # de modes actius}other{Hi ha # modes actius}}"</string>
     <string name="zen_priority_introduction" msgid="3159291973383796646">"No t\'interromprà cap so ni cap vibració, tret dels de les alarmes, recordatoris, esdeveniments i trucades de les persones que especifiquis. Continuaràs sentint tot allò que decideixis reproduir, com ara música, vídeos i jocs."</string>
@@ -573,8 +573,7 @@
     <string name="notification_section_header_conversations" msgid="821834744538345661">"Converses"</string>
     <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Esborra totes les notificacions silencioses"</string>
     <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Notificacions pausades pel mode No molestis"</string>
-    <!-- no translation found for modes_suppressing_shade_text (6037581130837903239) -->
-    <skip />
+    <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{No hi ha cap notificació}=1{{mode} ha posat en pausa les notificacions}=2{{mode} i un altre mode han posat en pausa les notificacions}many{{mode} i # de modes més han posat en pausa les notificacions}other{{mode} i # modes més han posat en pausa les notificacions}}"</string>
     <string name="media_projection_action_text" msgid="3634906766918186440">"Comença ara"</string>
     <string name="empty_shade_text" msgid="8935967157319717412">"No hi ha cap notificació"</string>
     <string name="no_unseen_notif_text" msgid="395512586119868682">"No hi ha cap notificació nova"</string>
@@ -673,6 +672,10 @@
     <string name="stream_notification_unavailable" msgid="4313854556205836435">"No disponible perquè el so està silenciat"</string>
     <string name="stream_alarm_unavailable" msgid="4059817189292197839">"No disponible perquè No molestis està activat"</string>
     <string name="stream_media_unavailable" msgid="6823020894438959853">"No disponible perquè No molestis està activat"</string>
+    <!-- no translation found for stream_unavailable_by_modes (3674139029490353683) -->
+    <skip />
+    <!-- no translation found for stream_unavailable_by_unknown (6908434629318171588) -->
+    <skip />
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Toca per activar el so."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Toca per activar la vibració. Pot ser que els serveis d\'accessibilitat se silenciïn."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Toca per silenciar el so. Pot ser que els serveis d\'accessibilitat se silenciïn."</string>
@@ -706,6 +709,7 @@
     <string name="show_demo_mode" msgid="3677956462273059726">"Mostra el mode de demostració"</string>
     <string name="status_bar_ethernet" msgid="5690979758988647484">"Ethernet"</string>
     <string name="status_bar_alarm" msgid="87160847643623352">"Alarma"</string>
+    <string name="active_mode_content_description" msgid="1627555562186515927">"El mode <xliff:g id="MODENAME">%1$s</xliff:g> està activat"</string>
     <string name="wallet_title" msgid="5369767670735827105">"Wallet"</string>
     <string name="wallet_empty_state_label" msgid="7776761245237530394">"Configura una manera més ràpida i segura de fer compres amb el telèfon"</string>
     <string name="wallet_app_button_label" msgid="7123784239111190992">"Mostra-ho tot"</string>
@@ -1405,26 +1409,26 @@
     <string name="launch_touchpad_tutorial_notification_content" msgid="7931085031240753226">"Aprèn els gestos del ratolí tàctil"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_title" msgid="1940023776496198762">"Navega amb el teclat i el ratolí tàctil"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Aprèn els gestos del ratolí tàctil, les tecles de drecera i més"</string>
-    <string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Gest Enrere"</string>
-    <string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Gest Inici"</string>
+    <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"Torna"</string>
+    <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Ves a la pàgina d\'inici"</string>
     <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Mostra les aplicacions recents"</string>
     <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Fet"</string>
     <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Torna"</string>
-    <string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"Per tornar enrere, llisca cap a l\'esquerra o cap a la dreta amb tres dits en qualsevol lloc del ratolí tàctil.\n\nTambé pots utilitzar les tecles d\'accions de drecera+Esc."</string>
-    <string name="touchpad_back_gesture_success_title" msgid="7240576648330612171">"Ben fet!"</string>
+    <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"Llisca cap a l\'esquerra o cap a la dreta amb tres dits al ratolí tàctil"</string>
+    <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"Molt bé!"</string>
     <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"Has completat el gest per tornar enrere."</string>
     <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"Ves a la pantalla d\'inici"</string>
-    <string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"Per anar a la pantalla d\'inici en qualsevol moment, fes lliscar tres dits cap amunt des de la part inferior de la pantalla."</string>
-    <string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Molt bé!"</string>
-    <string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Has completat el gest per anar a la pantalla d\'inici."</string>
+    <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"Llisca cap amunt amb tres dits al ratolí tàctil"</string>
+    <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"Ben fet!"</string>
+    <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"Has completat el gest per anar a la pantalla d\'inici"</string>
     <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"Mostra les aplicacions recents"</string>
-    <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"Llisca cap amunt amb tres dits i mantén premut al ratolí tàctil."</string>
+    <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"Llisca cap amunt amb tres dits i mantén premut al ratolí tàctil"</string>
     <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Ben fet!"</string>
     <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Has completat el gest per veure les aplicacions recents."</string>
-    <string name="tutorial_action_key_title" msgid="2659466586996495447">"Tecla d\'acció"</string>
-    <string name="tutorial_action_key_guidance" msgid="5718948664616999196">"Per accedir a les aplicacions, prem la tecla d\'acció al teclat."</string>
-    <string name="tutorial_action_key_success_title" msgid="466467860120112933">"Enhorabona!"</string>
-    <string name="tutorial_action_key_success_body" msgid="7201991081652850430">"Has completat el gest de la tecla d\'acció.\n\nTecla d\'acció+/ mostra totes les dreceres que tens disponibles."</string>
+    <string name="tutorial_action_key_title" msgid="8172535792469008169">"Mostra totes les aplicacions"</string>
+    <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Prem la tecla d\'acció al teclat"</string>
+    <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Enhorabona!"</string>
+    <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Has completat el gest per veure totes les aplicacions"</string>
     <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Retroil·luminació del teclat"</string>
     <string name="keyboard_backlight_value" msgid="7336398765584393538">"Nivell %1$d de %2$d"</string>
     <string name="home_controls_dream_label" msgid="6567105701292324257">"Controls de la llar"</string>
@@ -1436,6 +1440,7 @@
     <string name="all_apps_edu_toast_content" msgid="8807496014667211562">"Per veure totes les aplicacions, prem la tecla d\'acció al teclat"</string>
     <string name="redacted_notification_single_line_title" msgid="212019960919261670">"Emmascarat"</string>
     <string name="redacted_notification_single_line_text" msgid="8684166405005242945">"Desbloqueja per veure"</string>
+    <string name="contextual_education_dialog_title" msgid="4630392552837487324">"Educació contextual"</string>
     <string name="back_edu_notification_title" msgid="5624780717751357278">"Utilitza el ratolí tàctil per tornar enrere"</string>
     <string name="back_edu_notification_content" msgid="2497557451540954068">"Fes lliscar tres dits cap a l\'esquerra o cap a la dreta. Toca per aprendre més gestos."</string>
     <string name="home_edu_notification_title" msgid="6097902076909654045">"Utilitza el ratolí tàctil per anar a la pantalla d\'inici"</string>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index 107bac6..c7ec42c 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -440,7 +440,7 @@
     <string name="zen_mode_on" msgid="9085304934016242591">"Zapnuto"</string>
     <string name="zen_mode_on_with_details" msgid="7416143430557895497">"Zapnuto • <xliff:g id="TRIGGER_DESCRIPTION">%1$s</xliff:g>"</string>
     <string name="zen_mode_off" msgid="1736604456618147306">"Vypnuto"</string>
-    <string name="zen_mode_set_up" msgid="7457957033034460064">"Nastavit"</string>
+    <string name="zen_mode_set_up" msgid="8231201163894922821">"Nenastaveno"</string>
     <string name="zen_mode_no_manual_invocation" msgid="1769975741344633672">"Spravovat v nastavení"</string>
     <string name="zen_mode_active_modes" msgid="1625850411578488856">"{count,plural, =0{Žádné aktivní}=1{Režim {mode} je aktivní}few{# režimy jsou aktivní}many{# režimu je aktivních}other{# režimů je aktivních}}"</string>
     <string name="zen_priority_introduction" msgid="3159291973383796646">"Nebudou vás rušit zvuky ani vibrace s výjimkou budíků, upozornění, událostí a volajících, které zadáte. Nadále uslyšíte veškerý obsah, který si sami pustíte (např. hudba, videa nebo hry)."</string>
@@ -573,8 +573,7 @@
     <string name="notification_section_header_conversations" msgid="821834744538345661">"Konverzace"</string>
     <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Vymazat všechna tichá oznámení"</string>
     <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Oznámení jsou pozastavena režimem Nerušit"</string>
-    <!-- no translation found for modes_suppressing_shade_text (6037581130837903239) -->
-    <skip />
+    <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{Žádná oznámení}=1{Oznámení jsou pozastavená režimem {mode}}=2{Oznámení jsou pozastavená režimem {mode} a 1 dalším}few{Oznámení jsou pozastavená režimem {mode} a # dalšími}many{Oznámení jsou pozastavená režimem {mode} a # dalšího}other{Oznámení jsou pozastavená režimem {mode} a # dalšími}}"</string>
     <string name="media_projection_action_text" msgid="3634906766918186440">"Spustit"</string>
     <string name="empty_shade_text" msgid="8935967157319717412">"Žádná oznámení"</string>
     <string name="no_unseen_notif_text" msgid="395512586119868682">"Žádná nová oznámení"</string>
@@ -673,6 +672,10 @@
     <string name="stream_notification_unavailable" msgid="4313854556205836435">"Nedostupné, protože vyzvánění je ztlumené"</string>
     <string name="stream_alarm_unavailable" msgid="4059817189292197839">"Nedostupné, protože je zapnutý režim Nerušit"</string>
     <string name="stream_media_unavailable" msgid="6823020894438959853">"Nedostupné – je zapnutý režim Nerušit"</string>
+    <!-- no translation found for stream_unavailable_by_modes (3674139029490353683) -->
+    <skip />
+    <!-- no translation found for stream_unavailable_by_unknown (6908434629318171588) -->
+    <skip />
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Klepnutím zapnete zvuk."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Klepnutím aktivujete režim vibrací. Služby přístupnosti mohou být ztlumeny."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Klepnutím vypnete zvuk. Služby přístupnosti mohou být ztlumeny."</string>
@@ -706,6 +709,7 @@
     <string name="show_demo_mode" msgid="3677956462273059726">"Zobrazit ukázkový režim"</string>
     <string name="status_bar_ethernet" msgid="5690979758988647484">"Ethernet"</string>
     <string name="status_bar_alarm" msgid="87160847643623352">"Budík"</string>
+    <string name="active_mode_content_description" msgid="1627555562186515927">"Je zapnutý režim <xliff:g id="MODENAME">%1$s</xliff:g>"</string>
     <string name="wallet_title" msgid="5369767670735827105">"Peněženka"</string>
     <string name="wallet_empty_state_label" msgid="7776761245237530394">"Nastavte si rychlejší a bezpečnější platby pomocí telefonu"</string>
     <string name="wallet_app_button_label" msgid="7123784239111190992">"Zobrazit vše"</string>
@@ -1405,26 +1409,26 @@
     <string name="launch_touchpad_tutorial_notification_content" msgid="7931085031240753226">"Naučte se gesta touchpadu"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_title" msgid="1940023776496198762">"Navigujte pomocí klávesnice a touchpadu"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Naučte se gesta touchpadu, klávesové zkratky a další"</string>
-    <string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Gesto zpět"</string>
-    <string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Gesto domů"</string>
+    <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"Zpět"</string>
+    <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Přejít na domovskou stránku"</string>
     <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Zobrazit nedávné aplikace"</string>
     <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Hotovo"</string>
     <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Zpět"</string>
-    <string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"Pokud se chcete vrátit zpět, stačí kdekoli na touchpadu přejet třemi prsty doleva nebo doprava.\n\nMůžete také použít klávesovou zkratku Akce + ESC."</string>
-    <string name="touchpad_back_gesture_success_title" msgid="7240576648330612171">"Výborně!"</string>
+    <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"Přejeďte po touchpadu třemi prsty doleva nebo doprava"</string>
+    <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"Skvělé!"</string>
     <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"Dokončili jste gesto pro přechod zpět."</string>
     <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"Přejít na plochu"</string>
-    <string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"Na plochu přejdete kdykoli přejetím třemi prsty ze spodní části obrazovky nahoru."</string>
-    <string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Skvělé!"</string>
-    <string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Dokončili jste gesto pro přechod na plochu."</string>
+    <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"Přejeďte po touchpadu třemi prsty nahoru"</string>
+    <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"Výborně!"</string>
+    <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"Dokončili jste gesto pro přechod na plochu"</string>
     <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"Zobrazit nedávné aplikace"</string>
-    <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"Přejeďte po touchpadu třemi prsty nahoru a podržte je."</string>
+    <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"Přejeďte po touchpadu třemi prsty nahoru a podržte je"</string>
     <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Výborně!"</string>
     <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Provedli jste gesto pro zobrazení nedávných aplikací."</string>
-    <string name="tutorial_action_key_title" msgid="2659466586996495447">"Akční klávesa"</string>
-    <string name="tutorial_action_key_guidance" msgid="5718948664616999196">"Přístup k aplikacím získáte stisknutím akční klávesy na klávesnici."</string>
-    <string name="tutorial_action_key_success_title" msgid="466467860120112933">"Gratulujeme!"</string>
-    <string name="tutorial_action_key_success_body" msgid="7201991081652850430">"Dokončili jste gesto akční klávesy.\n\nAkce + / zobrazí všechny dostupné zkratky."</string>
+    <string name="tutorial_action_key_title" msgid="8172535792469008169">"Zobrazit všechny aplikace"</string>
+    <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Stiskněte akční klávesu na klávesnici"</string>
+    <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Výborně!"</string>
+    <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Dokončili jste gesto k zobrazení všech aplikací"</string>
     <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Podsvícení klávesnice"</string>
     <string name="keyboard_backlight_value" msgid="7336398765584393538">"Úroveň %1$d z %2$d"</string>
     <string name="home_controls_dream_label" msgid="6567105701292324257">"Ovládání domácnosti"</string>
@@ -1436,6 +1440,7 @@
     <string name="all_apps_edu_toast_content" msgid="8807496014667211562">"Pokud chcete zobrazit všechny aplikace, stiskněte na klávesnici akční klávesu"</string>
     <string name="redacted_notification_single_line_title" msgid="212019960919261670">"Odstraněno"</string>
     <string name="redacted_notification_single_line_text" msgid="8684166405005242945">"K zobrazení je potřeba zařízení odemknout"</string>
+    <string name="contextual_education_dialog_title" msgid="4630392552837487324">"Kontextová výuka"</string>
     <string name="back_edu_notification_title" msgid="5624780717751357278">"Návrat zpět pomocí touchpadu"</string>
     <string name="back_edu_notification_content" msgid="2497557451540954068">"Přejeďte třemi prsty doleva nebo doprava. Další gesta zjistíte klepnutím."</string>
     <string name="home_edu_notification_title" msgid="6097902076909654045">"Návrat domů pomocí touchpadu"</string>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index 1ac7526..b5220d6 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -440,7 +440,7 @@
     <string name="zen_mode_on" msgid="9085304934016242591">"Til"</string>
     <string name="zen_mode_on_with_details" msgid="7416143430557895497">"Til • <xliff:g id="TRIGGER_DESCRIPTION">%1$s</xliff:g>"</string>
     <string name="zen_mode_off" msgid="1736604456618147306">"Fra"</string>
-    <string name="zen_mode_set_up" msgid="7457957033034460064">"Konfigurer"</string>
+    <string name="zen_mode_set_up" msgid="8231201163894922821">"Ikke konfigureret"</string>
     <string name="zen_mode_no_manual_invocation" msgid="1769975741344633672">"Administrer i indstillingerne"</string>
     <string name="zen_mode_active_modes" msgid="1625850411578488856">"{count,plural, =0{Ingen aktive tilstande}=1{{mode} er aktiv}one{# tilstand er aktiv}other{# tilstande er aktive}}"</string>
     <string name="zen_priority_introduction" msgid="3159291973383796646">"Du bliver ikke forstyrret af lyde eller vibrationer, undtagen fra alarmer, påmindelser, begivenheder og opkald fra udvalgte personer, du selv angiver. Du kan stadig høre alt, du vælger at afspille, f.eks. musik, videoer og spil."</string>
@@ -573,8 +573,7 @@
     <string name="notification_section_header_conversations" msgid="821834744538345661">"Samtaler"</string>
     <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Ryd alle lydløse notifikationer"</string>
     <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Notifikationer er sat på pause af Forstyr ikke"</string>
-    <!-- no translation found for modes_suppressing_shade_text (6037581130837903239) -->
-    <skip />
+    <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{Ingen notifikationer}=1{Notifikationer er sat på pause af {mode}}=2{Notifikationer er sat på pause af {mode} og én anden tilstand}one{Notifikationer er sat på pause af {mode} og # anden tilstand}other{Notifikationer er sat på pause af {mode} og # andre tilstande}}"</string>
     <string name="media_projection_action_text" msgid="3634906766918186440">"Start nu"</string>
     <string name="empty_shade_text" msgid="8935967157319717412">"Ingen notifikationer"</string>
     <string name="no_unseen_notif_text" msgid="395512586119868682">"Ingen nye notifikationer"</string>
@@ -673,6 +672,10 @@
     <string name="stream_notification_unavailable" msgid="4313854556205836435">"Ikke muligt, da ringetonen er slået fra"</string>
     <string name="stream_alarm_unavailable" msgid="4059817189292197839">"Ikke tilgængelig, fordi Forstyr ikke er aktiveret"</string>
     <string name="stream_media_unavailable" msgid="6823020894438959853">"Ikke tilgængelig, fordi Forstyr ikke er aktiveret"</string>
+    <!-- no translation found for stream_unavailable_by_modes (3674139029490353683) -->
+    <skip />
+    <!-- no translation found for stream_unavailable_by_unknown (6908434629318171588) -->
+    <skip />
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Tryk for at slå lyden til."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Tryk for at konfigurere til at vibrere. Tilgængelighedstjenester kan blive deaktiveret."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Tryk for at slå lyden fra. Lyden i tilgængelighedstjenester kan blive slået fra."</string>
@@ -706,6 +709,7 @@
     <string name="show_demo_mode" msgid="3677956462273059726">"Vis Demotilstand"</string>
     <string name="status_bar_ethernet" msgid="5690979758988647484">"Ethernet"</string>
     <string name="status_bar_alarm" msgid="87160847643623352">"Alarm"</string>
+    <string name="active_mode_content_description" msgid="1627555562186515927">"<xliff:g id="MODENAME">%1$s</xliff:g> er aktiveret"</string>
     <string name="wallet_title" msgid="5369767670735827105">"Wallet"</string>
     <string name="wallet_empty_state_label" msgid="7776761245237530394">"Bliv klar til at foretage hurtigere og mere sikre køb med din telefon"</string>
     <string name="wallet_app_button_label" msgid="7123784239111190992">"Vis alle"</string>
@@ -1405,26 +1409,26 @@
     <string name="launch_touchpad_tutorial_notification_content" msgid="7931085031240753226">"Se bevægelser på touchpladen"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_title" msgid="1940023776496198762">"Naviger ved hjælp af dit tastatur og din touchplade"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Se bevægelser på touchpladen, tastaturgenveje m.m."</string>
-    <string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Bevægelse for at gå tilbage"</string>
-    <string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Bevægelse for at gå til startskærm"</string>
+    <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"Gå tilbage"</string>
+    <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Gå til startsiden"</string>
     <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Se seneste apps"</string>
     <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Udfør"</string>
     <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Gå tilbage"</string>
-    <string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"Du kan gå tilbage ved at stryge mod venstre eller højre med tre fingre et vilkårligt sted på touchpladen.\n\nDu kan også bruge tastaturgenvejen Alt + Esc."</string>
-    <string name="touchpad_back_gesture_success_title" msgid="7240576648330612171">"Flot!"</string>
+    <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"Stryg til venstre eller højre med tre fingre på touchpladen"</string>
+    <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"Sådan!"</string>
     <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"Du har fuldført bevægelsen for Gå tilbage."</string>
     <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"Gå til startskærmen"</string>
-    <string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"Du kan til enhver tid stryge opad med tre fingre fra bunden af skærmen, hvis du vil gå til startskærmen."</string>
-    <string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Sådan!"</string>
-    <string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Du har fuldført bevægelsen for Gå til startskærmen."</string>
+    <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"Stryg opad med tre fingre på touchpladen"</string>
+    <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"Flot!"</string>
+    <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"Du har udført bevægelsen for at gå til startsiden"</string>
     <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"Se seneste apps"</string>
-    <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"Stryg opad, og hold tre fingre på touchpladen."</string>
+    <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"Stryg opad, og hold tre fingre på touchpladen"</string>
     <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Godt klaret!"</string>
     <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Du har udført bevægelsen for at se de seneste apps."</string>
-    <string name="tutorial_action_key_title" msgid="2659466586996495447">"Handlingstast"</string>
-    <string name="tutorial_action_key_guidance" msgid="5718948664616999196">"Du kan tilgå alle dine apps ved at trykke på handlingstasten på dit tastatur."</string>
-    <string name="tutorial_action_key_success_title" msgid="466467860120112933">"Tillykke!"</string>
-    <string name="tutorial_action_key_success_body" msgid="7201991081652850430">"Du har fuldført bevægelsen for handlingstasten.\n\nHandling + / viser alle de tilgængelige genveje."</string>
+    <string name="tutorial_action_key_title" msgid="8172535792469008169">"Se alle apps"</string>
+    <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Tryk på handlingstasten på dit tastatur"</string>
+    <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Flot klaret!"</string>
+    <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Du har udført bevægelsen for at se alle apps"</string>
     <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Tastaturets baggrundslys"</string>
     <string name="keyboard_backlight_value" msgid="7336398765584393538">"Niveau %1$d af %2$d"</string>
     <string name="home_controls_dream_label" msgid="6567105701292324257">"Hjemmestyring"</string>
@@ -1436,6 +1440,7 @@
     <string name="all_apps_edu_toast_content" msgid="8807496014667211562">"Du kan se alle dine apps ved at trykke på handlingstasten på dit tastatur"</string>
     <string name="redacted_notification_single_line_title" msgid="212019960919261670">"Skjult"</string>
     <string name="redacted_notification_single_line_text" msgid="8684166405005242945">"Lås op for at se"</string>
+    <string name="contextual_education_dialog_title" msgid="4630392552837487324">"Kontekstbaseret uddannelse"</string>
     <string name="back_edu_notification_title" msgid="5624780717751357278">"Brug din touchplade til at gå tilbage"</string>
     <string name="back_edu_notification_content" msgid="2497557451540954068">"Stryg til venstre eller højre med tre fingre. Tryk for at lære flere bevægelser."</string>
     <string name="home_edu_notification_title" msgid="6097902076909654045">"Brug din touchplade til at gå til startskærmen"</string>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index 8f5a705..9367d40 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -440,7 +440,8 @@
     <string name="zen_mode_on" msgid="9085304934016242591">"An"</string>
     <string name="zen_mode_on_with_details" msgid="7416143430557895497">"An • <xliff:g id="TRIGGER_DESCRIPTION">%1$s</xliff:g>"</string>
     <string name="zen_mode_off" msgid="1736604456618147306">"Aus"</string>
-    <string name="zen_mode_set_up" msgid="7457957033034460064">"Einrichten"</string>
+    <!-- no translation found for zen_mode_set_up (8231201163894922821) -->
+    <skip />
     <string name="zen_mode_no_manual_invocation" msgid="1769975741344633672">"In den Einstellungen verwalten"</string>
     <string name="zen_mode_active_modes" msgid="1625850411578488856">"{count,plural, =0{Keine aktiven Modi}=1{{mode} aktiv}other{# aktiv}}"</string>
     <string name="zen_priority_introduction" msgid="3159291973383796646">"Klingeltöne und die Vibration werden deaktiviert, außer für Weckrufe, Erinnerungen, Termine sowie Anrufe von zuvor von dir festgelegten Personen. Du hörst jedoch weiterhin Sound, wenn du dir Musik anhörst, Videos ansiehst oder Spiele spielst."</string>
@@ -573,8 +574,7 @@
     <string name="notification_section_header_conversations" msgid="821834744538345661">"Unterhaltungen"</string>
     <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Alle lautlosen Benachrichtigungen löschen"</string>
     <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Benachrichtigungen durch „Bitte nicht stören“ pausiert"</string>
-    <!-- no translation found for modes_suppressing_shade_text (6037581130837903239) -->
-    <skip />
+    <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{Keine Benachrichtigungen}=1{Benachrichtigungen durch {mode} pausiert}=2{Benachrichtigungen durch {mode} und einen weiteren Modus pausiert}other{Benachrichtigungen durch {mode} und # weitere Modi pausiert}}"</string>
     <string name="media_projection_action_text" msgid="3634906766918186440">"Jetzt starten"</string>
     <string name="empty_shade_text" msgid="8935967157319717412">"Keine Benachrichtigungen"</string>
     <string name="no_unseen_notif_text" msgid="395512586119868682">"Keine neuen Benachrichtigungen"</string>
@@ -673,6 +673,10 @@
     <string name="stream_notification_unavailable" msgid="4313854556205836435">"Nicht verfügbar, da Klingelton stumm"</string>
     <string name="stream_alarm_unavailable" msgid="4059817189292197839">"Nicht verfügbar, weil „Bitte nicht stören“ an ist"</string>
     <string name="stream_media_unavailable" msgid="6823020894438959853">"Nicht verfügbar, weil „Bitte nicht stören“ an"</string>
+    <!-- no translation found for stream_unavailable_by_modes (3674139029490353683) -->
+    <skip />
+    <!-- no translation found for stream_unavailable_by_unknown (6908434629318171588) -->
+    <skip />
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Zum Aufheben der Stummschaltung tippen."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Tippen, um Vibrieren festzulegen. Bedienungshilfen werden unter Umständen stummgeschaltet."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Zum Stummschalten tippen. Bedienungshilfen werden unter Umständen stummgeschaltet."</string>
@@ -706,6 +710,7 @@
     <string name="show_demo_mode" msgid="3677956462273059726">"Demomodus anzeigen"</string>
     <string name="status_bar_ethernet" msgid="5690979758988647484">"Ethernet"</string>
     <string name="status_bar_alarm" msgid="87160847643623352">"Weckruf"</string>
+    <string name="active_mode_content_description" msgid="1627555562186515927">"„<xliff:g id="MODENAME">%1$s</xliff:g>“ ist aktiviert"</string>
     <string name="wallet_title" msgid="5369767670735827105">"Wallet"</string>
     <string name="wallet_empty_state_label" msgid="7776761245237530394">"Füge eine Zahlungsmethode hinzu, um noch schneller und sicherer mit deinem Smartphone zu bezahlen"</string>
     <string name="wallet_app_button_label" msgid="7123784239111190992">"Alle anzeigen"</string>
@@ -1405,26 +1410,38 @@
     <string name="launch_touchpad_tutorial_notification_content" msgid="7931085031240753226">"Informationen zu Touchpad-Gesten"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_title" msgid="1940023776496198762">"Navigation mit Tastatur und Touchpad"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Informationen zu Touchpad-Gesten, Tastenkombinationen und mehr"</string>
-    <string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Touch-Geste „Zurück“"</string>
-    <string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Touch-Geste „Startbildschirm“"</string>
+    <!-- no translation found for touchpad_tutorial_back_gesture_button (3104716365403620315) -->
+    <skip />
+    <!-- no translation found for touchpad_tutorial_home_gesture_button (8023973153559885624) -->
+    <skip />
     <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Letzte Apps aufrufen"</string>
     <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Fertig"</string>
     <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Zurück"</string>
-    <string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"Wenn du zurückgehen möchtest, wische an einer beliebigen Stelle des Touchpads mit drei Fingern nach links oder rechts.\n\nDu kannst stattdessen auch die Tastenkombination „Aktion“ + „ESC“ verwenden."</string>
-    <string name="touchpad_back_gesture_success_title" msgid="7240576648330612171">"Gut gemacht!"</string>
+    <!-- no translation found for touchpad_back_gesture_guidance (5352221087725906542) -->
+    <skip />
+    <!-- no translation found for touchpad_back_gesture_success_title (7370719098633023496) -->
+    <skip />
     <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"Du hast den Schritt für die „Zurück“-Geste abgeschlossen."</string>
     <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"Startbildschirm"</string>
-    <string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"Du kannst jederzeit zum Startbildschirm gehen, indem du mit drei Fingern vom unteren Displayrand nach oben wischst."</string>
-    <string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Sehr gut!"</string>
-    <string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Du hast den Schritt für die „Startbildschirm“-Geste abgeschlossen."</string>
+    <!-- no translation found for touchpad_home_gesture_guidance (4178219118381915899) -->
+    <skip />
+    <!-- no translation found for touchpad_home_gesture_success_title (3648264553645798470) -->
+    <skip />
+    <!-- no translation found for touchpad_home_gesture_success_body (2590690589194027059) -->
+    <skip />
     <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"Letzte Apps aufrufen"</string>
-    <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"Wische mit 3 Fingern nach oben und halte das Touchpad gedrückt."</string>
+    <!-- no translation found for touchpad_recent_apps_gesture_guidance (6304446013842271822) -->
+    <skip />
     <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Gut gemacht!"</string>
     <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Du hast das Tutorial für die Touch-Geste zum Aufrufen der zuletzt verwendeten Apps abgeschlossen."</string>
-    <string name="tutorial_action_key_title" msgid="2659466586996495447">"Aktionstaste"</string>
-    <string name="tutorial_action_key_guidance" msgid="5718948664616999196">"Wenn du auf deine Apps zugreifen möchtest, drücke auf der Tastatur die Aktionstaste."</string>
-    <string name="tutorial_action_key_success_title" msgid="466467860120112933">"Glückwunsch!"</string>
-    <string name="tutorial_action_key_success_body" msgid="7201991081652850430">"Du hast den Schritt für die „Aktionstaste“-Geste abgeschlossen.\n\nAktion + / zeigt alle verfügbaren Tastenkombinationen."</string>
+    <!-- no translation found for tutorial_action_key_title (8172535792469008169) -->
+    <skip />
+    <!-- no translation found for tutorial_action_key_guidance (5040613427202799294) -->
+    <skip />
+    <!-- no translation found for tutorial_action_key_success_title (2371827347071979571) -->
+    <skip />
+    <!-- no translation found for tutorial_action_key_success_body (1688986269491357832) -->
+    <skip />
     <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Tastaturbeleuchtung"</string>
     <string name="keyboard_backlight_value" msgid="7336398765584393538">"Level %1$d von %2$d"</string>
     <string name="home_controls_dream_label" msgid="6567105701292324257">"Smart-Home-Steuerung"</string>
@@ -1436,6 +1453,7 @@
     <string name="all_apps_edu_toast_content" msgid="8807496014667211562">"Wenn du alle deine Apps aufrufen möchtest, drücke auf der Tastatur die Aktionstaste"</string>
     <string name="redacted_notification_single_line_title" msgid="212019960919261670">"Entfernt"</string>
     <string name="redacted_notification_single_line_text" msgid="8684166405005242945">"Zum Ansehen entsperren"</string>
+    <string name="contextual_education_dialog_title" msgid="4630392552837487324">"Kontextbezogene Informationen"</string>
     <string name="back_edu_notification_title" msgid="5624780717751357278">"Über das Touchpad zurückgehen"</string>
     <string name="back_edu_notification_content" msgid="2497557451540954068">"Wische mit drei Fingern nach links oder rechts. Tippe für mehr Infos zu Touch-Gesten."</string>
     <string name="home_edu_notification_title" msgid="6097902076909654045">"Über das Touchpad zum Startbildschirm zurückkehren"</string>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index 183249b..18b99aa 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -440,7 +440,7 @@
     <string name="zen_mode_on" msgid="9085304934016242591">"Ενεργό"</string>
     <string name="zen_mode_on_with_details" msgid="7416143430557895497">"Ενεργή • <xliff:g id="TRIGGER_DESCRIPTION">%1$s</xliff:g>"</string>
     <string name="zen_mode_off" msgid="1736604456618147306">"Ανενεργό"</string>
-    <string name="zen_mode_set_up" msgid="7457957033034460064">"Ρύθμιση"</string>
+    <string name="zen_mode_set_up" msgid="8231201163894922821">"Δεν έχει οριστεί"</string>
     <string name="zen_mode_no_manual_invocation" msgid="1769975741344633672">"Διαχείριση στις ρυθμίσεις"</string>
     <string name="zen_mode_active_modes" msgid="1625850411578488856">"{count,plural, =0{Δεν υπάρχει ενεργή λειτουργία}=1{{mode} ενεργή λειτουργία}other{# ενεργές λειτουργίες}}"</string>
     <string name="zen_priority_introduction" msgid="3159291973383796646">"Δεν θα ενοχλείστε από ήχους και δονήσεις, παρά μόνο από ξυπνητήρια, υπενθυμίσεις, συμβάντα και καλούντες που έχετε καθορίσει. Θα εξακολουθείτε να ακούτε όλο το περιεχόμενο που επιλέγετε να αναπαραγάγετε, συμπεριλαμβανομένης της μουσικής, των βίντεο και των παιχνιδιών."</string>
@@ -573,8 +573,7 @@
     <string name="notification_section_header_conversations" msgid="821834744538345661">"Συζητήσεις"</string>
     <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Διαγραφή όλων των ειδοποιήσεων σε σίγαση"</string>
     <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Οι ειδοποιήσεις τέθηκαν σε παύση από τη λειτουργία \"Μην ενοχλείτε\""</string>
-    <!-- no translation found for modes_suppressing_shade_text (6037581130837903239) -->
-    <skip />
+    <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{Δεν υπάρχουν ειδοποιήσεις}=1{Οι ειδοποιήσεις τέθηκαν σε παύση από τη λειτουργία {mode}}=2{Οι ειδοποιήσεις τέθηκαν σε παύση από τη λειτουργία {mode} και μία άλλη λειτουργία}other{Οι ειδοποιήσεις τέθηκαν σε παύση από τη λειτουργία {mode} και # άλλες λειτουργίες}}"</string>
     <string name="media_projection_action_text" msgid="3634906766918186440">"Έναρξη τώρα"</string>
     <string name="empty_shade_text" msgid="8935967157319717412">"Δεν υπάρχουν ειδοποιήσεις"</string>
     <string name="no_unseen_notif_text" msgid="395512586119868682">"Δεν υπάρχουν νέες ειδοποιήσεις"</string>
@@ -673,6 +672,10 @@
     <string name="stream_notification_unavailable" msgid="4313854556205836435">"Μη διαθέσιμο λόγω σίγασης ήχου κλήσης"</string>
     <string name="stream_alarm_unavailable" msgid="4059817189292197839">"Μη διαθ. επειδή η λειτ. Μην ενοχλείτε είναι ενεργή"</string>
     <string name="stream_media_unavailable" msgid="6823020894438959853">"Μη διαθ. επειδή η λειτ. Μην ενοχλείτε είναι ενεργή"</string>
+    <!-- no translation found for stream_unavailable_by_modes (3674139029490353683) -->
+    <skip />
+    <!-- no translation found for stream_unavailable_by_unknown (6908434629318171588) -->
+    <skip />
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Πατήστε για κατάργηση σίγασης."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Πατήστε για ενεργοποιήσετε τη δόνηση. Οι υπηρεσίες προσβασιμότητας ενδέχεται να τεθούν σε σίγαση."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Πατήστε για σίγαση. Οι υπηρεσίες προσβασιμότητας ενδέχεται να τεθούν σε σίγαση."</string>
@@ -706,6 +709,7 @@
     <string name="show_demo_mode" msgid="3677956462273059726">"Εμφάνιση λειτουργίας επίδειξης"</string>
     <string name="status_bar_ethernet" msgid="5690979758988647484">"Ethernet"</string>
     <string name="status_bar_alarm" msgid="87160847643623352">"Ξυπνητήρι"</string>
+    <string name="active_mode_content_description" msgid="1627555562186515927">"Η λειτουργία <xliff:g id="MODENAME">%1$s</xliff:g> είναι ενεργή"</string>
     <string name="wallet_title" msgid="5369767670735827105">"Πορτοφόλι"</string>
     <string name="wallet_empty_state_label" msgid="7776761245237530394">"Ολοκληρώστε τη ρύθμιση για να κάνετε πιο γρήγορες και πιο ασφαλείς αγορές με το τηλέφωνό σας"</string>
     <string name="wallet_app_button_label" msgid="7123784239111190992">"Εμφάνιση όλων"</string>
@@ -1405,26 +1409,26 @@
     <string name="launch_touchpad_tutorial_notification_content" msgid="7931085031240753226">"Μάθετε κινήσεις επιφάνειας αφής"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_title" msgid="1940023776496198762">"Πλοήγηση με το πληκτρολόγιο και την επιφάνεια αφής"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Μάθετε κινήσεις επιφάνειας αφής, συντομεύσεις πληκτρολογίου και άλλα"</string>
-    <string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Κίνηση επιστροφής"</string>
-    <string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Κίνηση μετάβασης στην αρχική οθόνη"</string>
+    <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"Επιστροφή"</string>
+    <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Αρχική"</string>
     <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Προβολή πρόσφατων εφαρμογών"</string>
     <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Τέλος"</string>
     <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Επιστροφή"</string>
-    <string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"Για να επιστρέψετε, σύρετε προς τα αριστερά ή προς τα δεξιά χρησιμοποιώντας τρία δάχτυλα σε οποιοδήποτε σημείο της επιφάνειας αφής.\n\nΜπορείτε επίσης να χρησιμοποιήσετε τη συντόμευση πληκτρολογίου Action + ESC."</string>
-    <string name="touchpad_back_gesture_success_title" msgid="7240576648330612171">"Μπράβο!"</string>
+    <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"Σύρετε προς τα αριστερά ή τα δεξιά με τρία δάχτυλα στην επιφάνεια αφής"</string>
+    <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"Ωραία!"</string>
     <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"Ολοκληρώσατε την κίνηση επιστροφής."</string>
     <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"Αρχική"</string>
-    <string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"Για μετάβαση στην αρχική οθόνη ανά πάσα στιγμή, σύρετε προς τα επάνω με τρία δάχτυλα από το κάτω μέρος της οθόνης."</string>
-    <string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Ωραία!"</string>
-    <string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Ολοκληρώσατε την κίνηση μετάβασης στην αρχική οθόνη."</string>
+    <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"Σύρετε προς τα επάνω με τρία δάχτυλα στην επιφάνεια αφής"</string>
+    <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"Μπράβο!"</string>
+    <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"Ολοκληρώσατε την κίνηση μετάβασης στην αρχική οθόνη"</string>
     <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"Προβολή πρόσφατων εφαρμογών"</string>
-    <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"Σύρετε προς τα πάνω με τρία δάχτυλα στην επιφάνεια αφής και μην τα σηκώσετε."</string>
+    <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"Σύρετε προς τα επάνω με τρία δάχτυλα στην επιφάνεια αφής και μην τα σηκώσετε"</string>
     <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Μπράβο!"</string>
     <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Ολοκληρώσατε την κίνηση για την προβολή πρόσφατων εφαρμογών."</string>
-    <string name="tutorial_action_key_title" msgid="2659466586996495447">"Πλήκτρο ενέργειας"</string>
-    <string name="tutorial_action_key_guidance" msgid="5718948664616999196">"Για να αποκτήσετε πρόσβαση στις εφαρμογές σας, πατήστε το πλήκτρο ενέργειας στο πληκτρολόγιό σας."</string>
-    <string name="tutorial_action_key_success_title" msgid="466467860120112933">"Συγχαρητήρια!"</string>
-    <string name="tutorial_action_key_success_body" msgid="7201991081652850430">"Ολοκληρώσατε την κίνηση του κουμπιού ενέργειας.\n\nΗ ενέργεια + / εμφανίζει όλες τις διαθέσιμες συντομεύσεις."</string>
+    <string name="tutorial_action_key_title" msgid="8172535792469008169">"Προβολή όλων των εφαρμογών"</string>
+    <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Πατήστε το πλήκτρο ενέργειας στο πληκτρολόγιό σας"</string>
+    <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Μπράβο!"</string>
+    <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Ολοκληρώσατε την κίνηση για την προβολή όλων των εφαρμογών"</string>
     <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Οπίσθιος φωτισμός πληκτρολογίου"</string>
     <string name="keyboard_backlight_value" msgid="7336398765584393538">"Επίπεδο %1$d από %2$d"</string>
     <string name="home_controls_dream_label" msgid="6567105701292324257">"Οικιακοί έλεγχοι"</string>
@@ -1436,6 +1440,7 @@
     <string name="all_apps_edu_toast_content" msgid="8807496014667211562">"Για να δείτε όλες τις εφαρμογές, πιέστε το πλήκτρο ενέργειας στο πληκτρολόγιό σας"</string>
     <string name="redacted_notification_single_line_title" msgid="212019960919261670">"Αποκρύφτηκε"</string>
     <string name="redacted_notification_single_line_text" msgid="8684166405005242945">"Ξεκλείδωμα για προβολή"</string>
+    <string name="contextual_education_dialog_title" msgid="4630392552837487324">"Εκπαίδευση με βάση τα συμφραζόμενα"</string>
     <string name="back_edu_notification_title" msgid="5624780717751357278">"Χρήση της επιφάνειας αφής για επιστροφή"</string>
     <string name="back_edu_notification_content" msgid="2497557451540954068">"Σύρετε προς τα αριστερά ή τα δεξιά με τρία δάχτυλα. Πατήστε για να μάθετε περισσότερες κινήσεις."</string>
     <string name="home_edu_notification_title" msgid="6097902076909654045">"Χρήση της επιφάνειας αφής για μετάβαση στην αρχική οθόνη"</string>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index 9b7ae5d..ba945f2 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -440,7 +440,7 @@
     <string name="zen_mode_on" msgid="9085304934016242591">"On"</string>
     <string name="zen_mode_on_with_details" msgid="7416143430557895497">"On • <xliff:g id="TRIGGER_DESCRIPTION">%1$s</xliff:g>"</string>
     <string name="zen_mode_off" msgid="1736604456618147306">"Off"</string>
-    <string name="zen_mode_set_up" msgid="7457957033034460064">"Set up"</string>
+    <string name="zen_mode_set_up" msgid="8231201163894922821">"Not set"</string>
     <string name="zen_mode_no_manual_invocation" msgid="1769975741344633672">"Manage in settings"</string>
     <string name="zen_mode_active_modes" msgid="1625850411578488856">"{count,plural, =0{No active modes}=1{{mode} is active}other{# modes are active}}"</string>
     <string name="zen_priority_introduction" msgid="3159291973383796646">"You won\'t be disturbed by sounds and vibrations, except from alarms, reminders, events and callers you specify. You\'ll still hear anything you choose to play including music, videos and games."</string>
@@ -573,8 +573,7 @@
     <string name="notification_section_header_conversations" msgid="821834744538345661">"Conversations"</string>
     <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Clear all silent notifications"</string>
     <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Notifications paused by Do Not Disturb"</string>
-    <!-- no translation found for modes_suppressing_shade_text (6037581130837903239) -->
-    <skip />
+    <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{No notifications}=1{Notifications paused by {mode}}=2{Notifications paused by {mode} and one other mode}other{Notifications paused by {mode} and # other modes}}"</string>
     <string name="media_projection_action_text" msgid="3634906766918186440">"Start now"</string>
     <string name="empty_shade_text" msgid="8935967157319717412">"No notifications"</string>
     <string name="no_unseen_notif_text" msgid="395512586119868682">"No new notifications"</string>
@@ -673,6 +672,10 @@
     <string name="stream_notification_unavailable" msgid="4313854556205836435">"Unavailable because ring is muted"</string>
     <string name="stream_alarm_unavailable" msgid="4059817189292197839">"Unavailable because Do Not Disturb is on"</string>
     <string name="stream_media_unavailable" msgid="6823020894438959853">"Unavailable because Do Not Disturb is on"</string>
+    <!-- no translation found for stream_unavailable_by_modes (3674139029490353683) -->
+    <skip />
+    <!-- no translation found for stream_unavailable_by_unknown (6908434629318171588) -->
+    <skip />
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Tap to unmute."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Tap to set to vibrate. Accessibility services may be muted."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Tap to mute. Accessibility services may be muted."</string>
@@ -706,6 +709,7 @@
     <string name="show_demo_mode" msgid="3677956462273059726">"Show demo mode"</string>
     <string name="status_bar_ethernet" msgid="5690979758988647484">"Ethernet"</string>
     <string name="status_bar_alarm" msgid="87160847643623352">"Alarm"</string>
+    <string name="active_mode_content_description" msgid="1627555562186515927">"<xliff:g id="MODENAME">%1$s</xliff:g> is on"</string>
     <string name="wallet_title" msgid="5369767670735827105">"Wallet"</string>
     <string name="wallet_empty_state_label" msgid="7776761245237530394">"Get set up to make faster, more secure purchases with your phone"</string>
     <string name="wallet_app_button_label" msgid="7123784239111190992">"Show all"</string>
@@ -1405,26 +1409,26 @@
     <string name="launch_touchpad_tutorial_notification_content" msgid="7931085031240753226">"Learn touchpad gestures"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_title" msgid="1940023776496198762">"Navigate using your keyboard and touchpad"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Learn touchpad gestures, keyboards shortcuts and more"</string>
-    <string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Back gesture"</string>
-    <string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Home gesture"</string>
+    <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"Go back"</string>
+    <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Go home"</string>
     <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"View recent apps"</string>
     <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Done"</string>
     <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Go back"</string>
-    <string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"To go back, swipe left or right using three fingers anywhere on the touchpad.\n\nYou can also use the keyboard shortcut Action + Esc for this."</string>
-    <string name="touchpad_back_gesture_success_title" msgid="7240576648330612171">"Great work!"</string>
+    <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"Swipe left or right using three fingers on your touchpad"</string>
+    <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"Nice!"</string>
     <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"You completed the go back gesture."</string>
     <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"Go home"</string>
-    <string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"To go to your home screen at any time, swipe up with three fingers from the bottom of your screen."</string>
-    <string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Nice!"</string>
-    <string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"You completed the go home gesture."</string>
+    <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"Swipe up with three fingers on your touchpad"</string>
+    <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"Well done!"</string>
+    <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"You completed the go home gesture"</string>
     <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"View recent apps"</string>
-    <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"Swipe up and hold using three fingers on your touchpad."</string>
+    <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"Swipe up and hold using three fingers on your touchpad"</string>
     <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Well done!"</string>
     <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"You completed the view recent apps gesture."</string>
-    <string name="tutorial_action_key_title" msgid="2659466586996495447">"Action key"</string>
-    <string name="tutorial_action_key_guidance" msgid="5718948664616999196">"To access your apps, press the action key on your keyboard."</string>
-    <string name="tutorial_action_key_success_title" msgid="466467860120112933">"Congratulations!"</string>
-    <string name="tutorial_action_key_success_body" msgid="7201991081652850430">"You completed the action key gesture.\n\nAction + / shows all the shortcuts that you have available."</string>
+    <string name="tutorial_action_key_title" msgid="8172535792469008169">"View all apps"</string>
+    <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Press the action key on your keyboard"</string>
+    <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Well done!"</string>
+    <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"You completed the view all apps gesture"</string>
     <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Keyboard backlight"</string>
     <string name="keyboard_backlight_value" msgid="7336398765584393538">"Level %1$d of %2$d"</string>
     <string name="home_controls_dream_label" msgid="6567105701292324257">"Home controls"</string>
@@ -1436,6 +1440,7 @@
     <string name="all_apps_edu_toast_content" msgid="8807496014667211562">"To view all your apps, press the action key on your keyboard"</string>
     <string name="redacted_notification_single_line_title" msgid="212019960919261670">"Redacted"</string>
     <string name="redacted_notification_single_line_text" msgid="8684166405005242945">"Unlock to view"</string>
+    <string name="contextual_education_dialog_title" msgid="4630392552837487324">"Contextual education"</string>
     <string name="back_edu_notification_title" msgid="5624780717751357278">"Use your touchpad to go back"</string>
     <string name="back_edu_notification_content" msgid="2497557451540954068">"Swipe left or right using three fingers. Tap to learn more gestures."</string>
     <string name="home_edu_notification_title" msgid="6097902076909654045">"Use your touchpad to go home"</string>
diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml
index 4fcc7a4..a26d161 100644
--- a/packages/SystemUI/res/values-en-rCA/strings.xml
+++ b/packages/SystemUI/res/values-en-rCA/strings.xml
@@ -440,7 +440,7 @@
     <string name="zen_mode_on" msgid="9085304934016242591">"On"</string>
     <string name="zen_mode_on_with_details" msgid="7416143430557895497">"On • <xliff:g id="TRIGGER_DESCRIPTION">%1$s</xliff:g>"</string>
     <string name="zen_mode_off" msgid="1736604456618147306">"Off"</string>
-    <string name="zen_mode_set_up" msgid="7457957033034460064">"Set up"</string>
+    <string name="zen_mode_set_up" msgid="8231201163894922821">"Not set"</string>
     <string name="zen_mode_no_manual_invocation" msgid="1769975741344633672">"Manage in settings"</string>
     <string name="zen_mode_active_modes" msgid="1625850411578488856">"{count,plural, =0{No active modes}=1{{mode} is active}other{# modes are active}}"</string>
     <string name="zen_priority_introduction" msgid="3159291973383796646">"You won\'t be disturbed by sounds and vibrations, except from alarms, reminders, events, and callers you specify. You\'ll still hear anything you choose to play including music, videos, and games."</string>
@@ -672,6 +672,10 @@
     <string name="stream_notification_unavailable" msgid="4313854556205836435">"Unavailable because ring is muted"</string>
     <string name="stream_alarm_unavailable" msgid="4059817189292197839">"Unavailable because Do Not Disturb is on"</string>
     <string name="stream_media_unavailable" msgid="6823020894438959853">"Unavailable because Do Not Disturb is on"</string>
+    <!-- no translation found for stream_unavailable_by_modes (3674139029490353683) -->
+    <skip />
+    <!-- no translation found for stream_unavailable_by_unknown (6908434629318171588) -->
+    <skip />
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Tap to unmute."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Tap to set to vibrate. Accessibility services may be muted."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Tap to mute. Accessibility services may be muted."</string>
@@ -705,6 +709,7 @@
     <string name="show_demo_mode" msgid="3677956462273059726">"Show demo mode"</string>
     <string name="status_bar_ethernet" msgid="5690979758988647484">"Ethernet"</string>
     <string name="status_bar_alarm" msgid="87160847643623352">"Alarm"</string>
+    <string name="active_mode_content_description" msgid="1627555562186515927">"<xliff:g id="MODENAME">%1$s</xliff:g> is on"</string>
     <string name="wallet_title" msgid="5369767670735827105">"Wallet"</string>
     <string name="wallet_empty_state_label" msgid="7776761245237530394">"Get set up to make faster, more secure purchases with your phone"</string>
     <string name="wallet_app_button_label" msgid="7123784239111190992">"Show all"</string>
@@ -1404,26 +1409,26 @@
     <string name="launch_touchpad_tutorial_notification_content" msgid="7931085031240753226">"Learn touchpad gestures"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_title" msgid="1940023776496198762">"Navigate using your keyboard and touchpad"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Learn touchpad gestures, keyboards shortcuts, and more"</string>
-    <string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Back gesture"</string>
-    <string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Home gesture"</string>
+    <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"Go back"</string>
+    <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Go home"</string>
     <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"View recent apps"</string>
     <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Done"</string>
     <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Go back"</string>
-    <string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"To go back, swipe left or right using three fingers anywhere on the touchpad.\n\nYou can also use the keyboard shortcut Action + ESC for this."</string>
-    <string name="touchpad_back_gesture_success_title" msgid="7240576648330612171">"Great job!"</string>
+    <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"Swipe left or right using three fingers on your touchpad"</string>
+    <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"Nice!"</string>
     <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"You completed the go back gesture."</string>
     <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"Go home"</string>
-    <string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"To go to your home screen at any time, swipe up with three fingers from the bottom of your screen."</string>
-    <string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Nice!"</string>
-    <string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"You completed the go home gesture."</string>
+    <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"Swipe up with three fingers on your touchpad"</string>
+    <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"Great job!"</string>
+    <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"You completed the go home gesture"</string>
     <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"View recent apps"</string>
-    <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"Swipe up and hold using three fingers on your touchpad."</string>
+    <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"Swipe up and hold using three fingers on your touchpad"</string>
     <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Great job!"</string>
     <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"You completed the view recent apps gesture."</string>
-    <string name="tutorial_action_key_title" msgid="2659466586996495447">"Action key"</string>
-    <string name="tutorial_action_key_guidance" msgid="5718948664616999196">"To access your apps, press the action key on your keyboard."</string>
-    <string name="tutorial_action_key_success_title" msgid="466467860120112933">"Congratulations!"</string>
-    <string name="tutorial_action_key_success_body" msgid="7201991081652850430">"You completed the action key gesture.\n\nAction + / shows all the shortcuts you have available."</string>
+    <string name="tutorial_action_key_title" msgid="8172535792469008169">"View all apps"</string>
+    <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Press the action key on your keyboard"</string>
+    <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Well done!"</string>
+    <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"You completed the view all apps gesture"</string>
     <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Keyboard backlight"</string>
     <string name="keyboard_backlight_value" msgid="7336398765584393538">"Level %1$d of %2$d"</string>
     <string name="home_controls_dream_label" msgid="6567105701292324257">"Home Controls"</string>
@@ -1435,6 +1440,7 @@
     <string name="all_apps_edu_toast_content" msgid="8807496014667211562">"To view all your apps, press the action key on your keyboard"</string>
     <string name="redacted_notification_single_line_title" msgid="212019960919261670">"Redacted"</string>
     <string name="redacted_notification_single_line_text" msgid="8684166405005242945">"Unlock to view"</string>
+    <string name="contextual_education_dialog_title" msgid="4630392552837487324">"Contextual education"</string>
     <string name="back_edu_notification_title" msgid="5624780717751357278">"Use your touchpad to go back"</string>
     <string name="back_edu_notification_content" msgid="2497557451540954068">"Swipe left or right using three fingers. Tap to learn more gestures."</string>
     <string name="home_edu_notification_title" msgid="6097902076909654045">"Use your touchpad to go home"</string>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index cea405b..ba945f2 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -440,7 +440,7 @@
     <string name="zen_mode_on" msgid="9085304934016242591">"On"</string>
     <string name="zen_mode_on_with_details" msgid="7416143430557895497">"On • <xliff:g id="TRIGGER_DESCRIPTION">%1$s</xliff:g>"</string>
     <string name="zen_mode_off" msgid="1736604456618147306">"Off"</string>
-    <string name="zen_mode_set_up" msgid="7457957033034460064">"Set up"</string>
+    <string name="zen_mode_set_up" msgid="8231201163894922821">"Not set"</string>
     <string name="zen_mode_no_manual_invocation" msgid="1769975741344633672">"Manage in settings"</string>
     <string name="zen_mode_active_modes" msgid="1625850411578488856">"{count,plural, =0{No active modes}=1{{mode} is active}other{# modes are active}}"</string>
     <string name="zen_priority_introduction" msgid="3159291973383796646">"You won\'t be disturbed by sounds and vibrations, except from alarms, reminders, events and callers you specify. You\'ll still hear anything you choose to play including music, videos and games."</string>
@@ -672,6 +672,10 @@
     <string name="stream_notification_unavailable" msgid="4313854556205836435">"Unavailable because ring is muted"</string>
     <string name="stream_alarm_unavailable" msgid="4059817189292197839">"Unavailable because Do Not Disturb is on"</string>
     <string name="stream_media_unavailable" msgid="6823020894438959853">"Unavailable because Do Not Disturb is on"</string>
+    <!-- no translation found for stream_unavailable_by_modes (3674139029490353683) -->
+    <skip />
+    <!-- no translation found for stream_unavailable_by_unknown (6908434629318171588) -->
+    <skip />
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Tap to unmute."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Tap to set to vibrate. Accessibility services may be muted."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Tap to mute. Accessibility services may be muted."</string>
@@ -705,6 +709,7 @@
     <string name="show_demo_mode" msgid="3677956462273059726">"Show demo mode"</string>
     <string name="status_bar_ethernet" msgid="5690979758988647484">"Ethernet"</string>
     <string name="status_bar_alarm" msgid="87160847643623352">"Alarm"</string>
+    <string name="active_mode_content_description" msgid="1627555562186515927">"<xliff:g id="MODENAME">%1$s</xliff:g> is on"</string>
     <string name="wallet_title" msgid="5369767670735827105">"Wallet"</string>
     <string name="wallet_empty_state_label" msgid="7776761245237530394">"Get set up to make faster, more secure purchases with your phone"</string>
     <string name="wallet_app_button_label" msgid="7123784239111190992">"Show all"</string>
@@ -1404,26 +1409,26 @@
     <string name="launch_touchpad_tutorial_notification_content" msgid="7931085031240753226">"Learn touchpad gestures"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_title" msgid="1940023776496198762">"Navigate using your keyboard and touchpad"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Learn touchpad gestures, keyboards shortcuts and more"</string>
-    <string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Back gesture"</string>
-    <string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Home gesture"</string>
+    <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"Go back"</string>
+    <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Go home"</string>
     <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"View recent apps"</string>
     <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Done"</string>
     <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Go back"</string>
-    <string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"To go back, swipe left or right using three fingers anywhere on the touchpad.\n\nYou can also use the keyboard shortcut Action + Esc for this."</string>
-    <string name="touchpad_back_gesture_success_title" msgid="7240576648330612171">"Great work!"</string>
+    <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"Swipe left or right using three fingers on your touchpad"</string>
+    <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"Nice!"</string>
     <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"You completed the go back gesture."</string>
     <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"Go home"</string>
-    <string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"To go to your home screen at any time, swipe up with three fingers from the bottom of your screen."</string>
-    <string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Nice!"</string>
-    <string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"You completed the go home gesture."</string>
+    <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"Swipe up with three fingers on your touchpad"</string>
+    <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"Well done!"</string>
+    <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"You completed the go home gesture"</string>
     <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"View recent apps"</string>
-    <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"Swipe up and hold using three fingers on your touchpad."</string>
+    <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"Swipe up and hold using three fingers on your touchpad"</string>
     <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Well done!"</string>
     <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"You completed the view recent apps gesture."</string>
-    <string name="tutorial_action_key_title" msgid="2659466586996495447">"Action key"</string>
-    <string name="tutorial_action_key_guidance" msgid="5718948664616999196">"To access your apps, press the action key on your keyboard."</string>
-    <string name="tutorial_action_key_success_title" msgid="466467860120112933">"Congratulations!"</string>
-    <string name="tutorial_action_key_success_body" msgid="7201991081652850430">"You completed the action key gesture.\n\nAction + / shows all the shortcuts that you have available."</string>
+    <string name="tutorial_action_key_title" msgid="8172535792469008169">"View all apps"</string>
+    <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Press the action key on your keyboard"</string>
+    <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Well done!"</string>
+    <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"You completed the view all apps gesture"</string>
     <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Keyboard backlight"</string>
     <string name="keyboard_backlight_value" msgid="7336398765584393538">"Level %1$d of %2$d"</string>
     <string name="home_controls_dream_label" msgid="6567105701292324257">"Home controls"</string>
@@ -1435,8 +1440,7 @@
     <string name="all_apps_edu_toast_content" msgid="8807496014667211562">"To view all your apps, press the action key on your keyboard"</string>
     <string name="redacted_notification_single_line_title" msgid="212019960919261670">"Redacted"</string>
     <string name="redacted_notification_single_line_text" msgid="8684166405005242945">"Unlock to view"</string>
-    <!-- no translation found for contextual_education_dialog_title (4630392552837487324) -->
-    <skip />
+    <string name="contextual_education_dialog_title" msgid="4630392552837487324">"Contextual education"</string>
     <string name="back_edu_notification_title" msgid="5624780717751357278">"Use your touchpad to go back"</string>
     <string name="back_edu_notification_content" msgid="2497557451540954068">"Swipe left or right using three fingers. Tap to learn more gestures."</string>
     <string name="home_edu_notification_title" msgid="6097902076909654045">"Use your touchpad to go home"</string>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index 9b7ae5d..ba945f2 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -440,7 +440,7 @@
     <string name="zen_mode_on" msgid="9085304934016242591">"On"</string>
     <string name="zen_mode_on_with_details" msgid="7416143430557895497">"On • <xliff:g id="TRIGGER_DESCRIPTION">%1$s</xliff:g>"</string>
     <string name="zen_mode_off" msgid="1736604456618147306">"Off"</string>
-    <string name="zen_mode_set_up" msgid="7457957033034460064">"Set up"</string>
+    <string name="zen_mode_set_up" msgid="8231201163894922821">"Not set"</string>
     <string name="zen_mode_no_manual_invocation" msgid="1769975741344633672">"Manage in settings"</string>
     <string name="zen_mode_active_modes" msgid="1625850411578488856">"{count,plural, =0{No active modes}=1{{mode} is active}other{# modes are active}}"</string>
     <string name="zen_priority_introduction" msgid="3159291973383796646">"You won\'t be disturbed by sounds and vibrations, except from alarms, reminders, events and callers you specify. You\'ll still hear anything you choose to play including music, videos and games."</string>
@@ -573,8 +573,7 @@
     <string name="notification_section_header_conversations" msgid="821834744538345661">"Conversations"</string>
     <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Clear all silent notifications"</string>
     <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Notifications paused by Do Not Disturb"</string>
-    <!-- no translation found for modes_suppressing_shade_text (6037581130837903239) -->
-    <skip />
+    <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{No notifications}=1{Notifications paused by {mode}}=2{Notifications paused by {mode} and one other mode}other{Notifications paused by {mode} and # other modes}}"</string>
     <string name="media_projection_action_text" msgid="3634906766918186440">"Start now"</string>
     <string name="empty_shade_text" msgid="8935967157319717412">"No notifications"</string>
     <string name="no_unseen_notif_text" msgid="395512586119868682">"No new notifications"</string>
@@ -673,6 +672,10 @@
     <string name="stream_notification_unavailable" msgid="4313854556205836435">"Unavailable because ring is muted"</string>
     <string name="stream_alarm_unavailable" msgid="4059817189292197839">"Unavailable because Do Not Disturb is on"</string>
     <string name="stream_media_unavailable" msgid="6823020894438959853">"Unavailable because Do Not Disturb is on"</string>
+    <!-- no translation found for stream_unavailable_by_modes (3674139029490353683) -->
+    <skip />
+    <!-- no translation found for stream_unavailable_by_unknown (6908434629318171588) -->
+    <skip />
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Tap to unmute."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Tap to set to vibrate. Accessibility services may be muted."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Tap to mute. Accessibility services may be muted."</string>
@@ -706,6 +709,7 @@
     <string name="show_demo_mode" msgid="3677956462273059726">"Show demo mode"</string>
     <string name="status_bar_ethernet" msgid="5690979758988647484">"Ethernet"</string>
     <string name="status_bar_alarm" msgid="87160847643623352">"Alarm"</string>
+    <string name="active_mode_content_description" msgid="1627555562186515927">"<xliff:g id="MODENAME">%1$s</xliff:g> is on"</string>
     <string name="wallet_title" msgid="5369767670735827105">"Wallet"</string>
     <string name="wallet_empty_state_label" msgid="7776761245237530394">"Get set up to make faster, more secure purchases with your phone"</string>
     <string name="wallet_app_button_label" msgid="7123784239111190992">"Show all"</string>
@@ -1405,26 +1409,26 @@
     <string name="launch_touchpad_tutorial_notification_content" msgid="7931085031240753226">"Learn touchpad gestures"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_title" msgid="1940023776496198762">"Navigate using your keyboard and touchpad"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Learn touchpad gestures, keyboards shortcuts and more"</string>
-    <string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Back gesture"</string>
-    <string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Home gesture"</string>
+    <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"Go back"</string>
+    <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Go home"</string>
     <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"View recent apps"</string>
     <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Done"</string>
     <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Go back"</string>
-    <string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"To go back, swipe left or right using three fingers anywhere on the touchpad.\n\nYou can also use the keyboard shortcut Action + Esc for this."</string>
-    <string name="touchpad_back_gesture_success_title" msgid="7240576648330612171">"Great work!"</string>
+    <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"Swipe left or right using three fingers on your touchpad"</string>
+    <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"Nice!"</string>
     <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"You completed the go back gesture."</string>
     <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"Go home"</string>
-    <string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"To go to your home screen at any time, swipe up with three fingers from the bottom of your screen."</string>
-    <string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Nice!"</string>
-    <string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"You completed the go home gesture."</string>
+    <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"Swipe up with three fingers on your touchpad"</string>
+    <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"Well done!"</string>
+    <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"You completed the go home gesture"</string>
     <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"View recent apps"</string>
-    <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"Swipe up and hold using three fingers on your touchpad."</string>
+    <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"Swipe up and hold using three fingers on your touchpad"</string>
     <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Well done!"</string>
     <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"You completed the view recent apps gesture."</string>
-    <string name="tutorial_action_key_title" msgid="2659466586996495447">"Action key"</string>
-    <string name="tutorial_action_key_guidance" msgid="5718948664616999196">"To access your apps, press the action key on your keyboard."</string>
-    <string name="tutorial_action_key_success_title" msgid="466467860120112933">"Congratulations!"</string>
-    <string name="tutorial_action_key_success_body" msgid="7201991081652850430">"You completed the action key gesture.\n\nAction + / shows all the shortcuts that you have available."</string>
+    <string name="tutorial_action_key_title" msgid="8172535792469008169">"View all apps"</string>
+    <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Press the action key on your keyboard"</string>
+    <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Well done!"</string>
+    <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"You completed the view all apps gesture"</string>
     <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Keyboard backlight"</string>
     <string name="keyboard_backlight_value" msgid="7336398765584393538">"Level %1$d of %2$d"</string>
     <string name="home_controls_dream_label" msgid="6567105701292324257">"Home controls"</string>
@@ -1436,6 +1440,7 @@
     <string name="all_apps_edu_toast_content" msgid="8807496014667211562">"To view all your apps, press the action key on your keyboard"</string>
     <string name="redacted_notification_single_line_title" msgid="212019960919261670">"Redacted"</string>
     <string name="redacted_notification_single_line_text" msgid="8684166405005242945">"Unlock to view"</string>
+    <string name="contextual_education_dialog_title" msgid="4630392552837487324">"Contextual education"</string>
     <string name="back_edu_notification_title" msgid="5624780717751357278">"Use your touchpad to go back"</string>
     <string name="back_edu_notification_content" msgid="2497557451540954068">"Swipe left or right using three fingers. Tap to learn more gestures."</string>
     <string name="home_edu_notification_title" msgid="6097902076909654045">"Use your touchpad to go home"</string>
diff --git a/packages/SystemUI/res/values-en-rXC/strings.xml b/packages/SystemUI/res/values-en-rXC/strings.xml
index 3c22ed1..b70fdeb 100644
--- a/packages/SystemUI/res/values-en-rXC/strings.xml
+++ b/packages/SystemUI/res/values-en-rXC/strings.xml
@@ -440,7 +440,7 @@
     <string name="zen_mode_on" msgid="9085304934016242591">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‎‎‎‎‏‎‏‎‏‎‏‏‏‏‏‎‎‏‎‏‏‎‎‏‏‏‎‎‏‎‏‎‎‎‎‏‎‎‏‎‎‎‏‎‏‎‎‏‏‏‎‎‏‏‏‏‏‎On‎‏‎‎‏‎"</string>
     <string name="zen_mode_on_with_details" msgid="7416143430557895497">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‏‏‎‏‏‏‎‏‎‏‏‎‏‏‎‏‏‏‏‎‎‏‎‏‎‎‎‎‏‎‏‏‏‎‏‏‏‎‎‎‎‎‎‎‎‎‎‏‎‏‏‎‏‎‎‏‎‎‏‎On • ‎‏‎‎‏‏‎<xliff:g id="TRIGGER_DESCRIPTION">%1$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
     <string name="zen_mode_off" msgid="1736604456618147306">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‎‎‎‎‎‏‏‎‎‏‏‎‏‎‏‎‎‎‏‎‎‎‏‏‎‏‎‏‏‎‏‎‎‎‎‎‎‏‎‏‎‏‏‎‏‏‏‏‎‏‏‏‏‎‏‎‏‎‎Off‎‏‎‎‏‎"</string>
-    <string name="zen_mode_set_up" msgid="7457957033034460064">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‏‏‏‎‏‏‏‏‏‏‏‏‏‏‏‏‏‎‎‎‏‏‎‏‎‎‎‎‏‎‏‏‎‎‎‎‎‏‎‎‏‎‏‎‎‏‎‏‎‏‏‏‎‏‎‎‎‎‎‎Set up‎‏‎‎‏‎"</string>
+    <string name="zen_mode_set_up" msgid="8231201163894922821">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‏‎‎‎‏‏‏‎‏‏‎‎‎‏‏‎‎‏‏‏‎‏‏‎‎‏‎‎‎‎‏‎‎‎‏‎‏‏‏‏‎‏‎‎‎‏‏‏‏‎‎‏‎‎‎‏‎‏‎Not set‎‏‎‎‏‎"</string>
     <string name="zen_mode_no_manual_invocation" msgid="1769975741344633672">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‎‎‏‎‎‏‎‎‎‎‎‎‏‏‎‏‏‏‏‎‎‎‏‏‏‏‎‎‎‏‏‎‏‏‏‏‏‎‎‏‏‏‏‏‎‏‎‎‏‏‎‏‎‎‏‎‎‎‎Manage in settings‎‏‎‎‏‎"</string>
     <string name="zen_mode_active_modes" msgid="1625850411578488856">"{count,plural, =0{‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‏‏‎‏‎‎‏‎‎‎‎‎‎‏‎‏‏‏‎‎‏‎‏‎‏‎‏‏‏‎‏‎‎‎‎‎‎‎‎‏‏‏‎‏‏‏‏‏‎‎‎‎‎‎‏‏‎‎‎‎No active modes‎‏‎‎‏‎}=1{‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‏‏‎‏‎‎‏‎‎‎‎‎‎‏‎‏‏‏‎‎‏‎‏‎‏‎‏‏‏‎‏‎‎‎‎‎‎‎‎‏‏‏‎‏‏‏‏‏‎‎‎‎‎‎‏‏‎‎‎‎‎‏‎‎‏‏‎{mode}‎‏‎‎‏‏‏‎ is active‎‏‎‎‏‎}other{‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‏‏‎‏‎‎‏‎‎‎‎‎‎‏‎‏‏‏‎‎‏‎‏‎‏‎‏‏‏‎‏‎‎‎‎‎‎‎‎‏‏‏‎‏‏‏‏‏‎‎‎‎‎‎‏‏‎‎‎‎# modes are active‎‏‎‎‏‎}}"</string>
     <string name="zen_priority_introduction" msgid="3159291973383796646">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‏‏‏‏‎‏‏‎‎‎‎‎‎‎‏‏‏‏‎‏‎‎‏‏‏‏‏‎‏‎‎‏‏‏‎‏‎‎‏‎‎‎‏‎‏‏‎‏‏‏‏‎‏‎‎‏‏‎‎You won\'t be disturbed by sounds and vibrations, except from alarms, reminders, events, and callers you specify. You\'ll still hear anything you choose to play including music, videos, and games.‎‏‎‎‏‎"</string>
@@ -672,6 +672,10 @@
     <string name="stream_notification_unavailable" msgid="4313854556205836435">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‎‏‏‏‏‎‏‏‏‎‏‏‏‏‎‎‎‏‏‏‏‎‏‏‏‎‎‏‏‏‏‎‎‏‏‎‏‎‏‏‎‎‏‎‏‏‎‏‎‎‎‏‎‎‏‎‎‏‏‎Unavailable because ring is muted‎‏‎‎‏‎"</string>
     <string name="stream_alarm_unavailable" msgid="4059817189292197839">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‎‎‎‎‏‎‏‎‏‏‏‎‏‎‏‏‏‏‎‎‎‏‏‏‎‎‏‎‏‎‎‏‏‎‎‏‏‎‎‏‎‎‏‎‏‎‎‎‏‏‏‏‏‎‎‏‏‏‏‎Unavailable because Do Not Disturb is on‎‏‎‎‏‎"</string>
     <string name="stream_media_unavailable" msgid="6823020894438959853">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‏‎‏‎‏‏‎‎‎‎‎‎‏‏‏‏‎‏‎‏‎‏‏‎‏‎‏‎‎‎‎‏‎‎‎‎‎‏‏‎‏‎‎‎‏‎‏‎‏‎‏‏‏‎‏‏‎‏‎Unavailable because Do Not Disturb is on‎‏‎‎‏‎"</string>
+    <!-- no translation found for stream_unavailable_by_modes (3674139029490353683) -->
+    <skip />
+    <!-- no translation found for stream_unavailable_by_unknown (6908434629318171588) -->
+    <skip />
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‏‏‎‏‎‎‎‏‎‎‏‏‏‏‏‎‎‎‏‏‎‎‎‎‎‏‏‎‏‏‏‎‎‏‏‏‏‏‎‏‎‎‎‏‏‎‏‎‎‏‎‎‎‏‎‎‎‏‎%1$s. Tap to unmute.‎‏‎‎‏‎"</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‎‏‏‎‏‏‎‏‎‏‏‎‏‏‏‏‎‏‏‎‎‎‏‏‏‏‎‏‎‎‎‏‏‎‎‎‏‎‏‏‎‎‎‏‏‏‏‏‏‏‎‎‏‏‎‎‎‎‏‎%1$s. Tap to set to vibrate. Accessibility services may be muted.‎‏‎‎‏‎"</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‎‎‎‏‎‎‏‏‎‏‏‏‎‏‎‏‏‏‏‎‏‏‏‎‎‎‎‎‏‏‎‏‏‎‏‎‎‏‏‏‎‏‏‎‏‎‏‏‏‎‎‏‏‎‏‏‎‎‎‎%1$s. Tap to mute. Accessibility services may be muted.‎‏‎‎‏‎"</string>
@@ -705,6 +709,7 @@
     <string name="show_demo_mode" msgid="3677956462273059726">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‏‏‎‎‎‎‏‎‏‎‏‎‏‏‏‎‎‏‏‏‏‎‏‎‏‎‎‏‏‏‎‎‎‏‎‎‏‎‎‎‏‏‎‏‎‏‏‎‏‏‏‎‎‎‏‏‏‎‎Show demo mode‎‏‎‎‏‎"</string>
     <string name="status_bar_ethernet" msgid="5690979758988647484">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‏‏‎‏‏‏‏‏‎‏‎‎‏‏‎‏‎‏‏‏‏‏‏‎‎‎‎‎‏‎‎‏‏‏‎‎‏‏‏‎‏‎‎‏‏‎‏‏‏‎‎‎‎‏‏‏‏‎‎‎Ethernet‎‏‎‎‏‎"</string>
     <string name="status_bar_alarm" msgid="87160847643623352">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‎‏‏‎‎‏‏‎‏‎‏‏‎‏‎‏‎‎‎‎‏‎‏‎‏‎‎‎‏‎‎‎‎‏‎‎‎‎‏‏‏‏‎‏‎‏‏‏‏‏‏‏‎‏‏‏‎‎‎‎Alarm‎‏‎‎‏‎"</string>
+    <string name="active_mode_content_description" msgid="1627555562186515927">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‏‏‎‏‎‎‏‎‏‏‎‎‎‏‏‏‏‎‏‎‎‏‎‏‎‎‏‎‎‏‎‎‎‎‎‎‏‎‏‎‏‏‎‏‎‏‎‎‏‎‏‏‏‎‏‎‏‏‏‎‎‏‎‎‏‏‎<xliff:g id="MODENAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎ is on‎‏‎‎‏‎"</string>
     <string name="wallet_title" msgid="5369767670735827105">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‎‏‎‏‎‎‎‎‏‎‏‎‎‏‏‏‏‏‏‎‎‏‏‏‏‏‏‎‎‎‎‏‏‎‎‏‎‎‏‎‏‎‏‏‏‏‏‎‎‎‎‏‎‏‎‎‎‎‏‎Wallet‎‏‎‎‏‎"</string>
     <string name="wallet_empty_state_label" msgid="7776761245237530394">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‏‏‏‏‏‎‏‏‎‎‏‎‎‏‏‎‏‏‎‎‏‎‎‏‏‎‎‏‎‎‎‏‎‏‎‏‏‎‏‎‎‎‎‏‎‎‏‏‏‏‎‎‎‏‏‎‏‎‎Get set up to make faster, more secure purchases with your phone‎‏‎‎‏‎"</string>
     <string name="wallet_app_button_label" msgid="7123784239111190992">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‎‏‎‏‏‎‏‏‏‎‎‏‏‎‎‎‏‎‎‎‎‎‎‎‏‎‏‏‎‏‎‎‏‎‎‏‎‏‏‏‏‏‏‏‎‏‏‏‎‎‏‏‏‎‏‎‎‎‎‎Show all‎‏‎‎‏‎"</string>
@@ -1404,26 +1409,26 @@
     <string name="launch_touchpad_tutorial_notification_content" msgid="7931085031240753226">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‏‎‎‎‎‏‎‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‎‎‎‎‏‎‏‏‎‎‏‎‏‎‎‎‎‏‎‏‏‏‏‎‎‎‎‎‎‏‎‎‏‎‏‎‎Learn touchpad gestures‎‏‎‎‏‎"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_title" msgid="1940023776496198762">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‏‎‏‏‏‎‏‏‎‎‎‏‎‏‏‎‎‏‎‏‎‏‏‎‎‎‏‎‎‏‎‏‎‏‏‏‎‏‏‏‏‎‎‎‏‎‎‏‎‎‎‏‏‎‏‎‏‎‎Navigate using your keyboard and touchpad‎‏‎‎‏‎"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‎‎‏‎‏‏‎‏‏‎‎‏‏‎‏‎‎‎‎‎‎‏‏‎‏‏‎‎‎‏‎‎‏‏‎‏‏‏‏‏‎‎‎‏‎‎‏‏‏‏‎‎‎‏‎‏‎‏‎Learn touchpad gestures, keyboards shortcuts, and more‎‏‎‎‏‎"</string>
-    <string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‏‎‎‎‎‏‏‏‏‎‏‎‏‏‎‏‏‏‎‎‏‏‏‎‏‏‎‏‎‎‏‏‎‏‏‎‏‏‎‏‎‏‎‏‎‏‏‏‎‎‎‎‎‏‏‎‏‎‎Back gesture‎‏‎‎‏‎"</string>
-    <string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‏‎‎‎‎‎‏‎‎‎‏‎‏‎‏‎‏‏‎‎‎‏‎‎‏‏‎‏‏‎‎‏‎‏‎‏‎‎‎‏‏‏‎‏‏‎‏‏‏‏‏‏‏‎‏‎‎‎‎Home gesture‎‏‎‎‏‎"</string>
+    <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‏‏‎‎‎‏‎‏‏‎‎‎‏‎‏‎‏‏‎‎‎‏‎‏‎‏‏‎‏‏‏‎‎‎‎‎‏‏‏‎‎‏‏‎‎‎‎‎‏‏‏‏‎‏‏‎‏‏‎Go back‎‏‎‎‏‎"</string>
+    <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‏‏‎‏‎‏‏‎‏‎‏‏‏‎‎‎‎‏‎‎‎‏‎‎‏‎‎‎‎‎‎‎‎‏‎‎‏‏‎‏‎‏‎‎‏‏‎‏‏‏‎‎‏‏‏‎‎‎‎Go home‎‏‎‎‏‎"</string>
     <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‎‏‏‏‏‎‎‎‏‏‏‎‏‏‏‎‏‏‎‎‏‎‎‏‎‏‎‎‎‎‏‏‎‎‏‎‎‎‎‏‎‏‎‏‎‏‏‏‎‎‏‎‏‎‏‏‏‏‏‎View recent apps‎‏‎‎‏‎"</string>
     <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‎‏‎‎‏‏‏‎‎‎‏‏‏‏‎‎‎‎‎‎‏‎‎‏‏‏‎‏‎‏‎‎‏‎‎‏‏‎‏‎‏‏‎‏‎‎‎‏‏‏‎‎‏‏‎‏‏‏‏‎Done‎‏‎‎‏‎"</string>
     <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‎‏‏‏‏‏‎‏‎‎‎‎‎‏‏‏‎‎‏‏‎‎‎‎‏‎‏‏‎‏‎‏‏‎‏‎‏‏‎‎‏‏‎‎‏‎‎‎‏‏‏‎‎‏‏‏‏‏‏‎Go back‎‏‎‎‏‎"</string>
-    <string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‏‎‏‏‏‎‏‏‎‏‎‏‎‎‏‏‏‏‏‎‏‎‎‎‏‎‎‎‏‏‏‏‏‎‏‏‎‎‎‎‎‏‏‏‏‏‎‎‎‎‎‏‎‏‎‎‏‏‎To go back, swipe left or right using three fingers anywhere on the touchpad.‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎You can also use the keyboard shortcut Action + ESC for this.‎‏‎‎‏‎"</string>
-    <string name="touchpad_back_gesture_success_title" msgid="7240576648330612171">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‏‎‎‎‏‏‏‏‎‏‏‏‎‏‏‎‎‏‎‎‎‎‏‏‎‎‏‎‏‏‏‎‏‎‎‏‎‏‏‏‏‎‎‎‎‎‎‏‏‎‏‏‏‎‎‏‎‏‏‎Great job!‎‏‎‎‏‎"</string>
+    <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‎‏‎‎‏‎‎‎‏‏‎‏‏‏‎‏‎‎‎‏‎‏‏‏‎‎‎‏‏‎‏‎‏‎‏‎‏‎‎‎‎‎‏‏‏‏‎‏‎‏‎‎‏‏‎‏‏‏‎‎Swipe left or right using three fingers on your touchpad‎‏‎‎‏‎"</string>
+    <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‏‏‎‎‏‎‎‏‎‏‎‎‎‎‎‏‏‎‏‏‏‏‏‎‏‏‏‏‏‏‎‏‏‎‏‎‎‏‏‎‏‎‏‎‏‏‏‎‎‎‎‎‎‎‎‏‎‎‎‎Nice!‎‏‎‎‏‎"</string>
     <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‎‎‎‎‏‎‎‎‎‏‏‎‎‎‏‎‏‎‏‎‎‎‎‎‏‏‏‎‏‎‎‏‎‏‏‎‎‎‎‎‎‏‎‏‏‎‏‏‏‏‏‎‏‎‏‎‏‏‏‎You completed the go back gesture.‎‏‎‎‏‎"</string>
     <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‎‏‏‎‏‎‎‏‏‏‎‎‎‏‏‏‏‏‎‎‎‎‎‏‏‏‏‎‎‏‎‏‎‏‏‎‎‏‏‏‎‏‎‏‎‎‏‎‎‏‏‎‎‎‏‏‎‏‎‎Go home‎‏‎‎‏‎"</string>
-    <string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‏‎‎‎‏‏‏‏‏‎‎‎‏‏‎‏‏‏‎‏‏‏‎‎‎‎‏‏‏‎‎‎‎‎‏‏‎‏‎‎‎‏‏‎‎‏‏‎‏‏‎‎‏‏‏‏‏‎‎To go to your home screen at any time, swipe up with three fingers from the bottom of your screen.‎‏‎‎‏‎"</string>
-    <string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‏‎‎‎‏‏‎‏‏‏‏‏‎‎‏‏‎‎‏‎‎‏‎‎‏‏‎‏‎‏‏‎‏‏‏‎‎‏‎‏‏‏‎‎‏‎‏‎‏‏‎‏‎‎‎‎‎‏‏‎Nice!‎‏‎‎‏‎"</string>
-    <string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‎‎‏‎‏‎‏‏‏‎‎‏‏‎‏‎‏‎‏‏‎‎‎‏‎‏‏‎‎‏‏‎‎‎‏‏‎‏‎‎‎‎‎‏‏‏‏‏‏‏‎‎‎‎‏‏‎‏‏‎You completed the go home gesture.‎‏‎‎‏‎"</string>
+    <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‎‎‏‏‏‏‏‏‏‎‎‎‎‎‎‎‏‎‎‎‎‏‎‎‏‏‎‏‎‏‎‏‎‎‎‏‏‏‎‎‏‏‎‎‏‎‏‏‏‏‎‏‏‏‏‏‎‏‏‎Swipe up with three fingers on your touchpad‎‏‎‎‏‎"</string>
+    <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‏‎‏‎‏‎‎‎‎‏‎‎‏‏‏‏‎‏‎‏‎‎‏‎‎‎‎‎‏‏‏‏‏‎‏‎‏‏‎‏‎‎‏‏‏‏‎‏‎‎‎‏‎‎‎‏‏‎‎Great job!‎‏‎‎‏‎"</string>
+    <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‎‏‏‏‏‏‏‎‎‏‏‏‏‏‏‏‎‏‏‎‏‎‏‏‏‎‏‎‏‏‎‎‎‏‏‏‏‎‏‏‎‏‏‏‎‎‎‎‎‎‎‎‎‏‏‎‎‏‏‎You completed the go home gesture‎‏‎‎‏‎"</string>
     <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‎‎‏‏‏‏‏‎‎‏‎‏‏‏‎‏‎‎‏‏‎‏‎‎‎‎‏‎‎‏‎‏‎‏‏‎‎‎‏‏‎‎‏‏‎‎‎‎‎‏‎‏‏‏‎‎‏‎‎View recent apps‎‏‎‎‏‎"</string>
-    <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‎‏‏‎‏‏‎‏‏‏‏‎‎‎‏‏‏‏‎‎‎‏‏‎‏‏‎‏‎‎‏‎‎‎‎‎‎‏‏‏‏‏‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎Swipe up and hold using three fingers on your touchpad.‎‏‎‎‏‎"</string>
+    <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‏‏‎‏‏‏‏‏‎‏‏‏‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‎‎‎‏‎‏‏‎‎‏‎‎‎‏‎‏‏‏‎‎‏‎‎‏‏‏‎‎Swipe up and hold using three fingers on your touchpad‎‏‎‎‏‎"</string>
     <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‏‎‏‏‎‏‏‎‏‎‏‏‏‎‏‎‏‎‏‏‏‎‎‏‏‏‎‎‎‎‎‏‎‏‎‏‎‎‎‏‏‏‏‎‎‏‎‏‏‏‏‏‏‏‏‎‎‎‏‎Great job!‎‏‎‎‏‎"</string>
     <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‏‎‎‎‎‏‎‎‏‏‎‎‏‏‎‎‏‏‎‎‎‎‎‏‏‏‏‎‎‏‎‏‎‎‏‏‎‎‎‎‎‎‎‎‎‏‏‏‎‏‏‎‎‎‏‏‎‎‏‎You completed the view recent apps gesture.‎‏‎‎‏‎"</string>
-    <string name="tutorial_action_key_title" msgid="2659466586996495447">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‎‎‏‏‏‎‏‎‎‎‎‏‎‏‎‎‏‎‏‏‎‎‎‏‎‏‎‎‏‏‏‎‎‏‏‏‏‏‎‎‏‎‎‏‎‏‎‏‎‎‎‏‎‏‎‏‏‏‎Action key‎‏‎‎‏‎"</string>
-    <string name="tutorial_action_key_guidance" msgid="5718948664616999196">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‏‏‏‎‏‎‏‏‏‎‏‏‏‎‎‏‎‎‏‏‎‎‎‎‎‏‎‏‎‎‏‏‎‏‏‎‎‏‏‎‎‎‎‏‏‎‏‏‎‎‏‎‎‎‏‏‏‎‎‎To access your apps, press the action key on your keyboard.‎‏‎‎‏‎"</string>
-    <string name="tutorial_action_key_success_title" msgid="466467860120112933">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‏‏‏‎‎‏‏‏‏‎‎‏‎‎‏‏‏‎‏‎‎‎‎‎‏‏‎‎‎‎‎‏‏‏‎‏‏‎‎‏‏‎‎‎‏‎‎‎‏‏‏‏‎‎‏‎‎‏‎‏‎Congratulations!‎‏‎‎‏‎"</string>
-    <string name="tutorial_action_key_success_body" msgid="7201991081652850430">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‎‏‏‏‏‏‏‎‎‏‎‏‎‎‏‏‏‎‎‏‎‏‏‏‎‏‏‎‎‏‎‎‎‎‏‎‏‏‏‎‎‏‏‎‎‎‎‏‏‏‎‏‏‏‏‏‏‏‎‎You completed the action key gesture.‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎Action + / shows all the shortcuts you have available.‎‏‎‎‏‎"</string>
+    <string name="tutorial_action_key_title" msgid="8172535792469008169">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‎‏‎‏‏‎‏‎‏‎‏‎‏‎‏‏‏‎‎‎‎‎‎‎‎‎‏‏‎‏‏‎‎‎‎‏‎‎‎‏‏‏‏‏‎‏‏‏‏‏‎‎‏‎‏‎‎‏‎View all apps‎‏‎‎‏‎"</string>
+    <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‎‏‏‏‏‏‎‎‏‏‏‏‎‏‏‎‏‏‎‎‏‏‎‏‎‎‏‎‏‎‏‎‏‎‎‏‏‏‏‏‎‎‏‎‏‏‎‏‏‎‏‎‏‏‏‏‏‎‎Press the action key on your keyboard‎‏‎‎‏‎"</string>
+    <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‎‎‎‏‏‏‎‏‎‏‎‎‏‏‎‏‏‎‎‎‏‏‎‎‏‏‏‏‏‎‏‏‎‏‎‏‏‎‎‏‎‎‎‎‏‎‏‎‎‎‎‎‎‏‏‎‎‏‏‎Well done!‎‏‎‎‏‎"</string>
+    <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‏‏‏‎‏‏‏‎‎‎‎‎‏‏‏‏‏‎‎‎‎‎‏‎‎‎‎‎‎‏‏‏‏‏‏‏‎‎‎‏‎‏‏‎‏‏‎‏‎‎‎‏‎‎‎‏‎‎‎‎You completed the view all apps gesture‎‏‎‎‏‎"</string>
     <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‏‎‏‏‎‎‏‏‏‏‏‏‏‏‎‏‏‏‎‏‎‎‏‎‎‎‏‏‎‎‎‎‎‎‏‎‏‏‎‎‏‏‎‎‏‎‏‏‏‎‎‎‏‏‎‏‎‎‎Keyboard backlight‎‏‎‎‏‎"</string>
     <string name="keyboard_backlight_value" msgid="7336398765584393538">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‏‎‏‏‏‎‏‎‎‎‎‎‎‎‏‏‏‏‏‏‏‎‎‏‏‏‎‏‎‏‏‎‎‎‏‎‏‎‎‎‏‎‏‏‎‏‎‎‏‎‏‎‏‎‎‎‎‏‎‎Level %1$d of %2$d‎‏‎‎‏‎"</string>
     <string name="home_controls_dream_label" msgid="6567105701292324257">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‏‏‎‎‏‎‎‎‏‏‎‎‎‎‏‎‏‏‏‏‎‏‎‏‏‏‎‏‎‏‏‏‏‏‏‏‏‏‏‎‎‎‏‎‏‏‎‏‎‏‏‎‏‎‎‎‎‏‎Home Controls‎‏‎‎‏‎"</string>
@@ -1435,6 +1440,7 @@
     <string name="all_apps_edu_toast_content" msgid="8807496014667211562">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‎‏‎‎‎‏‏‏‎‏‎‏‎‎‎‎‎‏‎‏‏‏‏‎‏‏‎‎‎‎‏‎‎‏‎‏‏‏‎‏‎‎‎‎‏‏‎‎‎‏‏‎‎‏‎‏‎‏‎‎To view all your apps, press the action key on your keyboard‎‏‎‎‏‎"</string>
     <string name="redacted_notification_single_line_title" msgid="212019960919261670">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‎‏‎‏‏‏‏‎‎‎‏‎‎‏‏‏‏‏‏‎‎‎‎‎‏‏‏‏‏‏‏‎‏‏‏‏‏‏‎‎‎‏‎‏‎‎‎‎‎‎‏‏‏‏‎‎‏‏‎‎Redacted‎‏‎‎‏‎"</string>
     <string name="redacted_notification_single_line_text" msgid="8684166405005242945">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‎‎‎‏‎‎‎‎‏‎‎‎‏‎‏‏‎‏‏‎‏‎‏‎‏‎‏‏‎‏‎‏‏‎‎‏‎‏‏‎‏‏‏‏‏‏‏‎‎‏‎‎‏‎‎‎‎‎‏‎Unlock to view‎‏‎‎‏‎"</string>
+    <string name="contextual_education_dialog_title" msgid="4630392552837487324">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‎‎‎‎‏‎‎‎‎‏‎‎‏‏‏‎‏‎‏‎‏‏‏‏‏‏‎‎‏‏‏‎‎‏‎‎‏‏‏‏‏‏‎‎‎‎‏‏‎‏‎‏‏‎‏‏‏‎‎‎Contextual education‎‏‎‎‏‎"</string>
     <string name="back_edu_notification_title" msgid="5624780717751357278">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‏‏‎‎‎‎‎‏‏‏‏‎‎‏‏‏‏‎‎‎‏‎‎‎‎‏‎‏‏‏‎‏‏‎‏‎‎‎‎‏‎‎‏‎‏‎‎‏‏‏‏‎‏‎‏‏‏‏‎‎Use your touchpad to go back‎‏‎‎‏‎"</string>
     <string name="back_edu_notification_content" msgid="2497557451540954068">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‎‏‎‏‎‏‎‏‎‎‏‎‎‎‏‏‎‏‏‎‏‎‎‎‏‎‏‎‎‎‎‎‎‎‏‎‎‏‏‏‎‏‎‎‏‏‏‏‎‏‏‏‏‎‏‎‏‎‎‎Swipe left or right using three fingers. Tap to learn more gestures.‎‏‎‎‏‎"</string>
     <string name="home_edu_notification_title" msgid="6097902076909654045">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‎‎‏‎‏‎‎‎‎‎‎‎‎‏‏‎‎‏‏‎‏‎‎‎‎‏‏‎‎‎‎‎‎‏‎‏‎‏‎‎‎‏‎‎‎‏‎‎‎‎‎‎‎‏‏‏‎‏‎Use your touchpad to go home‎‏‎‎‏‎"</string>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index 88cedcf..0620cc3 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -440,7 +440,8 @@
     <string name="zen_mode_on" msgid="9085304934016242591">"Activado"</string>
     <string name="zen_mode_on_with_details" msgid="7416143430557895497">"Sí • <xliff:g id="TRIGGER_DESCRIPTION">%1$s</xliff:g>"</string>
     <string name="zen_mode_off" msgid="1736604456618147306">"Desactivado"</string>
-    <string name="zen_mode_set_up" msgid="7457957033034460064">"Configurar"</string>
+    <!-- no translation found for zen_mode_set_up (8231201163894922821) -->
+    <skip />
     <string name="zen_mode_no_manual_invocation" msgid="1769975741344633672">"Administrar en configuración"</string>
     <string name="zen_mode_active_modes" msgid="1625850411578488856">"{count,plural, =0{No hay modos activos}=1{{mode} está activo}many{# de modos están activos}other{# modos están activos}}"</string>
     <string name="zen_priority_introduction" msgid="3159291973383796646">"No te molestarán los sonidos ni las vibraciones, excepto las alarmas, los recordatorios, los eventos y las llamadas de los emisores que especifiques. Podrás escuchar el contenido que reproduzcas, como música, videos y juegos."</string>
@@ -573,8 +574,7 @@
     <string name="notification_section_header_conversations" msgid="821834744538345661">"Conversaciones"</string>
     <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Borrar todas las notificaciones silenciosas"</string>
     <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Notificaciones pausadas por el modo \"No interrumpir\""</string>
-    <!-- no translation found for modes_suppressing_shade_text (6037581130837903239) -->
-    <skip />
+    <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{No hay notificaciones}=1{{mode} pausó las notificaciones}=2{{mode} y un modo más pausaron las notificaciones}many{{mode} y # de modos más pausaron las notificaciones}other{{mode} y # modos más pausaron las notificaciones}}"</string>
     <string name="media_projection_action_text" msgid="3634906766918186440">"Comenzar ahora"</string>
     <string name="empty_shade_text" msgid="8935967157319717412">"No hay notificaciones"</string>
     <string name="no_unseen_notif_text" msgid="395512586119868682">"No hay notificaciones nuevas"</string>
@@ -673,6 +673,10 @@
     <string name="stream_notification_unavailable" msgid="4313854556205836435">"No disponible por timbre silenciado"</string>
     <string name="stream_alarm_unavailable" msgid="4059817189292197839">"No disponible si está activado No interrumpir"</string>
     <string name="stream_media_unavailable" msgid="6823020894438959853">"No disponible si está activado No interrumpir"</string>
+    <!-- no translation found for stream_unavailable_by_modes (3674139029490353683) -->
+    <skip />
+    <!-- no translation found for stream_unavailable_by_unknown (6908434629318171588) -->
+    <skip />
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Presiona para dejar de silenciar."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Presiona para establecer el modo vibración. Es posible que los servicios de accesibilidad estén silenciados."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Presiona para silenciar. Es posible que los servicios de accesibilidad estén silenciados."</string>
@@ -706,6 +710,7 @@
     <string name="show_demo_mode" msgid="3677956462273059726">"Ver en modo de demostración"</string>
     <string name="status_bar_ethernet" msgid="5690979758988647484">"Ethernet"</string>
     <string name="status_bar_alarm" msgid="87160847643623352">"Alarma"</string>
+    <string name="active_mode_content_description" msgid="1627555562186515927">"<xliff:g id="MODENAME">%1$s</xliff:g> activado"</string>
     <string name="wallet_title" msgid="5369767670735827105">"Billetera"</string>
     <string name="wallet_empty_state_label" msgid="7776761245237530394">"Prepárate para realizar compras rápidas y seguras con tu teléfono"</string>
     <string name="wallet_app_button_label" msgid="7123784239111190992">"Mostrar todo"</string>
@@ -1405,26 +1410,38 @@
     <string name="launch_touchpad_tutorial_notification_content" msgid="7931085031240753226">"Aprende los gestos del panel táctil"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_title" msgid="1940023776496198762">"Navega con el teclado y el panel táctil"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Aprende sobre los gestos del panel táctil, las combinaciones de teclas y mucho más"</string>
-    <string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Gesto atrás"</string>
-    <string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Gesto para ir a la pantalla principal"</string>
+    <!-- no translation found for touchpad_tutorial_back_gesture_button (3104716365403620315) -->
+    <skip />
+    <!-- no translation found for touchpad_tutorial_home_gesture_button (8023973153559885624) -->
+    <skip />
     <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Ver apps recientes"</string>
     <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Listo"</string>
     <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Atrás"</string>
-    <string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"Para volver, desliza tres dedos hacia la derecha o la izquierda en cualquier lugar del panel táctil.\n\nPara completar esta acción, también puedes usar la combinación de teclas Action + ESC."</string>
-    <string name="touchpad_back_gesture_success_title" msgid="7240576648330612171">"¡Bien hecho!"</string>
+    <!-- no translation found for touchpad_back_gesture_guidance (5352221087725906542) -->
+    <skip />
+    <!-- no translation found for touchpad_back_gesture_success_title (7370719098633023496) -->
+    <skip />
     <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"Completaste el gesto para ir atrás."</string>
     <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"Ir a la página principal"</string>
-    <string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"Para ir a la pantalla principal en cualquier momento, desliza hacia arriba desde la parte inferior de la pantalla con tres dedos."</string>
-    <string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"¡Muy bien!"</string>
-    <string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Completaste el gesto para ir al inicio."</string>
+    <!-- no translation found for touchpad_home_gesture_guidance (4178219118381915899) -->
+    <skip />
+    <!-- no translation found for touchpad_home_gesture_success_title (3648264553645798470) -->
+    <skip />
+    <!-- no translation found for touchpad_home_gesture_success_body (2590690589194027059) -->
+    <skip />
     <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"Ver apps recientes"</string>
-    <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"Desliza hacia arriba con tres dedos en el panel táctil y mantenlos presionados."</string>
+    <!-- no translation found for touchpad_recent_apps_gesture_guidance (6304446013842271822) -->
+    <skip />
     <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"¡Bien hecho!"</string>
     <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Completaste el gesto para ver las apps recientes."</string>
-    <string name="tutorial_action_key_title" msgid="2659466586996495447">"Tecla de acción"</string>
-    <string name="tutorial_action_key_guidance" msgid="5718948664616999196">"Para acceder a las apps, presiona la tecla de acción en el teclado."</string>
-    <string name="tutorial_action_key_success_title" msgid="466467860120112933">"¡Felicitaciones!"</string>
-    <string name="tutorial_action_key_success_body" msgid="7201991081652850430">"Completaste el gesto de la tecla de acción.\n\nSi presionas las teclas Acción + /, se muestran todas las combinaciones de teclas disponibles."</string>
+    <!-- no translation found for tutorial_action_key_title (8172535792469008169) -->
+    <skip />
+    <!-- no translation found for tutorial_action_key_guidance (5040613427202799294) -->
+    <skip />
+    <!-- no translation found for tutorial_action_key_success_title (2371827347071979571) -->
+    <skip />
+    <!-- no translation found for tutorial_action_key_success_body (1688986269491357832) -->
+    <skip />
     <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Retroiluminación del teclado"</string>
     <string name="keyboard_backlight_value" msgid="7336398765584393538">"Nivel %1$d de %2$d"</string>
     <string name="home_controls_dream_label" msgid="6567105701292324257">"Controles de la casa"</string>
@@ -1436,6 +1453,7 @@
     <string name="all_apps_edu_toast_content" msgid="8807496014667211562">"Para ver todas las apps, presiona la tecla de acción en el teclado"</string>
     <string name="redacted_notification_single_line_title" msgid="212019960919261670">"Oculto"</string>
     <string name="redacted_notification_single_line_text" msgid="8684166405005242945">"Desbloquea el dispositivo para ver"</string>
+    <string name="contextual_education_dialog_title" msgid="4630392552837487324">"Educación contextual"</string>
     <string name="back_edu_notification_title" msgid="5624780717751357278">"Usa el panel táctil para ir hacia atrás"</string>
     <string name="back_edu_notification_content" msgid="2497557451540954068">"Desliza hacia la izquierda o la derecha con tres dedos. Presiona para aprender más gestos."</string>
     <string name="home_edu_notification_title" msgid="6097902076909654045">"Usa el panel táctil para ir a la pantalla principal"</string>
@@ -1445,7 +1463,7 @@
     <string name="all_apps_edu_notification_title" msgid="372262997265569063">"Usa el teclado para ver todas las apps"</string>
     <string name="all_apps_edu_notification_content" msgid="3255070575694025585">"Presiona la tecla de acción en cualquier momento. Presiona para aprender más gestos."</string>
     <string name="accessibility_deprecate_extra_dim_dialog_title" msgid="910988771011857460">"La atenuación extra ahora es parte del control deslizante de brillo"</string>
-    <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="4453123359258743230">"Ahora puedes bajar el nivel del brillo de la pantalla para atenuarla aún más.\n\nComo esta función ahora es parte del control deslizante de brillo, se quitaron los accesos directos de atenuación extra."</string>
+    <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="4453123359258743230">"Ahora puedes bajar el nivel del brillo de la pantalla para atenuarla aún más.\n\nComo esta función ahora es parte del control deslizante de brillo, se quitaron los accesos directos a la atenuación extra."</string>
     <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="3947537827396916005">"Quitar accesos directos a la atenuación extra"</string>
     <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="165474092660941104">"Se quitaron los accesos directos a la atenuación extra"</string>
     <string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"Conectividad"</string>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index 63f4ae1..c10fc7a 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -440,7 +440,8 @@
     <string name="zen_mode_on" msgid="9085304934016242591">"Activado"</string>
     <string name="zen_mode_on_with_details" msgid="7416143430557895497">"Activado • <xliff:g id="TRIGGER_DESCRIPTION">%1$s</xliff:g>"</string>
     <string name="zen_mode_off" msgid="1736604456618147306">"Desactivado"</string>
-    <string name="zen_mode_set_up" msgid="7457957033034460064">"Configurar"</string>
+    <!-- no translation found for zen_mode_set_up (8231201163894922821) -->
+    <skip />
     <string name="zen_mode_no_manual_invocation" msgid="1769975741344633672">"Gestionar en los ajustes"</string>
     <string name="zen_mode_active_modes" msgid="1625850411578488856">"{count,plural, =0{No hay modos activos}=1{{mode} está activo}many{Hay # modos activos}other{Hay # modos activos}}"</string>
     <string name="zen_priority_introduction" msgid="3159291973383796646">"No te molestarán los sonidos ni las vibraciones, excepto las alarmas, los recordatorios, los eventos y las llamadas que especifiques. Seguirás escuchando el contenido que quieras reproducir, como música, vídeos y juegos."</string>
@@ -573,8 +574,7 @@
     <string name="notification_section_header_conversations" msgid="821834744538345661">"Conversaciones"</string>
     <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Borrar todas las notificaciones silenciosas"</string>
     <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Notificaciones pausadas por el modo No molestar"</string>
-    <!-- no translation found for modes_suppressing_shade_text (6037581130837903239) -->
-    <skip />
+    <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{No hay notificaciones}=1{Notificaciones pausadas por {mode}}=2{Notificaciones pausadas por {mode} y un modo más}many{Notificaciones pausadas por {mode} y # modos más}other{Notificaciones pausadas por {mode} y # modos más}}"</string>
     <string name="media_projection_action_text" msgid="3634906766918186440">"Empezar ahora"</string>
     <string name="empty_shade_text" msgid="8935967157319717412">"No hay notificaciones"</string>
     <string name="no_unseen_notif_text" msgid="395512586119868682">"No hay notificaciones nuevas"</string>
@@ -673,6 +673,10 @@
     <string name="stream_notification_unavailable" msgid="4313854556205836435">"No disponible (el tono está silenciado)"</string>
     <string name="stream_alarm_unavailable" msgid="4059817189292197839">"No disponible porque No molestar está activado"</string>
     <string name="stream_media_unavailable" msgid="6823020894438959853">"No disponible porque No molestar está activado"</string>
+    <!-- no translation found for stream_unavailable_by_modes (3674139029490353683) -->
+    <skip />
+    <!-- no translation found for stream_unavailable_by_unknown (6908434629318171588) -->
+    <skip />
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Toca para activar el sonido."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Toca para poner el dispositivo en vibración. Los servicios de accesibilidad pueden silenciarse."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Toca para silenciar. Los servicios de accesibilidad pueden silenciarse."</string>
@@ -706,6 +710,7 @@
     <string name="show_demo_mode" msgid="3677956462273059726">"Mostrar modo Demo"</string>
     <string name="status_bar_ethernet" msgid="5690979758988647484">"Ethernet"</string>
     <string name="status_bar_alarm" msgid="87160847643623352">"Alarma"</string>
+    <string name="active_mode_content_description" msgid="1627555562186515927">"<xliff:g id="MODENAME">%1$s</xliff:g> activado"</string>
     <string name="wallet_title" msgid="5369767670735827105">"Wallet"</string>
     <string name="wallet_empty_state_label" msgid="7776761245237530394">"Configura un método de pago para comprar de forma más rápida y segura con tu teléfono"</string>
     <string name="wallet_app_button_label" msgid="7123784239111190992">"Mostrar todo"</string>
@@ -1405,26 +1410,38 @@
     <string name="launch_touchpad_tutorial_notification_content" msgid="7931085031240753226">"Aprende gestos del panel táctil"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_title" msgid="1940023776496198762">"Desplázate con el teclado y el panel táctil"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Aprende gestos del panel táctil, combinaciones de teclas y más"</string>
-    <string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Gesto para volver"</string>
-    <string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Gesto para ir al inicio"</string>
+    <!-- no translation found for touchpad_tutorial_back_gesture_button (3104716365403620315) -->
+    <skip />
+    <!-- no translation found for touchpad_tutorial_home_gesture_button (8023973153559885624) -->
+    <skip />
     <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Ver aplicaciones recientes"</string>
     <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Hecho"</string>
     <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Atrás"</string>
-    <string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"Para volver, desliza con tres dedos hacia la izquierda o la derecha en cualquier parte del panel táctil.\n\nTambién puedes hacerlo con la combinación de teclas asignada + Esc."</string>
-    <string name="touchpad_back_gesture_success_title" msgid="7240576648330612171">"¡Bien hecho!"</string>
+    <!-- no translation found for touchpad_back_gesture_guidance (5352221087725906542) -->
+    <skip />
+    <!-- no translation found for touchpad_back_gesture_success_title (7370719098633023496) -->
+    <skip />
     <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"Has completado el gesto para volver."</string>
     <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"Ir a Inicio"</string>
-    <string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"Para ir a la pantalla de inicio en cualquier momento, desliza hacia arriba con tres dedos desde la parte inferior de la pantalla."</string>
-    <string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"¡Muy bien!"</string>
-    <string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Has completado el gesto para ir a la pantalla de inicio."</string>
+    <!-- no translation found for touchpad_home_gesture_guidance (4178219118381915899) -->
+    <skip />
+    <!-- no translation found for touchpad_home_gesture_success_title (3648264553645798470) -->
+    <skip />
+    <!-- no translation found for touchpad_home_gesture_success_body (2590690589194027059) -->
+    <skip />
     <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"Ver aplicaciones recientes"</string>
-    <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"Desliza tres dedos hacia arriba y mantén pulsado en el panel táctil."</string>
+    <!-- no translation found for touchpad_recent_apps_gesture_guidance (6304446013842271822) -->
+    <skip />
     <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"¡Bien hecho!"</string>
     <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Has completado el gesto para ver las aplicaciones recientes."</string>
-    <string name="tutorial_action_key_title" msgid="2659466586996495447">"Tecla de acción"</string>
-    <string name="tutorial_action_key_guidance" msgid="5718948664616999196">"Para acceder a tus aplicaciones, pulsa la tecla de acción de tu teclado."</string>
-    <string name="tutorial_action_key_success_title" msgid="466467860120112933">"¡Enhorabuena!"</string>
-    <string name="tutorial_action_key_success_body" msgid="7201991081652850430">"Has completado el gesto de la tecla de acción.\n\nLa combinación de teclas Acción + / muestra todas las combinaciones de teclas que tienes disponibles."</string>
+    <!-- no translation found for tutorial_action_key_title (8172535792469008169) -->
+    <skip />
+    <!-- no translation found for tutorial_action_key_guidance (5040613427202799294) -->
+    <skip />
+    <!-- no translation found for tutorial_action_key_success_title (2371827347071979571) -->
+    <skip />
+    <!-- no translation found for tutorial_action_key_success_body (1688986269491357832) -->
+    <skip />
     <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Retroiluminación del teclado"</string>
     <string name="keyboard_backlight_value" msgid="7336398765584393538">"Nivel %1$d de %2$d"</string>
     <string name="home_controls_dream_label" msgid="6567105701292324257">"Controles de la casa"</string>
@@ -1436,6 +1453,7 @@
     <string name="all_apps_edu_toast_content" msgid="8807496014667211562">"Para ver todas tus aplicaciones, pulsa la tecla de acción de tu teclado"</string>
     <string name="redacted_notification_single_line_title" msgid="212019960919261670">"Oculta"</string>
     <string name="redacted_notification_single_line_text" msgid="8684166405005242945">"Desbloquea para ver"</string>
+    <string name="contextual_education_dialog_title" msgid="4630392552837487324">"Educación contextual"</string>
     <string name="back_edu_notification_title" msgid="5624780717751357278">"Usa el panel táctil para volver atrás"</string>
     <string name="back_edu_notification_content" msgid="2497557451540954068">"Desliza hacia la izquierda o hacia la derecha con tres dedos. Toca para aprender a usar más gestos."</string>
     <string name="home_edu_notification_title" msgid="6097902076909654045">"Usa el panel táctil para ir a la pantalla de inicio"</string>
@@ -1445,7 +1463,7 @@
     <string name="all_apps_edu_notification_title" msgid="372262997265569063">"Usa el teclado para ver todas las aplicaciones"</string>
     <string name="all_apps_edu_notification_content" msgid="3255070575694025585">"Pulsa la tecla de acción en cualquier momento. Toca para aprender a usar más gestos."</string>
     <string name="accessibility_deprecate_extra_dim_dialog_title" msgid="910988771011857460">"La atenuación extra ahora forma parte del control deslizante de brillo"</string>
-    <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="4453123359258743230">"Ahora puedes atenuar aún más tu pantalla reduciendo el nivel de brillo incluso más todavía.\n\nComo esta función ahora forma parte del control deslizante de brillo, se van a quitar los accesos directos de atenuación extra."</string>
+    <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="4453123359258743230">"Ahora puedes atenuar aún más tu pantalla reduciendo el nivel de brillo.\n\nComo esta función ahora forma parte del control deslizante de brillo, se van a quitar los accesos directos de atenuación extra."</string>
     <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="3947537827396916005">"Eliminar accesos directos de atenuación extra"</string>
     <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="165474092660941104">"Accesos directos de atenuación extra eliminados"</string>
     <string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"Conectividad"</string>
diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml
index 35d4012..4b97b7be 100644
--- a/packages/SystemUI/res/values-et/strings.xml
+++ b/packages/SystemUI/res/values-et/strings.xml
@@ -440,7 +440,7 @@
     <string name="zen_mode_on" msgid="9085304934016242591">"Sees"</string>
     <string name="zen_mode_on_with_details" msgid="7416143430557895497">"Sees • <xliff:g id="TRIGGER_DESCRIPTION">%1$s</xliff:g>"</string>
     <string name="zen_mode_off" msgid="1736604456618147306">"Väljas"</string>
-    <string name="zen_mode_set_up" msgid="7457957033034460064">"Seadistamine"</string>
+    <string name="zen_mode_set_up" msgid="8231201163894922821">"Määramata"</string>
     <string name="zen_mode_no_manual_invocation" msgid="1769975741344633672">"Seadetes halamine"</string>
     <string name="zen_mode_active_modes" msgid="1625850411578488856">"{count,plural, =0{Aktiivsed režiimid puuduvad}=1{{mode} on aktiivne}other{# režiimi on aktiivsed}}"</string>
     <string name="zen_priority_introduction" msgid="3159291973383796646">"Helid ja värinad ei sega teid. Kuulete siiski enda määratud äratusi, meeldetuletusi, sündmusi ja helistajaid. Samuti kuulete kõike, mille esitamise ise valite, sh muusika, videod ja mängud."</string>
@@ -573,8 +573,7 @@
     <string name="notification_section_header_conversations" msgid="821834744538345661">"Vestlused"</string>
     <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Kustuta kõik hääletud märguanded"</string>
     <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Režiim Mitte segada peatas märguanded"</string>
-    <!-- no translation found for modes_suppressing_shade_text (6037581130837903239) -->
-    <skip />
+    <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{Märguandeid pole}=1{{mode} peatas märguanded}=2{{mode} ja veel üks režiim peatasid märguanded}other{{mode} ja veel # režiimi peatasid märguanded}}"</string>
     <string name="media_projection_action_text" msgid="3634906766918186440">"Alusta kohe"</string>
     <string name="empty_shade_text" msgid="8935967157319717412">"Märguandeid pole"</string>
     <string name="no_unseen_notif_text" msgid="395512586119868682">"Uusi märguandeid ei ole"</string>
@@ -673,6 +672,10 @@
     <string name="stream_notification_unavailable" msgid="4313854556205836435">"Pole saadaval, kuna helin on vaigistatud"</string>
     <string name="stream_alarm_unavailable" msgid="4059817189292197839">"Pole saadaval, kuna režiim Mitte segada on sees"</string>
     <string name="stream_media_unavailable" msgid="6823020894438959853">"Pole saadaval, kuna režiim Mitte segada on sees"</string>
+    <!-- no translation found for stream_unavailable_by_modes (3674139029490353683) -->
+    <skip />
+    <!-- no translation found for stream_unavailable_by_unknown (6908434629318171588) -->
+    <skip />
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Puudutage vaigistuse tühistamiseks."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Puudutage värinarežiimi määramiseks. Juurdepääsetavuse teenused võidakse vaigistada."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Puudutage vaigistamiseks. Juurdepääsetavuse teenused võidakse vaigistada."</string>
@@ -706,6 +709,7 @@
     <string name="show_demo_mode" msgid="3677956462273059726">"Kuva demorežiim"</string>
     <string name="status_bar_ethernet" msgid="5690979758988647484">"Ethernet"</string>
     <string name="status_bar_alarm" msgid="87160847643623352">"Äratus"</string>
+    <string name="active_mode_content_description" msgid="1627555562186515927">"<xliff:g id="MODENAME">%1$s</xliff:g> on sisse lülitatud"</string>
     <string name="wallet_title" msgid="5369767670735827105">"Wallet"</string>
     <string name="wallet_empty_state_label" msgid="7776761245237530394">"Seadistage kiirem ja turvalisem viis telefoniga ostmiseks"</string>
     <string name="wallet_app_button_label" msgid="7123784239111190992">"Kuva kõik"</string>
@@ -1405,26 +1409,26 @@
     <string name="launch_touchpad_tutorial_notification_content" msgid="7931085031240753226">"Õppige puuteplaadi liigutusi"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_title" msgid="1940023776496198762">"Navigeerige klaviatuuri ja puuteplaadi abil"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Õppige puuteplaadi liigutusi, klaviatuuri otseteid ja palju muud"</string>
-    <string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Tagasiliikumisliigutus"</string>
-    <string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Avakuvale liikumise liigutus"</string>
+    <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"Mine tagasi"</string>
+    <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Avalehele"</string>
     <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Hiljutiste rakenduste vaatamine"</string>
     <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Valmis"</string>
     <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Tagasi"</string>
-    <string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"Tagasiliikumiseks pühkige puuteplaadil kolme sõrmega vasakule või paremale.\n\nSamuti saate selle jaoks kasutada klaviatuuri otseteed toiminguklahv + paoklahv."</string>
-    <string name="touchpad_back_gesture_success_title" msgid="7240576648330612171">"Väga hea!"</string>
+    <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"Pühkige puuteplaadil kolme sõrmega vasakule või paremale"</string>
+    <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"Tubli töö!"</string>
     <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"Tegite tagasiliikumise liigutuse."</string>
     <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"Avalehele"</string>
-    <string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"Mis tahes ajal avakuvale liikumiseks pühkige kolme sõrmega ekraanikuva allosast üles."</string>
-    <string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Hästi tehtud!"</string>
-    <string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Tegite avakuvale minemise liigutuse."</string>
+    <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"Pühkige puuteplaadil kolme sõrmega üles"</string>
+    <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"Väga hea!"</string>
+    <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"Tegite avakuvale minemise liigutuse"</string>
     <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"Hiljutiste rakenduste vaatamine"</string>
-    <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"Pühkige üles ja hoidke kolme sõrmega puuteplaadil."</string>
+    <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"Pühkige üles ja hoidke kolme sõrme puuteplaadil"</string>
     <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Väga hea!"</string>
     <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Lõpetasite hiljutiste rakenduste vaatamise liigutuse."</string>
-    <string name="tutorial_action_key_title" msgid="2659466586996495447">"Toiminguklahv"</string>
-    <string name="tutorial_action_key_guidance" msgid="5718948664616999196">"Rakendustele juurdepääsemiseks vajutage klaviatuuril toiminguklahvi."</string>
-    <string name="tutorial_action_key_success_title" msgid="466467860120112933">"Õnnitleme!"</string>
-    <string name="tutorial_action_key_success_body" msgid="7201991081652850430">"Tegite toiminguklahvi liigutuse.\n\nKombinatsiooni toiminguklahv + / vajutamisel kuvatakse kõik saadaolevad otseteed."</string>
+    <string name="tutorial_action_key_title" msgid="8172535792469008169">"Kõigi rakenduste kuvamine"</string>
+    <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Vajutage klaviatuuril toiminguklahvi"</string>
+    <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Hästi tehtud!"</string>
+    <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Tegite kõigi rakenduste vaatamise liigutuse"</string>
     <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Klaviatuuri taustavalgustus"</string>
     <string name="keyboard_backlight_value" msgid="7336398765584393538">"Tase %1$d/%2$d"</string>
     <string name="home_controls_dream_label" msgid="6567105701292324257">"Kodu juhtelemendid"</string>
@@ -1436,6 +1440,7 @@
     <string name="all_apps_edu_toast_content" msgid="8807496014667211562">"Kõigi oma rakenduste kuvamiseks vajutage klaviatuuril toiminguklahvi"</string>
     <string name="redacted_notification_single_line_title" msgid="212019960919261670">"Peidetud"</string>
     <string name="redacted_notification_single_line_text" msgid="8684166405005242945">"Vaatamiseks avage"</string>
+    <string name="contextual_education_dialog_title" msgid="4630392552837487324">"Kontekstipõhised õpetused"</string>
     <string name="back_edu_notification_title" msgid="5624780717751357278">"Puuteplaadi kasutamine tagasiliikumiseks"</string>
     <string name="back_edu_notification_content" msgid="2497557451540954068">"Pühkige kolme sõrmega vasakule või paremale. Puudutage žestide kohta lisateabe saamiseks."</string>
     <string name="home_edu_notification_title" msgid="6097902076909654045">"Puuteplaadi kasutamine avakuvale liikumiseks"</string>
diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml
index 7e0f203..eff98ce 100644
--- a/packages/SystemUI/res/values-eu/strings.xml
+++ b/packages/SystemUI/res/values-eu/strings.xml
@@ -440,7 +440,7 @@
     <string name="zen_mode_on" msgid="9085304934016242591">"Aktibatuta"</string>
     <string name="zen_mode_on_with_details" msgid="7416143430557895497">"Aktibo • <xliff:g id="TRIGGER_DESCRIPTION">%1$s</xliff:g>"</string>
     <string name="zen_mode_off" msgid="1736604456618147306">"Desaktibatuta"</string>
-    <string name="zen_mode_set_up" msgid="7457957033034460064">"Konfiguratu"</string>
+    <string name="zen_mode_set_up" msgid="8231201163894922821">"Ezarri gabe"</string>
     <string name="zen_mode_no_manual_invocation" msgid="1769975741344633672">"Kudeatu ezarpenetan"</string>
     <string name="zen_mode_active_modes" msgid="1625850411578488856">"{count,plural, =0{Ez dago modurik aktibo}=1{\"{mode}\" aktibo dago}other{# modu aktibo daude}}"</string>
     <string name="zen_priority_introduction" msgid="3159291973383796646">"Gailuak ez du egingo ez soinurik ez dardararik, baina alarmak, gertaera eta abisuen tonuak, eta aukeratzen dituzun deitzaileen dei-tonuak joko ditu. Bestalde, zuk erreproduzitutako guztia entzungo duzu, besteak beste, musika, bideoak eta jokoak."</string>
@@ -573,8 +573,7 @@
     <string name="notification_section_header_conversations" msgid="821834744538345661">"Elkarrizketak"</string>
     <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Garbitu soinurik gabeko jakinarazpen guztiak"</string>
     <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Ez molestatzeko moduak pausatu egin ditu jakinarazpenak"</string>
-    <!-- no translation found for modes_suppressing_shade_text (6037581130837903239) -->
-    <skip />
+    <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{Ez dago jakinarazpenik}=1{Modu honek jakinarazpenak pausatu ditu: {mode}}=2{Modu honek eta beste modu batek jakinarazpenak pausatu dituzte: {mode}}other{Modu honek eta beste # moduk jakinarazpenak pausatu dituzte: {mode}}}"</string>
     <string name="media_projection_action_text" msgid="3634906766918186440">"Hasi"</string>
     <string name="empty_shade_text" msgid="8935967157319717412">"Ez dago jakinarazpenik"</string>
     <string name="no_unseen_notif_text" msgid="395512586119868682">"Ez dago jakinarazpen berririk"</string>
@@ -673,6 +672,10 @@
     <string name="stream_notification_unavailable" msgid="4313854556205836435">"Ez dago erabilgarri, tonua desaktibatuta dagoelako"</string>
     <string name="stream_alarm_unavailable" msgid="4059817189292197839">"Ez dago erabilgarri, ez molestatzeko modua aktibatuta baitago"</string>
     <string name="stream_media_unavailable" msgid="6823020894438959853">"Ez dago erabilgarri, ez molestatzeko modua aktibatuta baitago"</string>
+    <!-- no translation found for stream_unavailable_by_modes (3674139029490353683) -->
+    <skip />
+    <!-- no translation found for stream_unavailable_by_unknown (6908434629318171588) -->
+    <skip />
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Sakatu audioa aktibatzeko."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Sakatu dardara ezartzeko. Baliteke erabilerraztasun-eginbideen audioa desaktibatzea."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Sakatu audioa desaktibatzeko. Baliteke erabilerraztasun-eginbideen audioa desaktibatzea."</string>
@@ -706,6 +709,7 @@
     <string name="show_demo_mode" msgid="3677956462273059726">"Erakutsi demo modua"</string>
     <string name="status_bar_ethernet" msgid="5690979758988647484">"Ethernet"</string>
     <string name="status_bar_alarm" msgid="87160847643623352">"Alarma"</string>
+    <string name="active_mode_content_description" msgid="1627555562186515927">"<xliff:g id="MODENAME">%1$s</xliff:g> aktibatuta dago"</string>
     <string name="wallet_title" msgid="5369767670735827105">"Diru-zorroa"</string>
     <string name="wallet_empty_state_label" msgid="7776761245237530394">"Konfiguratu erosketa bizkorrago eta seguruagoak egiteko telefonoarekin"</string>
     <string name="wallet_app_button_label" msgid="7123784239111190992">"Erakutsi guztiak"</string>
@@ -1405,26 +1409,26 @@
     <string name="launch_touchpad_tutorial_notification_content" msgid="7931085031240753226">"Ikasi ukipen-paneleko keinuak"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_title" msgid="1940023776496198762">"Nabigatu teklatua eta ukipen-panela erabilita"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Ikasi ukipen-paneleko keinuak, lasterbideak eta abar"</string>
-    <string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Atzera egiteko keinua"</string>
-    <string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Orri nagusira joateko keinua"</string>
+    <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"Egin atzera"</string>
+    <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Joan orri nagusira"</string>
     <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Ikusi azkenaldiko aplikazioak"</string>
     <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Eginda"</string>
     <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Egin atzera"</string>
-    <string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"Atzera egiteko, pasatu 3 hatz ezkerrera edo eskuinera ukipen-panelean.\n\nEkintza + Ihes lasterbidea ere erabil dezakezu horretarako."</string>
-    <string name="touchpad_back_gesture_success_title" msgid="7240576648330612171">"Bikain!"</string>
+    <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"Pasatu 3 hatz ezkerrera edo eskuinera ukipen-panelean"</string>
+    <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"Ederki!"</string>
     <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"Ikasi duzu atzera egiteko keinua."</string>
     <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"Joan orri nagusira"</string>
-    <string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"Orri nagusira joateko, pasatu 3 hatz pantailaren behealdetik gora."</string>
-    <string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Ederki!"</string>
-    <string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Ikasi duzu hasierako pantailara joateko keinua."</string>
+    <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"Pasatu 3 hatz gora ukipen-panelean"</string>
+    <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"Bikain!"</string>
+    <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"Ikasi duzu orri nagusira joateko keinua"</string>
     <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"Ikusi azkenaldiko aplikazioak"</string>
-    <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"Pasatu 3 hatz gora eta eduki sakatuta ukipen-panelean."</string>
+    <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"Pasatu 3 hatz gora eta eduki sakatuta ukipen-panelean"</string>
     <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Bikain!"</string>
     <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Osatu duzu azkenaldiko aplikazioak ikusteko keinua."</string>
-    <string name="tutorial_action_key_title" msgid="2659466586996495447">"Ekintza-tekla"</string>
-    <string name="tutorial_action_key_guidance" msgid="5718948664616999196">"Aplikazioak atzitzeko, sakatu teklatuko ekintza-tekla."</string>
-    <string name="tutorial_action_key_success_title" msgid="466467860120112933">"Zorionak!"</string>
-    <string name="tutorial_action_key_success_body" msgid="7201991081652850430">"Ekintza-teklaren keinua egin duzu.\n\nEkintza + / sakatuz gero, erabilgarri dituzun lasterbide guztiak ikusiko dituzu."</string>
+    <string name="tutorial_action_key_title" msgid="8172535792469008169">"Ikusi aplikazio guztiak"</string>
+    <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Sakatu teklatuko ekintza-tekla"</string>
+    <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Bikain!"</string>
+    <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Osatu duzu aplikazio guztiak ikusteko keinua"</string>
     <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Teklatuaren hondoko argia"</string>
     <string name="keyboard_backlight_value" msgid="7336398765584393538">"%1$d/%2$d maila"</string>
     <string name="home_controls_dream_label" msgid="6567105701292324257">"Etxeko gailuen kontrola"</string>
@@ -1436,6 +1440,7 @@
     <string name="all_apps_edu_toast_content" msgid="8807496014667211562">"Aplikazio guztiak ikusteko, sakatu teklatuko ekintza-tekla"</string>
     <string name="redacted_notification_single_line_title" msgid="212019960919261670">"Desitxuratuta"</string>
     <string name="redacted_notification_single_line_text" msgid="8684166405005242945">"Desblokeatu ikusteko"</string>
+    <string name="contextual_education_dialog_title" msgid="4630392552837487324">"Testuinguruaren araberako hezkuntza"</string>
     <string name="back_edu_notification_title" msgid="5624780717751357278">"Erabili ukipen-panela atzera egiteko"</string>
     <string name="back_edu_notification_content" msgid="2497557451540954068">"Pasatu 3 hatz ezkerrera edo eskuinera. Sakatu keinu gehiago ikasteko."</string>
     <string name="home_edu_notification_title" msgid="6097902076909654045">"Erabili ukipen-panela hasierako pantailara joateko"</string>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index e70d2bb..858670a 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -440,7 +440,7 @@
     <string name="zen_mode_on" msgid="9085304934016242591">"روشن"</string>
     <string name="zen_mode_on_with_details" msgid="7416143430557895497">"روشن • <xliff:g id="TRIGGER_DESCRIPTION">%1$s</xliff:g>"</string>
     <string name="zen_mode_off" msgid="1736604456618147306">"خاموش"</string>
-    <string name="zen_mode_set_up" msgid="7457957033034460064">"راه‌اندازی"</string>
+    <string name="zen_mode_set_up" msgid="8231201163894922821">"تنظیم نشده است"</string>
     <string name="zen_mode_no_manual_invocation" msgid="1769975741344633672">"مدیریت در تنظیمات"</string>
     <string name="zen_mode_active_modes" msgid="1625850411578488856">"{count,plural, =0{حالت فعالی وجود ندارد}=1{‫{mode} فعال است}one{‫# حالت فعال است}other{‫# حالت فعال است}}"</string>
     <string name="zen_priority_introduction" msgid="3159291973383796646">"به‌جز هشدارها، یادآوری‌ها، رویدادها و تماس‌گیرندگانی که خودتان مشخص می‌کنید، هیچ صدا و لرزشی نخواهید داشت. همچنان صدای مواردی را که پخش می‌کنید می‌شنوید (ازجمله صدای موسیقی، ویدیو و بازی)."</string>
@@ -573,8 +573,7 @@
     <string name="notification_section_header_conversations" msgid="821834744538345661">"مکالمه‌ها"</string>
     <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"پاک کردن همه اعلان‌های بی‌صدا"</string>
     <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"اعلان‌ها توسط «مزاحم نشوید» موقتاً متوقف شدند"</string>
-    <!-- no translation found for modes_suppressing_shade_text (6037581130837903239) -->
-    <skip />
+    <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{اعلانی موقتاً متوقف نشده است}=1{اعلان‌ها را «{mode}» موقتاً متوقف کرده است}=2{اعلان‌ها را «{mode}» و یک حالت دیگر موقتاً متوقف کرد‌اند}one{اعلان‌ها را «{mode}» و # حالت دیگر موقتاً متوقف کرده‌اند}other{اعلان‌ها را «{mode}» و # حالت دیگر موقتاً متوقف کرده‌اند}}"</string>
     <string name="media_projection_action_text" msgid="3634906766918186440">"اکنون شروع کنید"</string>
     <string name="empty_shade_text" msgid="8935967157319717412">"اعلانی موجود نیست"</string>
     <string name="no_unseen_notif_text" msgid="395512586119868682">"اعلان جدیدی وجود ندارد"</string>
@@ -673,6 +672,10 @@
     <string name="stream_notification_unavailable" msgid="4313854556205836435">"دردسترس نیست، چون زنگ بی‌صدا شده است"</string>
     <string name="stream_alarm_unavailable" msgid="4059817189292197839">"دردسترس نیست زیرا «مزاحم نشوید» روشن است"</string>
     <string name="stream_media_unavailable" msgid="6823020894438959853">"دردسترس نیست زیرا «مزاحم نشوید» روشن است"</string>
+    <!-- no translation found for stream_unavailable_by_modes (3674139029490353683) -->
+    <skip />
+    <!-- no translation found for stream_unavailable_by_unknown (6908434629318171588) -->
+    <skip />
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"‏%1$s. برای باصدا کردن تک‌ضرب بزنید."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"‏%1$s. برای تنظیم روی لرزش تک‌ضرب بزنید. ممکن است سرویس‌های دسترس‌پذیری بی‌صدا شوند."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"‏%1$s. برای صامت کردن تک‌ضرب بزنید. ممکن است سرویس‌های دسترس‌پذیری صامت شود."</string>
@@ -706,6 +709,7 @@
     <string name="show_demo_mode" msgid="3677956462273059726">"نمایش حالت نمایشی"</string>
     <string name="status_bar_ethernet" msgid="5690979758988647484">"اترنت"</string>
     <string name="status_bar_alarm" msgid="87160847643623352">"زنگ"</string>
+    <string name="active_mode_content_description" msgid="1627555562186515927">"<xliff:g id="MODENAME">%1$s</xliff:g> روشن است"</string>
     <string name="wallet_title" msgid="5369767670735827105">"کیف پول"</string>
     <string name="wallet_empty_state_label" msgid="7776761245237530394">"برای خرید سریع‌تر و امن‌تر با تلفن، راه‌اندازی کنید"</string>
     <string name="wallet_app_button_label" msgid="7123784239111190992">"نمایش همه"</string>
@@ -1178,7 +1182,7 @@
     <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"توقف پخش محتوا"</string>
     <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"دستگاه‌های دردسترس برای خروجی صوتی."</string>
     <string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"میزان صدا"</string>
-    <string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
+    <string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"‎%%<xliff:g id="PERCENTAGE">%1$d</xliff:g>"</string>
     <string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"بلندگوها و نمایشگرها"</string>
     <string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"دستگاه‌های پیشنهادی"</string>
     <string name="media_input_group_title" msgid="2057057473860783021">"ورودی"</string>
@@ -1405,26 +1409,26 @@
     <string name="launch_touchpad_tutorial_notification_content" msgid="7931085031240753226">"آشنایی با اشاره‌های صفحه لمسی"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_title" msgid="1940023776496198762">"پیمایش کردن بااستفاده از صفحه‌کلید و صفحه لمسی"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"آشنایی با اشاره‌های صفحه لمسی، میان‌برهای صفحه‌کلید، و موارد دیگر"</string>
-    <string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"اشاره برگشت"</string>
-    <string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"اشاره صفحه اصلی"</string>
+    <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"برگشتن"</string>
+    <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"رفتن به صفحه اصلی"</string>
     <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"مشاهده کردن برنامه‌های اخیر"</string>
     <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"تمام"</string>
     <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"برگشتن"</string>
-    <string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"برای برگشتن، در هر جایی از صفحه لمسی، با سه انگشت تند به‌چپ یا راست بکشید.\n\nبرای این کار می‌توانید از میان‌بر صفحه‌کلید «کنش + گریز» هم استفاده کنید."</string>
-    <string name="touchpad_back_gesture_success_title" msgid="7240576648330612171">"عالی بود!"</string>
+    <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"با سه انگشت روی صفحه لمسی تند به چپ یا راست بکشید."</string>
+    <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"چه خوب!"</string>
     <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"اشاره برگشت را تکمیل کردید."</string>
     <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"رفتن به صفحه اصلی"</string>
-    <string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"برای رفتن به صفحه اصلی در هرزمانی، با سه انگشت از پایین صفحه‌نمایش تند به‌بالا بکشید."</string>
-    <string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"آفرین!"</string>
-    <string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"اشاره رفتن به صفحه اصلی را تکمیل کردید."</string>
+    <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"با سه انگشت روی صفحه لمسی تند به بالا بکشید"</string>
+    <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"عالی است!"</string>
+    <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"اشاره رفتن به صفحه اصلی را تکمیل کردید"</string>
     <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"مشاهده کردن برنامه‌های اخیر"</string>
-    <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"با سه انگشت روی صفحه لمسی تند به‌بالا بکشید و نگه دارید."</string>
+    <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"با سه انگشت روی صفحه لمسی تند به بالا بکشید و نگه دارید"</string>
     <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"عالی است!"</string>
     <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"اشاره مشاهده برنامه‌های اخیر را انجام دادید"</string>
-    <string name="tutorial_action_key_title" msgid="2659466586996495447">"دکمه کنش"</string>
-    <string name="tutorial_action_key_guidance" msgid="5718948664616999196">"برای دسترسی به برنامه‌هایتان، دکمه کنش در صفحه‌کلید را فشار دهید."</string>
-    <string name="tutorial_action_key_success_title" msgid="466467860120112933">"تبریک!"</string>
-    <string name="tutorial_action_key_success_body" msgid="7201991081652850430">"اشاره دکمه کنش را تکمیل کردید.\n\n«کنش» + / همه میان‌برهای دردسترس را نمایش می‌دهد."</string>
+    <string name="tutorial_action_key_title" msgid="8172535792469008169">"مشاهده همه برنامه‌ها"</string>
+    <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"دکمه کنش را روی صفحه لمسی فشار دهید"</string>
+    <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"عالی بود!"</string>
+    <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"اشاره مشاهده همه برنامه‌ها را انجام دادید"</string>
     <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"نور پس‌زمینه صفحه‌کلید"</string>
     <string name="keyboard_backlight_value" msgid="7336398765584393538">"‏سطح %1$d از %2$d"</string>
     <string name="home_controls_dream_label" msgid="6567105701292324257">"کنترل خانه هوشمند"</string>
@@ -1436,6 +1440,7 @@
     <string name="all_apps_edu_toast_content" msgid="8807496014667211562">"برای مشاهده همه برنامه‌ها، دکمه کنش در صفحه‌کلید را فشار دهید"</string>
     <string name="redacted_notification_single_line_title" msgid="212019960919261670">"محوشده"</string>
     <string name="redacted_notification_single_line_text" msgid="8684166405005242945">"برای مشاهده، قفل را باز کنید"</string>
+    <string name="contextual_education_dialog_title" msgid="4630392552837487324">"آموزش زمینه‌ای"</string>
     <string name="back_edu_notification_title" msgid="5624780717751357278">"برای برگشتن از صفحه لمسی استفاده کنید"</string>
     <string name="back_edu_notification_content" msgid="2497557451540954068">"با سه انگشت تند به‌چپ یا راست بکشید. برای آشنایی با اشاره‌های بیشتر، تک‌ضرب بزنید."</string>
     <string name="home_edu_notification_title" msgid="6097902076909654045">"برای رفتن به صفحه اصلی از صفحه لمسی استفاده کنید"</string>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index f6d43c1..96a701a 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -440,7 +440,7 @@
     <string name="zen_mode_on" msgid="9085304934016242591">"Päällä"</string>
     <string name="zen_mode_on_with_details" msgid="7416143430557895497">"Päällä • <xliff:g id="TRIGGER_DESCRIPTION">%1$s</xliff:g>"</string>
     <string name="zen_mode_off" msgid="1736604456618147306">"Pois päältä"</string>
-    <string name="zen_mode_set_up" msgid="7457957033034460064">"Ota käyttöön"</string>
+    <string name="zen_mode_set_up" msgid="8231201163894922821">"Ei asetettu"</string>
     <string name="zen_mode_no_manual_invocation" msgid="1769975741344633672">"Muuta asetuksista"</string>
     <string name="zen_mode_active_modes" msgid="1625850411578488856">"{count,plural, =0{Ei aktiivisia tiloja}=1{{mode} on aktiivinen}other{# tilaa on aktiivisena}}"</string>
     <string name="zen_priority_introduction" msgid="3159291973383796646">"Äänet ja värinät eivät häiritse sinua, paitsi jos ne ovat hälytyksiä, muistutuksia, tapahtumia tai määrittämiäsi soittajia. Kuulet edelleen kaiken valitsemasi sisällön, kuten musiikin, videot ja pelit."</string>
@@ -573,8 +573,7 @@
     <string name="notification_section_header_conversations" msgid="821834744538345661">"Keskustelut"</string>
     <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Tyhjennä kaikki hiljaiset ilmoitukset"</string>
     <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Älä häiritse ‑tila keskeytti ilmoitukset"</string>
-    <!-- no translation found for modes_suppressing_shade_text (6037581130837903239) -->
-    <skip />
+    <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{Ei ilmoituksia}=1{{mode} keskeytti ilmoitukset}=2{{mode} ja yksi muu tila keskeytti ilmoitukset}other{{mode} ja # muuta tilaa keskeytti ilmoitukset}}"</string>
     <string name="media_projection_action_text" msgid="3634906766918186440">"Aloita nyt"</string>
     <string name="empty_shade_text" msgid="8935967157319717412">"Ei ilmoituksia"</string>
     <string name="no_unseen_notif_text" msgid="395512586119868682">"Ei uusia ilmoituksia"</string>
@@ -673,6 +672,10 @@
     <string name="stream_notification_unavailable" msgid="4313854556205836435">"Ei käytettävissä, soittoääni mykistetty"</string>
     <string name="stream_alarm_unavailable" msgid="4059817189292197839">"Ei saatavilla, koska Älä häiritse on päällä"</string>
     <string name="stream_media_unavailable" msgid="6823020894438959853">"Ei saatavilla, koska Älä häiritse on päällä"</string>
+    <!-- no translation found for stream_unavailable_by_modes (3674139029490353683) -->
+    <skip />
+    <!-- no translation found for stream_unavailable_by_unknown (6908434629318171588) -->
+    <skip />
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Poista mykistys koskettamalla."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Siirry värinätilaan koskettamalla. Myös esteettömyyspalvelut saattavat mykistyä."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Mykistä koskettamalla. Myös esteettömyyspalvelut saattavat mykistyä."</string>
@@ -706,6 +709,7 @@
     <string name="show_demo_mode" msgid="3677956462273059726">"Näytä esittelytila"</string>
     <string name="status_bar_ethernet" msgid="5690979758988647484">"Ethernet"</string>
     <string name="status_bar_alarm" msgid="87160847643623352">"Herätys"</string>
+    <string name="active_mode_content_description" msgid="1627555562186515927">"<xliff:g id="MODENAME">%1$s</xliff:g> on päällä"</string>
     <string name="wallet_title" msgid="5369767670735827105">"Wallet"</string>
     <string name="wallet_empty_state_label" msgid="7776761245237530394">"Lisää maksutapa, niin voit maksaa nopeasti ja turvallisesti puhelimella"</string>
     <string name="wallet_app_button_label" msgid="7123784239111190992">"Näytä kaikki"</string>
@@ -1405,26 +1409,26 @@
     <string name="launch_touchpad_tutorial_notification_content" msgid="7931085031240753226">"Opettele kosketuslevyn eleitä"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_title" msgid="1940023776496198762">"Siirry käyttämällä näppäimistöä ja kosketuslevyä"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Opettele kosketuslevyn eleitä, pikanäppäimiä ja muuta"</string>
-    <string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Takaisin-ele"</string>
-    <string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Etusivu-ele"</string>
+    <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"Takaisin"</string>
+    <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Siirry etusivulle"</string>
     <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Katso viimeisimmät sovellukset"</string>
     <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Valmis"</string>
     <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Takaisin"</string>
-    <string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"Jos haluat siirtyä takaisin, pyyhkäise kosketuslevyllä vasemmalle tai oikealle kolmella sormella.\n\nVoit myös käyttää pikanäppäinyhdistelmää toimintonäppäin + ESC."</string>
-    <string name="touchpad_back_gesture_success_title" msgid="7240576648330612171">"Hienoa!"</string>
+    <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"Pyyhkäise kosketuslevyllä vasemmalle tai oikealle kolmella sormella"</string>
+    <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"Hienoa!"</string>
     <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"Olet oppinut Takaisin-eleen."</string>
     <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"Siirry etusivulle"</string>
-    <string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"Voit siirtyä aloitusnäytölle milloin tahansa pyyhkäisemällä ylös näytön alareunasta kolmella sormella."</string>
-    <string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Hienoa!"</string>
-    <string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Olet oppinut aloitusnäytölle palaamiseleen."</string>
+    <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"Pyyhkäise ylös kolmella sormella kosketuslevyllä"</string>
+    <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"Hienoa!"</string>
+    <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"Olet oppinut aloitusnäytölle palaamiseleen"</string>
     <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"Katso viimeisimmät sovellukset"</string>
-    <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"Pyyhkäise ylös ja pidä kosketuslevyä painettuna kolmella sormella."</string>
+    <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"Pyyhkäise ylös ja pidä kosketuslevyä painettuna kolmella sormella"</string>
     <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Hienoa!"</string>
     <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Olet oppinut Katso viimeisimmät sovellukset ‑eleen."</string>
-    <string name="tutorial_action_key_title" msgid="2659466586996495447">"Toimintonäppäin"</string>
-    <string name="tutorial_action_key_guidance" msgid="5718948664616999196">"Voit käyttää sovelluksia painamalla näppäimistön toimintonäppäintä."</string>
-    <string name="tutorial_action_key_success_title" msgid="466467860120112933">"Onnittelut!"</string>
-    <string name="tutorial_action_key_success_body" msgid="7201991081652850430">"Olet oppinut toimintonäppäineleen.\n\nToiminto + / tuo esiin kaikki käytettävissä olevat pikakomennot."</string>
+    <string name="tutorial_action_key_title" msgid="8172535792469008169">"Näytä kaikki sovellukset"</string>
+    <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Paina näppäimistön toimintonäppäintä"</string>
+    <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Hienoa!"</string>
+    <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Olet oppinut Näytä kaikki sovellukset ‑eleen"</string>
     <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Näppämistön taustavalo"</string>
     <string name="keyboard_backlight_value" msgid="7336398765584393538">"Taso %1$d/%2$d"</string>
     <string name="home_controls_dream_label" msgid="6567105701292324257">"Kodin ohjaus"</string>
@@ -1436,6 +1440,7 @@
     <string name="all_apps_edu_toast_content" msgid="8807496014667211562">"Jos haluat nähdä kaikki sovellukset, paina näppäimistön toimintonäppäintä"</string>
     <string name="redacted_notification_single_line_title" msgid="212019960919261670">"Sensuroitu"</string>
     <string name="redacted_notification_single_line_text" msgid="8684166405005242945">"Avaa lukitus ja katso tiedot"</string>
+    <string name="contextual_education_dialog_title" msgid="4630392552837487324">"Kontekstuaalinen koulutus"</string>
     <string name="back_edu_notification_title" msgid="5624780717751357278">"Takaisin siirtyminen kosketuslevyn avulla"</string>
     <string name="back_edu_notification_content" msgid="2497557451540954068">"Pyyhkäise vasemmalle tai oikealle kolmella sormella. Lue lisää eleistä napauttamalla."</string>
     <string name="home_edu_notification_title" msgid="6097902076909654045">"Aloitusnäytölle siirtyminen kosketuslevyn avulla"</string>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index 1f6de9f..6b71808 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -440,7 +440,8 @@
     <string name="zen_mode_on" msgid="9085304934016242591">"Activé"</string>
     <string name="zen_mode_on_with_details" msgid="7416143430557895497">"Activé • <xliff:g id="TRIGGER_DESCRIPTION">%1$s</xliff:g>"</string>
     <string name="zen_mode_off" msgid="1736604456618147306">"Désactivé"</string>
-    <string name="zen_mode_set_up" msgid="7457957033034460064">"Configurer"</string>
+    <!-- no translation found for zen_mode_set_up (8231201163894922821) -->
+    <skip />
     <string name="zen_mode_no_manual_invocation" msgid="1769975741344633672">"Gérer dans les paramètres"</string>
     <string name="zen_mode_active_modes" msgid="1625850411578488856">"{count,plural, =0{Aucun mode actif}=1{Le mode {mode} est actif}one{# mode est actif}many{# de modes sont actifs}other{# modes sont actifs}}"</string>
     <string name="zen_priority_introduction" msgid="3159291973383796646">"Vous ne serez pas dérangé par les sons et les vibrations, sauf pour les alarmes, les rappels, les événements et les appelants que vous sélectionnez. Vous entendrez tout ce que vous choisissez d\'écouter, y compris la musique, les vidéos et les jeux."</string>
@@ -573,8 +574,7 @@
     <string name="notification_section_header_conversations" msgid="821834744538345661">"Conversations"</string>
     <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Effacer toutes les notifications silencieuses"</string>
     <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Les notifications sont suspendues par le mode Ne pas déranger"</string>
-    <!-- no translation found for modes_suppressing_shade_text (6037581130837903239) -->
-    <skip />
+    <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{Aucune notification}=1{Notifications suspendues par {mode}}=2{Notifications suspendues par {mode} et un autre mode}one{Notifications suspendues par {mode} et # autre mode}many{Notifications suspendues par {mode} et # d\'autres modes}other{Notifications suspendues par {mode} et # autres modes}}"</string>
     <string name="media_projection_action_text" msgid="3634906766918186440">"Commencer"</string>
     <string name="empty_shade_text" msgid="8935967157319717412">"Aucune notification"</string>
     <string name="no_unseen_notif_text" msgid="395512586119868682">"Aucune nouvelle notification"</string>
@@ -673,6 +673,10 @@
     <string name="stream_notification_unavailable" msgid="4313854556205836435">"Inaccessible : sonnerie en sourdine"</string>
     <string name="stream_alarm_unavailable" msgid="4059817189292197839">"Inaccessible parce que Ne pas déranger est activée"</string>
     <string name="stream_media_unavailable" msgid="6823020894438959853">"Inaccessible parce que Ne pas déranger est activée"</string>
+    <!-- no translation found for stream_unavailable_by_modes (3674139029490353683) -->
+    <skip />
+    <!-- no translation found for stream_unavailable_by_unknown (6908434629318171588) -->
+    <skip />
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Touchez pour réactiver le son."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Touchez pour activer les vibrations. Il est possible de couper le son des services d\'accessibilité."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Touchez pour couper le son. Il est possible de couper le son des services d\'accessibilité."</string>
@@ -706,6 +710,7 @@
     <string name="show_demo_mode" msgid="3677956462273059726">"Afficher le mode Démo"</string>
     <string name="status_bar_ethernet" msgid="5690979758988647484">"Ethernet"</string>
     <string name="status_bar_alarm" msgid="87160847643623352">"Alarme"</string>
+    <string name="active_mode_content_description" msgid="1627555562186515927">"Le mode <xliff:g id="MODENAME">%1$s</xliff:g> est activé"</string>
     <string name="wallet_title" msgid="5369767670735827105">"Wallet"</string>
     <string name="wallet_empty_state_label" msgid="7776761245237530394">"Préparez-vous à faire des achats plus rapidement et de façon plus sûre avec votre téléphone"</string>
     <string name="wallet_app_button_label" msgid="7123784239111190992">"Tout afficher"</string>
@@ -1405,26 +1410,38 @@
     <string name="launch_touchpad_tutorial_notification_content" msgid="7931085031240753226">"Apprenez à utiliser les gestes du pavé tactile"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_title" msgid="1940023776496198762">"Naviguer à l\'aide de votre clavier et de votre pavé tactile"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Apprenez les gestes du pavé tactile, les raccourcis-clavier et bien plus encore"</string>
-    <string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Geste de retour"</string>
-    <string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Geste d\'accès à l\'écran d\'accueil"</string>
+    <!-- no translation found for touchpad_tutorial_back_gesture_button (3104716365403620315) -->
+    <skip />
+    <!-- no translation found for touchpad_tutorial_home_gesture_button (8023973153559885624) -->
+    <skip />
     <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Afficher les applis récentes"</string>
     <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"OK"</string>
     <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Retour"</string>
-    <string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"Pour revenir en arrière, balayez vers la gauche ou la droite en utilisant trois doigts n\'importe où sur le pavé tactile.\n\nVous pouvez également utiliser le raccourci clavier Action+Échap."</string>
-    <string name="touchpad_back_gesture_success_title" msgid="7240576648330612171">"Bon travail!"</string>
+    <!-- no translation found for touchpad_back_gesture_guidance (5352221087725906542) -->
+    <skip />
+    <!-- no translation found for touchpad_back_gesture_success_title (7370719098633023496) -->
+    <skip />
     <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"Vous avez appris le geste de retour en arrière."</string>
     <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"Retour à la page d\'accueil"</string>
-    <string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"Pour accéder à votre écran d\'accueil à tout moment, balayez l\'écran du bas vers le haut avec trois doigts."</string>
-    <string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Bien!"</string>
-    <string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Vous avez appris le geste de retour à l\'écran d\'accueil."</string>
+    <!-- no translation found for touchpad_home_gesture_guidance (4178219118381915899) -->
+    <skip />
+    <!-- no translation found for touchpad_home_gesture_success_title (3648264553645798470) -->
+    <skip />
+    <!-- no translation found for touchpad_home_gesture_success_body (2590690589194027059) -->
+    <skip />
     <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"Afficher les applis récentes"</string>
-    <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"Balayez l\'écran vers le haut avec trois doigts et maintenez-les en place sur votre pavé tactile."</string>
+    <!-- no translation found for touchpad_recent_apps_gesture_guidance (6304446013842271822) -->
+    <skip />
     <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Bon travail!"</string>
     <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Vous avez effectué le geste pour afficher les applis récentes."</string>
-    <string name="tutorial_action_key_title" msgid="2659466586996495447">"Touche d\'action"</string>
-    <string name="tutorial_action_key_guidance" msgid="5718948664616999196">"Pour accéder à vos applis, appuyez sur la touche d\'action de votre clavier."</string>
-    <string name="tutorial_action_key_success_title" msgid="466467860120112933">"Félicitations!"</string>
-    <string name="tutorial_action_key_success_body" msgid="7201991081652850430">"Vous avez terminé le geste de la touche d\'action.\n\nAction + / affiche tous les raccourcis dont vous disposez."</string>
+    <!-- no translation found for tutorial_action_key_title (8172535792469008169) -->
+    <skip />
+    <!-- no translation found for tutorial_action_key_guidance (5040613427202799294) -->
+    <skip />
+    <!-- no translation found for tutorial_action_key_success_title (2371827347071979571) -->
+    <skip />
+    <!-- no translation found for tutorial_action_key_success_body (1688986269491357832) -->
+    <skip />
     <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Rétroéclairage du clavier"</string>
     <string name="keyboard_backlight_value" msgid="7336398765584393538">"Niveau %1$d de %2$d"</string>
     <string name="home_controls_dream_label" msgid="6567105701292324257">"Domotique"</string>
@@ -1436,6 +1453,7 @@
     <string name="all_apps_edu_toast_content" msgid="8807496014667211562">"Pour afficher toutes vos applis, appuyez sur la touche d\'action de votre clavier"</string>
     <string name="redacted_notification_single_line_title" msgid="212019960919261670">"Supprimé"</string>
     <string name="redacted_notification_single_line_text" msgid="8684166405005242945">"Déverrouiller pour afficher"</string>
+    <string name="contextual_education_dialog_title" msgid="4630392552837487324">"Enseignement contextuel"</string>
     <string name="back_edu_notification_title" msgid="5624780717751357278">"Utiliser votre pavé tactile pour revenir en arrière"</string>
     <string name="back_edu_notification_content" msgid="2497557451540954068">"Balayez vers la gauche ou vers la droite avec trois doigts. Touchez pour apprendre d\'autres gestes."</string>
     <string name="home_edu_notification_title" msgid="6097902076909654045">"Utilisez votre pavé tactile pour accéder à l\'écran d\'accueil"</string>
@@ -1445,7 +1463,7 @@
     <string name="all_apps_edu_notification_title" msgid="372262997265569063">"Utiliser votre clavier pour afficher toutes les applis"</string>
     <string name="all_apps_edu_notification_content" msgid="3255070575694025585">"Appuyez sur la touche d\'action à tout moment. Touchez pour apprendre d\'autres gestes."</string>
     <string name="accessibility_deprecate_extra_dim_dialog_title" msgid="910988771011857460">"La réduction supplémentaire de la luminosité fait désormais partie du curseur de luminosité"</string>
-    <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="4453123359258743230">"Vous pouvez désormais réduire la luminosité de l\'écran encore plus.\n\nÉtant donné que cette fonctionnalité fait désormais partie du curseur de luminosité, les raccourcis de la réduction supplémentaire de la luminosité sont retirés."</string>
+    <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="4453123359258743230">"Vous pouvez désormais réduire la luminosité de l\'écran encore plus.\n\nÉtant donné que cette fonctionnalité fait maintenant partie du curseur de luminosité, les raccourcis de la réduction supplémentaire de la luminosité sont retirés."</string>
     <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="3947537827396916005">"Retirer les raccourcis de la réduction supplémentaire de la luminosité"</string>
     <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="165474092660941104">"Les raccourcis de la réduction supplémentaire de la luminosité ont été retirés"</string>
     <string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"Connectivité"</string>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index fbf5a6c..dccb581 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -197,7 +197,7 @@
     <string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Authentifié"</string>
     <string name="biometric_dialog_cancel_authentication" msgid="981316588773442637">"Annuler l\'authentification"</string>
     <string name="biometric_dialog_content_view_more_options_button" msgid="2663810393874865475">"Plus d\'options"</string>
-    <string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Utiliser un code PIN"</string>
+    <string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Utiliser un code"</string>
     <string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Utiliser un schéma"</string>
     <string name="biometric_dialog_use_password" msgid="3445033859393474779">"Utiliser un mot de passe"</string>
     <string name="biometric_dialog_wrong_pin" msgid="1878539073972762803">"Code incorrect"</string>
@@ -440,7 +440,8 @@
     <string name="zen_mode_on" msgid="9085304934016242591">"Activé"</string>
     <string name="zen_mode_on_with_details" msgid="7416143430557895497">"Activé • <xliff:g id="TRIGGER_DESCRIPTION">%1$s</xliff:g>"</string>
     <string name="zen_mode_off" msgid="1736604456618147306">"Désactivé"</string>
-    <string name="zen_mode_set_up" msgid="7457957033034460064">"Configurer"</string>
+    <!-- no translation found for zen_mode_set_up (8231201163894922821) -->
+    <skip />
     <string name="zen_mode_no_manual_invocation" msgid="1769975741344633672">"Gérer dans les paramètres"</string>
     <string name="zen_mode_active_modes" msgid="1625850411578488856">"{count,plural, =0{Aucun mode actif}=1{{mode} est actif}one{# mode est actif}many{# de modes sont actifs}other{# modes sont actifs}}"</string>
     <string name="zen_priority_introduction" msgid="3159291973383796646">"Vous ne serez pas dérangé par des sons ou des vibrations, hormis ceux des alarmes, des rappels, des événements et des appelants de votre choix. Vous entendrez encore les sons que vous choisirez de jouer, notamment la musique, les vidéos et les jeux."</string>
@@ -573,13 +574,12 @@
     <string name="notification_section_header_conversations" msgid="821834744538345661">"Conversations"</string>
     <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Effacer toutes les notifications silencieuses"</string>
     <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Notifications suspendues par le mode Ne pas déranger"</string>
-    <!-- no translation found for modes_suppressing_shade_text (6037581130837903239) -->
-    <skip />
+    <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{Aucune notification}=1{Notifications suspendues par le mode {mode}}=2{Notifications suspendues par le mode {mode} et un autre mode}one{Notifications suspendues par le mode {mode} et # autre mode}many{Notifications suspendues par le mode {mode} et # d\'autres modes}other{Notifications suspendues par le mode {mode} et # autres modes}}"</string>
     <string name="media_projection_action_text" msgid="3634906766918186440">"Commencer"</string>
     <string name="empty_shade_text" msgid="8935967157319717412">"Aucune notification"</string>
     <string name="no_unseen_notif_text" msgid="395512586119868682">"Aucune nouvelle notification"</string>
     <string name="adaptive_notification_edu_hun_title" msgid="7790738150177329960">"La limitation des notifications est activée"</string>
-    <string name="adaptive_notification_edu_hun_text" msgid="7743367744129536610">"Les alertes et le volume de l\'appareil sont réduits automatiquement pendant 2 minutes max. quand vous recevez trop de notifications à la fois."</string>
+    <string name="adaptive_notification_edu_hun_text" msgid="7743367744129536610">"Les alertes et le volume de l\'appareil sont réduits automatiquement pendant 2 minutes maximum quand vous recevez trop de notifications à la fois."</string>
     <string name="go_to_adaptive_notification_settings" msgid="2423690125178298479">"Désactiver"</string>
     <string name="unlock_to_see_notif_text" msgid="7439033907167561227">"Déverrouiller pour voir anciennes notifications"</string>
     <string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"Cet appareil est géré par tes parents"</string>
@@ -673,6 +673,10 @@
     <string name="stream_notification_unavailable" msgid="4313854556205836435">"Indisponible, car la sonnerie est coupée"</string>
     <string name="stream_alarm_unavailable" msgid="4059817189292197839">"Indisponible car Ne pas déranger est activé"</string>
     <string name="stream_media_unavailable" msgid="6823020894438959853">"Indisponible car Ne pas déranger est activé"</string>
+    <!-- no translation found for stream_unavailable_by_modes (3674139029490353683) -->
+    <skip />
+    <!-- no translation found for stream_unavailable_by_unknown (6908434629318171588) -->
+    <skip />
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Appuyez pour ne plus ignorer."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Appuyez pour mettre en mode vibreur. Vous pouvez ignorer les services d\'accessibilité."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Appuyez pour ignorer. Vous pouvez ignorer les services d\'accessibilité."</string>
@@ -706,6 +710,7 @@
     <string name="show_demo_mode" msgid="3677956462273059726">"Afficher le mode de démonstration"</string>
     <string name="status_bar_ethernet" msgid="5690979758988647484">"Ethernet"</string>
     <string name="status_bar_alarm" msgid="87160847643623352">"Alarme"</string>
+    <string name="active_mode_content_description" msgid="1627555562186515927">"Mode <xliff:g id="MODENAME">%1$s</xliff:g> activé"</string>
     <string name="wallet_title" msgid="5369767670735827105">"Wallet"</string>
     <string name="wallet_empty_state_label" msgid="7776761245237530394">"Configurez un mode de paiement pour régler vos achats de façon sûre et rapide via votre téléphone"</string>
     <string name="wallet_app_button_label" msgid="7123784239111190992">"Tout afficher"</string>
@@ -1405,26 +1410,38 @@
     <string name="launch_touchpad_tutorial_notification_content" msgid="7931085031240753226">"Découvrir les gestes au pavé tactile"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_title" msgid="1940023776496198762">"Naviguer à l\'aide de votre clavier et de votre pavé tactile"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Découvrir les gestes au pavé tactile, les raccourcis clavier et plus encore"</string>
-    <string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Geste Retour"</string>
-    <string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Geste Accueil"</string>
+    <!-- no translation found for touchpad_tutorial_back_gesture_button (3104716365403620315) -->
+    <skip />
+    <!-- no translation found for touchpad_tutorial_home_gesture_button (8023973153559885624) -->
+    <skip />
     <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Afficher les applis récentes"</string>
     <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"OK"</string>
     <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Retour"</string>
-    <string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"Pour revenir en arrière, balayez vers la gauche ou vers la droite avec trois doigts n\'importe où sur le pavé tactile.\n\nVous pouvez aussi utiliser le raccourci clavier Action+Échap pour cela."</string>
-    <string name="touchpad_back_gesture_success_title" msgid="7240576648330612171">"Bravo !"</string>
+    <!-- no translation found for touchpad_back_gesture_guidance (5352221087725906542) -->
+    <skip />
+    <!-- no translation found for touchpad_back_gesture_success_title (7370719098633023496) -->
+    <skip />
     <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"Vous avez appris le geste pour revenir en arrière."</string>
     <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"Retour à l\'accueil"</string>
-    <string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"Pour accéder à l\'écran d\'accueil à tout moment, balayez l\'écran du bas vers le haut avec trois doigts."</string>
-    <string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Bravo !"</string>
-    <string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Vous avez appris le geste pour revenir à l\'écran d\'accueil."</string>
+    <!-- no translation found for touchpad_home_gesture_guidance (4178219118381915899) -->
+    <skip />
+    <!-- no translation found for touchpad_home_gesture_success_title (3648264553645798470) -->
+    <skip />
+    <!-- no translation found for touchpad_home_gesture_success_body (2590690589194027059) -->
+    <skip />
     <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"Afficher les applis récentes"</string>
-    <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"Avec trois doigts, balayez le pavé tactile vers le haut et maintenez la position."</string>
+    <!-- no translation found for touchpad_recent_apps_gesture_guidance (6304446013842271822) -->
+    <skip />
     <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Bravo !"</string>
     <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Vous avez appris le geste pour afficher les applis récentes"</string>
-    <string name="tutorial_action_key_title" msgid="2659466586996495447">"Touche d\'action"</string>
-    <string name="tutorial_action_key_guidance" msgid="5718948664616999196">"Pour accéder à vos applis, appuyez sur la touche d\'action de votre clavier."</string>
-    <string name="tutorial_action_key_success_title" msgid="466467860120112933">"Félicitations !"</string>
-    <string name="tutorial_action_key_success_body" msgid="7201991081652850430">"Vous avez appris le geste permettant d\'utiliser la touche d\'action.\n\nAction+/ affiche tous les raccourcis disponibles."</string>
+    <!-- no translation found for tutorial_action_key_title (8172535792469008169) -->
+    <skip />
+    <!-- no translation found for tutorial_action_key_guidance (5040613427202799294) -->
+    <skip />
+    <!-- no translation found for tutorial_action_key_success_title (2371827347071979571) -->
+    <skip />
+    <!-- no translation found for tutorial_action_key_success_body (1688986269491357832) -->
+    <skip />
     <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Rétroéclairage du clavier"</string>
     <string name="keyboard_backlight_value" msgid="7336398765584393538">"Niveau %1$d sur %2$d"</string>
     <string name="home_controls_dream_label" msgid="6567105701292324257">"Contrôle de la maison"</string>
@@ -1436,6 +1453,7 @@
     <string name="all_apps_edu_toast_content" msgid="8807496014667211562">"Pour afficher toutes vos applis, appuyez sur la touche d\'action de votre clavier"</string>
     <string name="redacted_notification_single_line_title" msgid="212019960919261670">"Masqué"</string>
     <string name="redacted_notification_single_line_text" msgid="8684166405005242945">"Déverrouiller pour afficher"</string>
+    <string name="contextual_education_dialog_title" msgid="4630392552837487324">"Éducation contextuelle"</string>
     <string name="back_edu_notification_title" msgid="5624780717751357278">"Utilisez votre pavé tactile pour revenir en arrière"</string>
     <string name="back_edu_notification_content" msgid="2497557451540954068">"Balayez vers la gauche ou la droite en utilisant trois doigts. Appuyez pour apprendre d\'autres gestes."</string>
     <string name="home_edu_notification_title" msgid="6097902076909654045">"Utilisez votre pavé tactile pour revenir à l\'accueil"</string>
diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml
index b9d0891..b0a432d 100644
--- a/packages/SystemUI/res/values-gl/strings.xml
+++ b/packages/SystemUI/res/values-gl/strings.xml
@@ -440,7 +440,7 @@
     <string name="zen_mode_on" msgid="9085304934016242591">"Activado"</string>
     <string name="zen_mode_on_with_details" msgid="7416143430557895497">"Activo • <xliff:g id="TRIGGER_DESCRIPTION">%1$s</xliff:g>"</string>
     <string name="zen_mode_off" msgid="1736604456618147306">"Desactivado"</string>
-    <string name="zen_mode_set_up" msgid="7457957033034460064">"Configurar"</string>
+    <string name="zen_mode_set_up" msgid="8231201163894922821">"Sen configurar"</string>
     <string name="zen_mode_no_manual_invocation" msgid="1769975741344633672">"Xestionar na configuración"</string>
     <string name="zen_mode_active_modes" msgid="1625850411578488856">"{count,plural, =0{Non hai ningún modo activo}=1{{mode} está activo}other{Hai # modos activos}}"</string>
     <string name="zen_priority_introduction" msgid="3159291973383796646">"Non te molestará ningún son nin vibración, agás os procedentes de alarmas, recordatorios, eventos e os emisores de chamada especificados. Seguirás escoitando todo aquilo que decidas reproducir, mesmo a música, os vídeos e os xogos."</string>
@@ -573,8 +573,7 @@
     <string name="notification_section_header_conversations" msgid="821834744538345661">"Conversas"</string>
     <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Borrar todas as notificacións silenciadas"</string>
     <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"O modo Non molestar puxo en pausa as notificacións"</string>
-    <!-- no translation found for modes_suppressing_shade_text (6037581130837903239) -->
-    <skip />
+    <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{Non hai ningunha notificación}=1{Notificacións postas en pausa polo modo {mode}}=2{Notificacións postas en pausa polo modo {mode} e un máis}other{Notificacións postas en pausa polo modo {mode} e # máis}}"</string>
     <string name="media_projection_action_text" msgid="3634906766918186440">"Iniciar agora"</string>
     <string name="empty_shade_text" msgid="8935967157319717412">"Non hai notificacións"</string>
     <string name="no_unseen_notif_text" msgid="395512586119868682">"Non hai notificacións novas"</string>
@@ -673,6 +672,10 @@
     <string name="stream_notification_unavailable" msgid="4313854556205836435">"Non dispoñible: o son está silenciado"</string>
     <string name="stream_alarm_unavailable" msgid="4059817189292197839">"Non dispoñible: Non molestar está activado"</string>
     <string name="stream_media_unavailable" msgid="6823020894438959853">"Non dispoñible: Non molestar está activado"</string>
+    <!-- no translation found for stream_unavailable_by_modes (3674139029490353683) -->
+    <skip />
+    <!-- no translation found for stream_unavailable_by_unknown (6908434629318171588) -->
+    <skip />
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Toca para activar o son."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Toca para establecer a vibración. Pódense silenciar os servizos de accesibilidade."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Toca para silenciar. Pódense silenciar os servizos de accesibilidade."</string>
@@ -706,6 +709,7 @@
     <string name="show_demo_mode" msgid="3677956462273059726">"Mostrar modo de demostración"</string>
     <string name="status_bar_ethernet" msgid="5690979758988647484">"Ethernet"</string>
     <string name="status_bar_alarm" msgid="87160847643623352">"Alarma"</string>
+    <string name="active_mode_content_description" msgid="1627555562186515927">"<xliff:g id="MODENAME">%1$s</xliff:g> activado"</string>
     <string name="wallet_title" msgid="5369767670735827105">"Wallet"</string>
     <string name="wallet_empty_state_label" msgid="7776761245237530394">"Configura un método de pago para comprar de xeito máis rápido e seguro co teléfono"</string>
     <string name="wallet_app_button_label" msgid="7123784239111190992">"Amosar todo"</string>
@@ -1405,26 +1409,26 @@
     <string name="launch_touchpad_tutorial_notification_content" msgid="7931085031240753226">"Aprende a usar os xestos do panel táctil"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_title" msgid="1940023776496198762">"Navega co teclado e o panel táctil"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Aprende a usar os xestos do panel táctil, atallos de teclado e moito máis"</string>
-    <string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Xesto para volver"</string>
-    <string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Xesto para ir ao inicio"</string>
+    <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"Volver"</string>
+    <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Ir ao inicio"</string>
     <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Consultar aplicacións recentes"</string>
     <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Feito"</string>
     <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Volver"</string>
-    <string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"Para retroceder, pasa tres dedos cara á esquerda ou cara á dereita en calquera parte do panel táctil.\n\nTamén podes usar o atallo de teclado Acción + Escape."</string>
-    <string name="touchpad_back_gesture_success_title" msgid="7240576648330612171">"Moi ben!"</string>
+    <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"Pasa tres dedos cara á esquerda ou cara á dereita no panel táctil"</string>
+    <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"Excelente!"</string>
     <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"Completaches o xesto de retroceso."</string>
     <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"Ir ao inicio"</string>
-    <string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"Para ir á pantalla de inicio, pasa tres dedos cara arriba desde a parte inferior da pantalla."</string>
-    <string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Excelente!"</string>
-    <string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Completaches o xesto de ir ao inicio."</string>
+    <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"Pasa tres dedos cara arriba no panel táctil"</string>
+    <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"Excelente traballo."</string>
+    <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"Completaches o titorial do xesto de ir ao inicio"</string>
     <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"Consultar aplicacións recentes"</string>
-    <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"Pasa tres dedos cara arriba e mantenos premidos no panel táctil."</string>
+    <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"Pasa tres dedos cara arriba e mantenos premidos no panel táctil"</string>
     <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Moi ben!"</string>
     <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Completaches o titorial do xesto de consultar aplicacións recentes."</string>
-    <string name="tutorial_action_key_title" msgid="2659466586996495447">"Tecla de acción"</string>
-    <string name="tutorial_action_key_guidance" msgid="5718948664616999196">"Para acceder ás aplicacións, preme a tecla de acción do teclado."</string>
-    <string name="tutorial_action_key_success_title" msgid="466467860120112933">"Parabéns!"</string>
-    <string name="tutorial_action_key_success_body" msgid="7201991081652850430">"Completaches o xesto da tecla de acción.\n\nAcción + / mostra todos os atallos que tes á túa disposición."</string>
+    <string name="tutorial_action_key_title" msgid="8172535792469008169">"Ver todas as aplicacións"</string>
+    <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Preme a tecla de acción do teclado"</string>
+    <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Ben feito!"</string>
+    <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Completaches o titorial do xesto de ver todas as aplicacións"</string>
     <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Retroiluminación do teclado"</string>
     <string name="keyboard_backlight_value" msgid="7336398765584393538">"Nivel %1$d de %2$d"</string>
     <string name="home_controls_dream_label" msgid="6567105701292324257">"Controis domóticos"</string>
@@ -1436,6 +1440,7 @@
     <string name="all_apps_edu_toast_content" msgid="8807496014667211562">"Para ver todas as aplicacións, preme a tecla de acción do teclado"</string>
     <string name="redacted_notification_single_line_title" msgid="212019960919261670">"Contido ocultado"</string>
     <string name="redacted_notification_single_line_text" msgid="8684166405005242945">"Desbloquea o dispositivo para ver o contido"</string>
+    <string name="contextual_education_dialog_title" msgid="4630392552837487324">"Información contextual"</string>
     <string name="back_edu_notification_title" msgid="5624780717751357278">"Usa o panel táctil para volver"</string>
     <string name="back_edu_notification_content" msgid="2497557451540954068">"Pasa tres dedos cara á esquerda ou cara á dereita. Toca para obter máis información sobre os xestos."</string>
     <string name="home_edu_notification_title" msgid="6097902076909654045">"Usa o panel táctil para volver ao inicio"</string>
diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml
index e9998e4..5de2293 100644
--- a/packages/SystemUI/res/values-gu/strings.xml
+++ b/packages/SystemUI/res/values-gu/strings.xml
@@ -440,7 +440,7 @@
     <string name="zen_mode_on" msgid="9085304934016242591">"ચાલુ"</string>
     <string name="zen_mode_on_with_details" msgid="7416143430557895497">"ચાલુ • <xliff:g id="TRIGGER_DESCRIPTION">%1$s</xliff:g>"</string>
     <string name="zen_mode_off" msgid="1736604456618147306">"બંધ"</string>
-    <string name="zen_mode_set_up" msgid="7457957033034460064">"સેટઅપ કરો"</string>
+    <string name="zen_mode_set_up" msgid="8231201163894922821">"સેટઅપ કર્યું નથી"</string>
     <string name="zen_mode_no_manual_invocation" msgid="1769975741344633672">"સેટિંગમાં જઈને મેનેજ કરો"</string>
     <string name="zen_mode_active_modes" msgid="1625850411578488856">"{count,plural, =0{કોઈ સક્રિય મોડ નથી}=1{{mode} સક્રિય છે}one{# મોડ સક્રિય છે}other{# મોડ સક્રિય છે}}"</string>
     <string name="zen_priority_introduction" msgid="3159291973383796646">"અલાર્મ, રિમાઇન્ડર, ઇવેન્ટ અને તમે ઉલ્લેખ કરો તે કૉલર સિવાય તમને ધ્વનિ કે વાઇબ્રેશન દ્વારા ખલેલ પહોંચાડવામાં આવશે નહીં. સંગીત, વીડિઓ અને રમતો સહિત તમે જે કંઈપણ ચલાવવાનું પસંદ કરશો તે સંભળાતું રહેશે."</string>
@@ -573,8 +573,7 @@
     <string name="notification_section_header_conversations" msgid="821834744538345661">"વાતચીત"</string>
     <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"બધા સાઇલન્ટ નોટિફિકેશન સાફ કરો"</string>
     <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"ખલેલ પાડશો નહીં દ્વારા થોભાવેલ નોટિફિકેશન"</string>
-    <!-- no translation found for modes_suppressing_shade_text (6037581130837903239) -->
-    <skip />
+    <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{કોઈ નોટિફિકેશન નથી}=1{{mode} દ્વારા નોટિફિકેશન થોભાવવામાં આવ્યા}=2{{mode} અને અન્ય એક મોડ દ્વારા નોટિફિકેશન થોભાવવામાં આવ્યા}one{{mode} અને અન્ય # મોડ દ્વારા નોટિફિકેશન થોભાવવામાં આવ્યા}other{{mode} અને અન્ય # મોડ દ્વારા નોટિફિકેશન થોભાવવામાં આવ્યા}}"</string>
     <string name="media_projection_action_text" msgid="3634906766918186440">"હવે શરૂ કરો"</string>
     <string name="empty_shade_text" msgid="8935967157319717412">"કોઈ નોટિફિકેશન નથી"</string>
     <string name="no_unseen_notif_text" msgid="395512586119868682">"કોઈ નવું નોટિફિકેશન નથી"</string>
@@ -673,6 +672,10 @@
     <string name="stream_notification_unavailable" msgid="4313854556205836435">"રિંગ મ્યૂટ કરી હોવાના કારણે અનુપલબ્ધ છે"</string>
     <string name="stream_alarm_unavailable" msgid="4059817189292197839">"ઉપલબ્ધ નથી, કારણ કે ખલેલ પાડશો નહીં મોડ ચાલુ છે"</string>
     <string name="stream_media_unavailable" msgid="6823020894438959853">"ઉપલબ્ધ નથી, કારણ કે ખલેલ પાડશો નહીં મોડ ચાલુ છે"</string>
+    <!-- no translation found for stream_unavailable_by_modes (3674139029490353683) -->
+    <skip />
+    <!-- no translation found for stream_unavailable_by_unknown (6908434629318171588) -->
+    <skip />
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. અનમ્યૂટ કરવા માટે ટૅપ કરો."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. વાઇબ્રેટ પર સેટ કરવા માટે ટૅપ કરો. ઍક્સેસિબિલિટી સેવાઓ મ્યૂટ કરવામાં આવી શકે છે."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. મ્યૂટ કરવા માટે ટૅપ કરો. ઍક્સેસિબિલિટી સેવાઓ મ્યૂટ કરવામાં આવી શકે છે."</string>
@@ -706,6 +709,7 @@
     <string name="show_demo_mode" msgid="3677956462273059726">"ડેમો મોડ બતાવો"</string>
     <string name="status_bar_ethernet" msgid="5690979758988647484">"ઇથરનેટ"</string>
     <string name="status_bar_alarm" msgid="87160847643623352">"અલાર્મ"</string>
+    <string name="active_mode_content_description" msgid="1627555562186515927">"<xliff:g id="MODENAME">%1$s</xliff:g> ચાલુ છે"</string>
     <string name="wallet_title" msgid="5369767670735827105">"Wallet"</string>
     <string name="wallet_empty_state_label" msgid="7776761245237530394">"તમારા ફોન વડે વધુ ઝડપી તેમજ સુરક્ષિત ખરીદીઓ કરવાની રીત સેટઅપ કરી લો"</string>
     <string name="wallet_app_button_label" msgid="7123784239111190992">"બધું બતાવો"</string>
@@ -1405,26 +1409,26 @@
     <string name="launch_touchpad_tutorial_notification_content" msgid="7931085031240753226">"ટચપૅડના સંકેતો વિશે જાણો"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_title" msgid="1940023776496198762">"તમારા કીબોર્ડ અને ટચપૅડ વડે નૅવિગેટ કરો"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"ટચપૅડના સંકેતો અને કીબોર્ડના શૉર્ટકટ જેવું બીજું ઘણું જાણો"</string>
-    <string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"પાછળ જવાનો સંકેત"</string>
-    <string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"હોમ સ્ક્રીન પર જવાનો સંકેત"</string>
+    <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"પાછા જાઓ"</string>
+    <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"હોમ પર જાઓ"</string>
     <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"તાજેતરની ઍપ જુઓ"</string>
     <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"થઈ ગયું"</string>
     <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"પાછા જાઓ"</string>
-    <string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"પાછા જવા માટે, ટચપૅડ પર ગમે ત્યાં ત્રણ આંગળી વડે ડાબે અથવા જમણે સ્વાઇપ કરો.\n\nઆના માટે તમે કીબોર્ડ શૉર્ટકટ Action + ESCનો ઉપયોગ કરી શકો છો."</string>
-    <string name="touchpad_back_gesture_success_title" msgid="7240576648330612171">"ખૂબ સરસ કામ!"</string>
+    <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"તમારા ટચપૅડ પર ત્રણ આંગળીનો ઉપયોગ કરીને ડાબે કે જમણે સ્વાઇપ કરો"</string>
+    <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"સરસ!"</string>
     <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"તમે પાછા જવાનો સંકેત પૂર્ણ કર્યો છે."</string>
     <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"હોમ પર જાઓ"</string>
-    <string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"કોઈપણ સમયે તમારી હોમ સ્ક્રીન પર જવા માટે, ત્રણ આંગળી વડે તમારી સ્ક્રીનની સૌથી નીચેની બાજુએથી ઉપરની તરફ સ્વાઇપ કરો."</string>
-    <string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"સરસ!"</string>
-    <string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"તમે હોમ સ્ક્રીન પર જવાનો સંકેત પૂર્ણ કર્યો છે."</string>
+    <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"તમારા ટચપૅડ પર ત્રણ આંગળી વડે ઉપરની તરફ સ્વાઇપ કરો"</string>
+    <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"ખૂબ સરસ કામ!"</string>
+    <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"તમે હોમ સ્ક્રીન પર જવાનો સંકેત પૂર્ણ કર્યો"</string>
     <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"તાજેતરની ઍપ જુઓ"</string>
-    <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"તમારા ટચપૅડ પર ત્રણ આંગળીઓનો ઉપયોગ કરીને ઉપર સ્વાઇપ કરો અને દબાવી રાખો."</string>
+    <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"તમારા ટચપૅડ પર ત્રણ આંગળીઓનો ઉપયોગ કરીને ઉપર સ્વાઇપ કરો અને દબાવી રાખો"</string>
     <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"ખૂબ સરસ કામ!"</string>
     <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"તમે \"તાજેતરની ઍપ જુઓ\" સંકેત પૂર્ણ કર્યો."</string>
-    <string name="tutorial_action_key_title" msgid="2659466586996495447">"ઍક્શન કી"</string>
-    <string name="tutorial_action_key_guidance" msgid="5718948664616999196">"તમારી ઍપ ઍક્સેસ કરવા માટે, તમારા કીબોર્ડ પરની ઍક્શન કી દબાવો."</string>
-    <string name="tutorial_action_key_success_title" msgid="466467860120112933">"અભિનંદન!"</string>
-    <string name="tutorial_action_key_success_body" msgid="7201991081652850430">"તમે ઍક્શન કીનો સંકેત પૂર્ણ કર્યો છે.\n\nઍક્શન કી + /ને દબાવવાથી, તમારી પાસે ઉપલબ્ધ હોય તે બધા શૉર્ટકટ જોવા મળે છે."</string>
+    <string name="tutorial_action_key_title" msgid="8172535792469008169">"બધી ઍપ જુઓ"</string>
+    <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"તમારા કીબોર્ડ પરની ઍક્શન કી દબાવો"</string>
+    <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"વાહ!"</string>
+    <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"તમે \"બધી ઍપ જુઓ\" સંકેત પૂર્ણ કર્યો"</string>
     <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"કીબોર્ડની બૅકલાઇટ"</string>
     <string name="keyboard_backlight_value" msgid="7336398765584393538">"%2$dમાંથી %1$d લેવલ"</string>
     <string name="home_controls_dream_label" msgid="6567105701292324257">"ઘરેલું સાધનોના નિયંત્રણો"</string>
@@ -1436,6 +1440,7 @@
     <string name="all_apps_edu_toast_content" msgid="8807496014667211562">"તમારી બધી ઍપ જોવા માટે, તમારા કીબોર્ડ પર ઍક્શન કી દબાવો"</string>
     <string name="redacted_notification_single_line_title" msgid="212019960919261670">"બદલાવેલું"</string>
     <string name="redacted_notification_single_line_text" msgid="8684166405005242945">"જોવા માટે અનલૉક કરો"</string>
+    <string name="contextual_education_dialog_title" msgid="4630392552837487324">"સંદર્ભાત્મક શિક્ષણ"</string>
     <string name="back_edu_notification_title" msgid="5624780717751357278">"પાછા જવા માટે તમારા ટચપૅડનો ઉપયોગ કરો"</string>
     <string name="back_edu_notification_content" msgid="2497557451540954068">"ત્રણ આંગળીનો ઉપયોગ કરીને ડાબે અથવા જમણે સ્વાઇપ કરો. સંકેતો વિશે વધુ જાણવા માટે ટૅપ કરો."</string>
     <string name="home_edu_notification_title" msgid="6097902076909654045">"હોમ સ્ક્રીન પર જવા માટે તમારા ટચપૅડનો ઉપયોગ કરો"</string>
@@ -1444,7 +1449,7 @@
     <string name="overview_edu_notification_content" msgid="3578204677648432500">"ત્રણ આંગળીઓનો ઉપયોગ કરીને ઉપર સ્વાઇપ કરો અને દબાવી રાખો. સંકેતો વિશે વધુ જાણવા માટે ટૅપ કરો."</string>
     <string name="all_apps_edu_notification_title" msgid="372262997265569063">"બધી ઍપ જોવા માટે તમારા કીબોર્ડનો ઉપયોગ કરો"</string>
     <string name="all_apps_edu_notification_content" msgid="3255070575694025585">"કોઈપણ સમયે ઍક્શન કી દબાવો. સંકેતો વિશે વધુ જાણવા માટે ટૅપ કરો."</string>
-    <string name="accessibility_deprecate_extra_dim_dialog_title" msgid="910988771011857460">"બ્રાઇટનેસ સ્લાઇડર હવે એક્સ્ટ્રા ડિમનો ભાગ છે"</string>
+    <string name="accessibility_deprecate_extra_dim_dialog_title" msgid="910988771011857460">"એક્સ્ટ્રા ડિમ હવે બ્રાઇટનેસ સ્લાઇડરનો ભાગ છે"</string>
     <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="4453123359258743230">"તમે હવે બ્રાઇટનેસ લેવલને હજી પણ ઘટાડીને સ્ક્રીનને એક્સ્ટ્રા ડિમ બનાવી શકો છો.\n\nઆ સુવિધા હવે બ્રાઇટનેસ સ્લાઇડરનો ભાગ હોવાથી એક્સ્ટ્રા ડિમ શૉર્ટકટને કાઢી નાખવામાં આવી રહ્યાં છે."</string>
     <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="3947537827396916005">"એક્સ્ટ્રા ડિમ શૉર્ટકટ કાઢી નાખો"</string>
     <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="165474092660941104">"એક્સ્ટ્રા ડિમ શૉર્ટકટ કાઢી નાખ્યા"</string>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index 534da68..15b3639 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -440,7 +440,7 @@
     <string name="zen_mode_on" msgid="9085304934016242591">"चालू है"</string>
     <string name="zen_mode_on_with_details" msgid="7416143430557895497">"<xliff:g id="TRIGGER_DESCRIPTION">%1$s</xliff:g> • पर"</string>
     <string name="zen_mode_off" msgid="1736604456618147306">"बंद है"</string>
-    <string name="zen_mode_set_up" msgid="7457957033034460064">"सेट अप करें"</string>
+    <string name="zen_mode_set_up" msgid="8231201163894922821">"सेट नहीं है"</string>
     <string name="zen_mode_no_manual_invocation" msgid="1769975741344633672">"सेटिंग में जाकर मैनेज करें"</string>
     <string name="zen_mode_active_modes" msgid="1625850411578488856">"{count,plural, =0{कोई मोड चालू नहीं है}=1{{mode} चालू है}one{# मोड चालू है}other{# मोड चालू हैं}}"</string>
     <string name="zen_priority_introduction" msgid="3159291973383796646">"आपको अलार्म, रिमाइंडर, इवेंट और चुनिंदा कॉल करने वालों के अलावा किसी और तरह से (आवाज़ करके और थरथरा कर ) परेशान नहीं किया जाएगा. आप फिर भी संगीत, वीडियो और गेम सहित अपना चुना हुआ सब कुछ सुन सकते हैं."</string>
@@ -573,8 +573,7 @@
     <string name="notification_section_header_conversations" msgid="821834744538345661">"बातचीत"</string>
     <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"बिना आवाज़ की सभी सूचनाएं हटाएं"</string>
     <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"\'परेशान न करें\' सुविधा के ज़रिए कुछ समय के लिए सूचनाएं दिखाना रोक दिया गया है"</string>
-    <!-- no translation found for modes_suppressing_shade_text (6037581130837903239) -->
-    <skip />
+    <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{कोई सूचना नहीं है}=1{{mode} की वजह से सूचना नहीं दिख रही है}=2{{mode} और एक अन्य मोड की वजह से सूचना नहीं दिख रही है}one{{mode} और # अन्य मोड की वजह से सूचना नहीं दिख रही है}other{{mode} और # अन्य मोड के की वजह से सूचनाएं नहीं दिख रही है}}"</string>
     <string name="media_projection_action_text" msgid="3634906766918186440">"अभी शुरू करें"</string>
     <string name="empty_shade_text" msgid="8935967157319717412">"कोई सूचना नहीं है"</string>
     <string name="no_unseen_notif_text" msgid="395512586119868682">"कोई नई सूचना नहीं है"</string>
@@ -673,6 +672,10 @@
     <string name="stream_notification_unavailable" msgid="4313854556205836435">"आवाज़ नहीं आएगी, क्योंकि रिंग म्यूट है"</string>
     <string name="stream_alarm_unavailable" msgid="4059817189292197839">"सुविधा बंद है, क्योंकि \'परेशान न करें\' मोड चालू है"</string>
     <string name="stream_media_unavailable" msgid="6823020894438959853">"आवाज़ बंद है, क्योंकि \'परेशान न करें\' मोड चालू है"</string>
+    <!-- no translation found for stream_unavailable_by_modes (3674139029490353683) -->
+    <skip />
+    <!-- no translation found for stream_unavailable_by_unknown (6908434629318171588) -->
+    <skip />
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. अनम्यूट करने के लिए टैप करें."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. कंपन पर सेट करने के लिए टैप करें. सुलभता सेवाएं म्यूट हो सकती हैं."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. म्यूट करने के लिए टैप करें. सुलभता सेवाएं म्यूट हो सकती हैं."</string>
@@ -706,6 +709,7 @@
     <string name="show_demo_mode" msgid="3677956462273059726">"डेमो मोड दिखाएं"</string>
     <string name="status_bar_ethernet" msgid="5690979758988647484">"ईथरनेट"</string>
     <string name="status_bar_alarm" msgid="87160847643623352">"अलार्म"</string>
+    <string name="active_mode_content_description" msgid="1627555562186515927">"<xliff:g id="MODENAME">%1$s</xliff:g> चालू है"</string>
     <string name="wallet_title" msgid="5369767670735827105">"Wallet"</string>
     <string name="wallet_empty_state_label" msgid="7776761245237530394">"फ़ोन के ज़रिए तेज़ी से और सुरक्षित तरीके से खरीदारी करने के लिए सेट अप करें"</string>
     <string name="wallet_app_button_label" msgid="7123784239111190992">"सभी दिखाएं"</string>
@@ -1316,7 +1320,7 @@
     <string name="log_access_confirmation_title" msgid="4843557604739943395">"<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> को डिवाइस लॉग ऐक्सेस करने की अनुमति देनी है?"</string>
     <string name="log_access_confirmation_allow" msgid="752147861593202968">"एक बार ऐक्सेस करने की अनुमति दें"</string>
     <string name="log_access_confirmation_deny" msgid="2389461495803585795">"अनुमति न दें"</string>
-    <string name="log_access_confirmation_body" msgid="6883031912003112634">"डिवाइस लॉग में आपके डिवाइस पर की गई कार्रवाइयां रिकॉर्ड होती हैं. ऐप्लिकेशन, इन लॉग का इस्तेमाल गड़बड़ियां ढूंढने और उन्हें ठीक करने के लिए कर सकते हैं.\n\nकुछ लॉग में संवेदनशील जानकारी हो सकती है. इसलिए, सिर्फ़ भरोसेमंद ऐप्लिकेशन को डिवाइस के सभी लॉग का ऐक्सेस दें. \n\nअगर इस ऐप्लिकेशन को डिवाइस के सभी लॉग का ऐक्सेस नहीं दिया जाता है, तब भी यह डिवाइस पर मौजूद अपने लॉग ऐक्सेस कर सकता है. डिवाइस को बनाने वाली कंपनी फिर भी डिवाइस के कुछ लॉग या जानकारी ऐक्सेस कर सकती है."</string>
+    <string name="log_access_confirmation_body" msgid="6883031912003112634">"डिवाइस लॉग में आपके डिवाइस पर की गई कार्रवाइयां रिकॉर्ड होती हैं. ऐप्लिकेशन, इन लॉग का इस्तेमाल गड़बड़ियां ढूंढने और उन्हें ठीक करने के लिए कर सकते हैं.\n\nकुछ लॉग में संवेदनशील जानकारी हो सकती है. इसलिए, सिर्फ़ भरोसेमंद ऐप्लिकेशन को डिवाइस के सभी लॉग का ऐक्सेस दें. \n\nअगर इस ऐप्लिकेशन को डिवाइस के सभी लॉग का ऐक्सेस नहीं दिया जाता है, तब भी यह डिवाइस पर मौजूद अपने लॉग ऐक्सेस कर सकता है. इसके अलावा, डिवाइस को बनाने वाली कंपनी भी डिवाइस के कुछ लॉग या जानकारी ऐक्सेस कर सकती है."</string>
     <string name="log_access_confirmation_learn_more" msgid="3134565480986328004">"ज़्यादा जानें"</string>
     <string name="log_access_confirmation_learn_more_at" msgid="5635666259505215905">"ज़्यादा जानने के लिए <xliff:g id="URL">%s</xliff:g> पर जाएं"</string>
     <string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"<xliff:g id="APPNAME">%1$s</xliff:g> खोलें"</string>
@@ -1405,26 +1409,26 @@
     <string name="launch_touchpad_tutorial_notification_content" msgid="7931085031240753226">"टचपैड पर हाथ के जेस्चर के बारे में जानें"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_title" msgid="1940023776496198762">"कीबोर्ड और टचपैड का इस्तेमाल करके नेविगेट करें"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"टचपैड पर हाथ के जेस्चर, कीबोर्ड शॉर्टकट वगैरह के बारे में जानें"</string>
-    <string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"पीछे जाने का जेस्चर"</string>
-    <string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"होम स्क्रीन पर जाने का जेस्चर"</string>
+    <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"वापस जाएं"</string>
+    <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"होम स्क्रीन पर जाएं"</string>
     <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"हाल ही में इस्तेमाल किए गए ऐप्लिकेशन देखें"</string>
     <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"हो गया"</string>
     <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"वापस जाएं"</string>
-    <string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"वापस जाने के लिए, टचपैड पर कहीं भी तीन उंगलियों से दाईं या बाईं ओर स्वाइप करें.\n\nइसके अलावा, ऐसा करने के लिए Action + ESC बटन का भी इस्तेमाल किया जा सकता है."</string>
-    <string name="touchpad_back_gesture_success_title" msgid="7240576648330612171">"बहुत बढ़िया!"</string>
+    <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"अपने टचपैड पर तीन उंगलियों का इस्तेमाल करके, बाईं या दाईं ओर स्वाइप करें"</string>
+    <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"बढ़िया!"</string>
     <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"अब आपने जान लिया है कि हाथ का जेस्चर इस्तेमाल करके, पिछली स्क्रीन पर वापस कैसे जाएं."</string>
     <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"होम स्क्रीन पर जाएं"</string>
-    <string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"किसी भी समय फ़ोन की होम स्क्रीन पर जाने के लिए, तीन उंगलियों से फ़ोन पर सबसे नीचे से ऊपर की ओर स्वाइप करें."</string>
-    <string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"बढ़िया!"</string>
-    <string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"आपने जान लिया कि हाथ का जेस्चर इस्तेमाल करके, होम स्क्रीन पर कैसे जाएं."</string>
+    <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"अपने टचपैड पर तीन उंगलियों से ऊपर की ओर स्वाइप करें"</string>
+    <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"बहुत बढ़िया!"</string>
+    <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"अब आपको इस बारे में जानकारी है कि हाथ के जेस्चर का इस्तेमाल करके होम स्क्रीन पर कैसे जाते हैं"</string>
     <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"हाल ही में इस्तेमाल किए गए ऐप्लिकेशन देखें"</string>
-    <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"अपने टचपैड पर तीन उंगलियों से ऊपर की ओर स्वाइप करें और फिर होल्ड करें."</string>
+    <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"अपने टचपैड पर तीन उंगलियों से ऊपर की ओर स्वाइप करें और फिर होल्ड करें"</string>
     <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"बहुत बढ़िया!"</string>
     <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"आपने हाल ही में इस्तेमाल किए गए ऐप्लिकेशन देखने के लिए, हाथ के जेस्चर के बारे में जान लिया है."</string>
-    <string name="tutorial_action_key_title" msgid="2659466586996495447">"ऐक्शन बटन"</string>
-    <string name="tutorial_action_key_guidance" msgid="5718948664616999196">"अपने ऐप्लिकेशन ऐक्सेस करने के लिए, कीबोर्ड पर ऐक्शन बटन दबाएं."</string>
-    <string name="tutorial_action_key_success_title" msgid="466467860120112933">"बधाई हो!"</string>
-    <string name="tutorial_action_key_success_body" msgid="7201991081652850430">"आपने ऐक्शन बटन का जेस्चर इस्तेमाल करने की प्रोसेस पूरी कर ली है.\n\nऐक्शन बटन और / को साथ में दबाने पर, आपके पास उपलब्ध सभी शॉर्टकट दिखते हैं."</string>
+    <string name="tutorial_action_key_title" msgid="8172535792469008169">"सभी ऐप्लिकेशन देखें"</string>
+    <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"अपने कीबोर्ड पर ऐक्शन बटन दबाएं"</string>
+    <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"बहुत खूब!"</string>
+    <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"अब आपको इस बारे में जानकारी है कि सभी ऐप्लिकेशन देखने के लिए, हाथ के जेस्चर का इस्तेमाल कैसे किया जाता है"</string>
     <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"कीबोर्ड की बैकलाइट"</string>
     <string name="keyboard_backlight_value" msgid="7336398765584393538">"%2$d में से %1$d लेवल"</string>
     <string name="home_controls_dream_label" msgid="6567105701292324257">"होम कंट्रोल"</string>
@@ -1436,6 +1440,7 @@
     <string name="all_apps_edu_toast_content" msgid="8807496014667211562">"सभी ऐप्लिकेशन देखने के लिए, कीबोर्ड पर ऐक्शन बटन दबाएं"</string>
     <string name="redacted_notification_single_line_title" msgid="212019960919261670">"जानकारी छिपाने के लिए सूचना में बदलाव किया गया"</string>
     <string name="redacted_notification_single_line_text" msgid="8684166405005242945">"देखने के लिए डिवाइस अनलॉक करें"</string>
+    <string name="contextual_education_dialog_title" msgid="4630392552837487324">"कॉन्टेक्स्ट के हिसाब से जानकारी"</string>
     <string name="back_edu_notification_title" msgid="5624780717751357278">"वापस जाने के लिए, अपने डिवाइस के टचपैड का इस्तेमाल करें"</string>
     <string name="back_edu_notification_content" msgid="2497557451540954068">"तीन उंगलियों से बाईं या दाईं ओर स्वाइप करें. जेस्चर के बारे में ज़्यादा जानने के लिए टैप करें."</string>
     <string name="home_edu_notification_title" msgid="6097902076909654045">"होम पर जाने के लिए, अपने डिवाइस के टचपैड का इस्तेमाल करें"</string>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index 0d226b1..f646ee6 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -440,7 +440,7 @@
     <string name="zen_mode_on" msgid="9085304934016242591">"Uključeno"</string>
     <string name="zen_mode_on_with_details" msgid="7416143430557895497">"Uklj. • <xliff:g id="TRIGGER_DESCRIPTION">%1$s</xliff:g>"</string>
     <string name="zen_mode_off" msgid="1736604456618147306">"Isključeno"</string>
-    <string name="zen_mode_set_up" msgid="7457957033034460064">"Postavi"</string>
+    <string name="zen_mode_set_up" msgid="8231201163894922821">"Nije postavljeno"</string>
     <string name="zen_mode_no_manual_invocation" msgid="1769975741344633672">"Upravljajte u postavkama"</string>
     <string name="zen_mode_active_modes" msgid="1625850411578488856">"{count,plural, =0{Nema aktivnih načina}=1{Aktivno: {mode}}one{# način je aktivan}few{# načina su aktivna}other{# načina je aktivno}}"</string>
     <string name="zen_priority_introduction" msgid="3159291973383796646">"Neće vas ometati zvukovi i vibracije, osim alarma, podsjetnika, događaja i pozivatelja koje navedete. I dalje ćete čuti sve što želite reproducirati, uključujući glazbu, videozapise i igre."</string>
@@ -573,8 +573,7 @@
     <string name="notification_section_header_conversations" msgid="821834744538345661">"Razgovori"</string>
     <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Izbriši sve bešumne obavijesti"</string>
     <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Značajka Ne uznemiravaj pauzirala je Obavijesti"</string>
-    <!-- no translation found for modes_suppressing_shade_text (6037581130837903239) -->
-    <skip />
+    <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{Nema obavijesti}=1{Obavijesti je pauzirao način {mode}}=2{Obavijesti su pauzirali način {mode} i još jedan način}one{Obavijesti su pauzirali način {mode} i još # način rada}few{Obavijesti su pauzirali način {mode} i još # načina rada}other{Obavijesti su pauzirali način {mode} i još # načina rada}}"</string>
     <string name="media_projection_action_text" msgid="3634906766918186440">"Pokreni"</string>
     <string name="empty_shade_text" msgid="8935967157319717412">"Nema obavijesti"</string>
     <string name="no_unseen_notif_text" msgid="395512586119868682">"Nema novih obavijesti"</string>
@@ -673,6 +672,10 @@
     <string name="stream_notification_unavailable" msgid="4313854556205836435">"Nedostupno jer je zvono utišano"</string>
     <string name="stream_alarm_unavailable" msgid="4059817189292197839">"Nedostupno jer je uključen način Ne uznemiravaj"</string>
     <string name="stream_media_unavailable" msgid="6823020894438959853">"Nedostupno jer je uključen način Ne uznemiravaj"</string>
+    <!-- no translation found for stream_unavailable_by_modes (3674139029490353683) -->
+    <skip />
+    <!-- no translation found for stream_unavailable_by_unknown (6908434629318171588) -->
+    <skip />
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Dodirnite da biste uključili zvuk."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Dodirnite da biste postavili na vibraciju. Usluge pristupačnosti možda neće imati zvuk."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Dodirnite da biste isključili zvuk. Usluge pristupačnosti možda neće imati zvuk."</string>
@@ -706,6 +709,7 @@
     <string name="show_demo_mode" msgid="3677956462273059726">"Prikaži demo način"</string>
     <string name="status_bar_ethernet" msgid="5690979758988647484">"Ethernet"</string>
     <string name="status_bar_alarm" msgid="87160847643623352">"Alarm"</string>
+    <string name="active_mode_content_description" msgid="1627555562186515927">"Uključen je način <xliff:g id="MODENAME">%1$s</xliff:g>"</string>
     <string name="wallet_title" msgid="5369767670735827105">"Wallet"</string>
     <string name="wallet_empty_state_label" msgid="7776761245237530394">"Postavite aplikaciju za bržu i sigurniju kupnju telefonom"</string>
     <string name="wallet_app_button_label" msgid="7123784239111190992">"Prikaži sve"</string>
@@ -1405,26 +1409,26 @@
     <string name="launch_touchpad_tutorial_notification_content" msgid="7931085031240753226">"Saznajte više o pokretima za dodirnu podlogu"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_title" msgid="1940023776496198762">"Krećite se pomoću tipkovnice i dodirne podloge"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Saznajte više o pokretima za dodirnu podlogu, tipkovnim prečacima i ostalom"</string>
-    <string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Pokret za povratak"</string>
-    <string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Pokret za otvaranje početnog zaslona"</string>
+    <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"Natrag"</string>
+    <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Na početni zaslon"</string>
     <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Pregled nedavnih aplikacija"</string>
     <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Gotovo"</string>
     <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Natrag"</string>
-    <string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"Da biste se vratili natrag, s tri prsta prijeđite ulijevo ili udesno bilo gdje na dodirnoj podlozi.\n\nZa to možete upotrijebiti i tipku za radnju tipkovnog prečaca + ESC."</string>
-    <string name="touchpad_back_gesture_success_title" msgid="7240576648330612171">"Sjajno!"</string>
+    <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"Prijeđite ulijevo ili udesno trima prstima na dodirnoj podlozi"</string>
+    <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"Odlično!"</string>
     <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"Izvršili ste pokret za povratak."</string>
     <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"Na početnu stranicu"</string>
-    <string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"Da biste u bilo kojem trenutku otvorili početni zaslon, trima prstima prijeđite prema gore od dna zaslona."</string>
-    <string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Odlično!"</string>
-    <string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Izvršili ste pokret za otvaranje početnog zaslona."</string>
+    <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"Prijeđite prema gore trima prstima na dodirnoj podlozi"</string>
+    <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"Sjajno!"</string>
+    <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"Izvršili ste pokret za otvaranje početnog zaslona"</string>
     <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"Pregled nedavnih aplikacija"</string>
-    <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"Prijeđite prema gore trima prstima na dodirnoj podlozi i zadržite pritisak."</string>
+    <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"Prijeđite prema gore trima prstima na dodirnoj podlozi i zadržite pritisak"</string>
     <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Sjajno!"</string>
     <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Izvršili ste pokret za prikaz nedavno korištenih aplikacija."</string>
-    <string name="tutorial_action_key_title" msgid="2659466586996495447">"Tipka za radnju"</string>
-    <string name="tutorial_action_key_guidance" msgid="5718948664616999196">"Da biste pristupili svojim aplikacijama, pritisnite tipku za radnje na tipkovnici."</string>
-    <string name="tutorial_action_key_success_title" msgid="466467860120112933">"Čestitamo!"</string>
-    <string name="tutorial_action_key_success_body" msgid="7201991081652850430">"Izvršili ste pokret tipke za radnju.\n\nRadnja + / prikazuje sve prečace koji su vam dostupni."</string>
+    <string name="tutorial_action_key_title" msgid="8172535792469008169">"Prikaži sve aplikacije"</string>
+    <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Pritisnite tipku za radnju na tipkovnici"</string>
+    <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Izvrsno!"</string>
+    <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Izvršili ste pokret za prikaz svih aplikacija"</string>
     <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Pozadinsko osvjetljenje tipkovnice"</string>
     <string name="keyboard_backlight_value" msgid="7336398765584393538">"Razina %1$d od %2$d"</string>
     <string name="home_controls_dream_label" msgid="6567105701292324257">"Upravljanje uređajima"</string>
@@ -1436,6 +1440,7 @@
     <string name="all_apps_edu_toast_content" msgid="8807496014667211562">"Za prikaz svojih svih aplikacija pritisnite tipku za radnju na tipkovnici"</string>
     <string name="redacted_notification_single_line_title" msgid="212019960919261670">"Redaktirano"</string>
     <string name="redacted_notification_single_line_text" msgid="8684166405005242945">"Otključajte za prikaz"</string>
+    <string name="contextual_education_dialog_title" msgid="4630392552837487324">"Kontekstualno obrazovanje"</string>
     <string name="back_edu_notification_title" msgid="5624780717751357278">"Upotrijebite dodirnu podlogu za povratak"</string>
     <string name="back_edu_notification_content" msgid="2497557451540954068">"Prijeđite ulijevo ili udesno trima prstima. Dodirnite da biste naučili više pokreta."</string>
     <string name="home_edu_notification_title" msgid="6097902076909654045">"Uz pomoć dodirne podloge vratite se na početni zaslon"</string>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index 6c26cd5..1248f41 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -440,7 +440,7 @@
     <string name="zen_mode_on" msgid="9085304934016242591">"Be"</string>
     <string name="zen_mode_on_with_details" msgid="7416143430557895497">"Be • <xliff:g id="TRIGGER_DESCRIPTION">%1$s</xliff:g>"</string>
     <string name="zen_mode_off" msgid="1736604456618147306">"Ki"</string>
-    <string name="zen_mode_set_up" msgid="7457957033034460064">"Beállítás"</string>
+    <string name="zen_mode_set_up" msgid="8231201163894922821">"Nincs beállítva"</string>
     <string name="zen_mode_no_manual_invocation" msgid="1769975741344633672">"A Beállítások között kezelheti"</string>
     <string name="zen_mode_active_modes" msgid="1625850411578488856">"{count,plural, =0{Nincs aktív mód}=1{A(z) {mode} aktív}other{# mód aktív}}"</string>
     <string name="zen_priority_introduction" msgid="3159291973383796646">"Az Ön által meghatározott ébresztéseken, emlékeztetőkön, eseményeken és hívókon kívül nem fogja Önt más hang vagy rezgés megzavarni. Továbbra is lesz hangjuk azoknak a tartalmaknak, amelyeket Ön elindít, például zenék, videók és játékok."</string>
@@ -573,8 +573,7 @@
     <string name="notification_section_header_conversations" msgid="821834744538345661">"Beszélgetések"</string>
     <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Az összes néma értesítés törlése"</string>
     <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Ne zavarjanak funkcióval szüneteltetett értesítések"</string>
-    <!-- no translation found for modes_suppressing_shade_text (6037581130837903239) -->
-    <skip />
+    <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{Nincs értesítés}=1{A(z) {mode} szüneteltette az értesítéseket}=2{A(z) {mode} és egy másik mód szüneteltette az értesítéseket}other{A(z) {mode} és # másik mód szüneteltette az értesítéseket}}"</string>
     <string name="media_projection_action_text" msgid="3634906766918186440">"Indítás most"</string>
     <string name="empty_shade_text" msgid="8935967157319717412">"Nincs értesítés"</string>
     <string name="no_unseen_notif_text" msgid="395512586119868682">"Nincsenek új értesítések"</string>
@@ -673,6 +672,10 @@
     <string name="stream_notification_unavailable" msgid="4313854556205836435">"Nem lehetséges, a csörgés le van némítva"</string>
     <string name="stream_alarm_unavailable" msgid="4059817189292197839">"Nem működik, mert be van kapcsolva a Ne zavarjanak"</string>
     <string name="stream_media_unavailable" msgid="6823020894438959853">"Nem működik, mert be van kapcsolva a Ne zavarjanak"</string>
+    <!-- no translation found for stream_unavailable_by_modes (3674139029490353683) -->
+    <skip />
+    <!-- no translation found for stream_unavailable_by_unknown (6908434629318171588) -->
+    <skip />
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Koppintson a némítás megszüntetéséhez."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Koppintson a rezgés beállításához. Előfordulhat, hogy a kisegítő lehetőségek szolgáltatásai le vannak némítva."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Koppintson a némításhoz. Előfordulhat, hogy a kisegítő lehetőségek szolgáltatásai le vannak némítva."</string>
@@ -706,6 +709,7 @@
     <string name="show_demo_mode" msgid="3677956462273059726">"Demó mód megjelenítése"</string>
     <string name="status_bar_ethernet" msgid="5690979758988647484">"Ethernet"</string>
     <string name="status_bar_alarm" msgid="87160847643623352">"Ébresztés"</string>
+    <string name="active_mode_content_description" msgid="1627555562186515927">"A(z) <xliff:g id="MODENAME">%1$s</xliff:g> aktív"</string>
     <string name="wallet_title" msgid="5369767670735827105">"Wallet"</string>
     <string name="wallet_empty_state_label" msgid="7776761245237530394">"Végezze el a beállítást a telefonjával való gyorsabb és biztonságosabb vásárláshoz"</string>
     <string name="wallet_app_button_label" msgid="7123784239111190992">"Összes mutatása"</string>
@@ -1405,26 +1409,26 @@
     <string name="launch_touchpad_tutorial_notification_content" msgid="7931085031240753226">"Érintőpad-kézmozdulatok megismerése"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_title" msgid="1940023776496198762">"Navigálás a billentyűzet és az érintőpad használatával"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Érintőpad-kézmozdulatok, billentyűparancsok és egyebek megismerése"</string>
-    <string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Vissza kézmozdulat"</string>
-    <string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Kezdőképernyő kézmozdulat"</string>
+    <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"Vissza"</string>
+    <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Ugrás a főoldalra"</string>
     <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Legutóbbi alkalmazások megtekintése"</string>
     <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Kész"</string>
     <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Vissza"</string>
-    <string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"A visszalépéshez csúsztasson három ujjal balra vagy a jobbra az érintőpadon.\n\nEnnek végrehajtásához használhatja az Action + Esc billentyűparancsot is."</string>
-    <string name="touchpad_back_gesture_success_title" msgid="7240576648330612171">"Kiváló!"</string>
+    <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"Csúsztassa gyorsan három ujját balra vagy jobbra az érintőpadon."</string>
+    <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"Remek!"</string>
     <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"Teljesítette a visszalépési kézmozdulatot."</string>
     <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"Ugrás a főoldalra"</string>
-    <string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"Ha bármikor vissza szeretne térni a kezdőképernyőre, csúsztassa gyorsan felfelé három ujját a képernyő aljáról."</string>
-    <string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Remek!"</string>
-    <string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Teljesítette a kezdőképernyőre lépés kézmozdulatát."</string>
+    <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"Csúsztasson gyorsan felfelé három ujjával az érintőpadon."</string>
+    <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"Kiváló!"</string>
+    <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"Teljesítette a kezdőképernyőre lépés kézmozdulatát."</string>
     <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"Legutóbbi alkalmazások megtekintése"</string>
-    <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"Csúsztasson felfelé három ujjal az érintőpadon, és tartsa lenyomva az ujjait."</string>
+    <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"Csúsztasson gyorsan felfelé három ujjal az érintőpadon, és tartsa rajta lenyomva az ujjait."</string>
     <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Kiváló!"</string>
     <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Teljesítette a legutóbbi alkalmazások megtekintésének kézmozdulatát."</string>
-    <string name="tutorial_action_key_title" msgid="2659466586996495447">"Műveletbillentyű"</string>
-    <string name="tutorial_action_key_guidance" msgid="5718948664616999196">"Az alkalmazásokhoz való hozzáféréshez nyomja meg a billentyűzet műveletbillentyűjét."</string>
-    <string name="tutorial_action_key_success_title" msgid="466467860120112933">"Gratulálunk!"</string>
-    <string name="tutorial_action_key_success_body" msgid="7201991081652850430">"Teljesítette a műveletbillentyű kézmozdulatát.\n\nA Művelet + / billentyűkombinációval megjelenítheti az összes használható billentyűparancsot."</string>
+    <string name="tutorial_action_key_title" msgid="8172535792469008169">"Összes alkalmazás megtekintése"</string>
+    <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Nyomja meg a műveletbillentyűt az érintőpadon."</string>
+    <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Szép munka!"</string>
+    <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Teljesítette az összes alkalmazás megtekintésének kézmozdulatát."</string>
     <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"A billentyűzet háttérvilágítása"</string>
     <string name="keyboard_backlight_value" msgid="7336398765584393538">"Fényerő: %2$d/%1$d"</string>
     <string name="home_controls_dream_label" msgid="6567105701292324257">"Otthon vezérlése"</string>
@@ -1436,6 +1440,7 @@
     <string name="all_apps_edu_toast_content" msgid="8807496014667211562">"Az összes alkalmazás megtekintéséhez nyomja meg a billentyűzet műveletbillentyűjét."</string>
     <string name="redacted_notification_single_line_title" msgid="212019960919261670">"Törölve"</string>
     <string name="redacted_notification_single_line_text" msgid="8684166405005242945">"Oldja fel a megtekintéshez"</string>
+    <string name="contextual_education_dialog_title" msgid="4630392552837487324">"Kontextusfüggő tájékoztató párbeszédpanel"</string>
     <string name="back_edu_notification_title" msgid="5624780717751357278">"A visszalépéshez használja az érintőpadot"</string>
     <string name="back_edu_notification_content" msgid="2497557451540954068">"Csúsztatasson gyorsan három ujjal balra vagy jobbra. Koppintson a további kézmozdulatokért."</string>
     <string name="home_edu_notification_title" msgid="6097902076909654045">"A kezdőképernyő megnyitásához használja az érintőpadot"</string>
diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml
index c0e7c30..db58b35 100644
--- a/packages/SystemUI/res/values-hy/strings.xml
+++ b/packages/SystemUI/res/values-hy/strings.xml
@@ -440,7 +440,8 @@
     <string name="zen_mode_on" msgid="9085304934016242591">"Միացված է"</string>
     <string name="zen_mode_on_with_details" msgid="7416143430557895497">"Միաց․ • <xliff:g id="TRIGGER_DESCRIPTION">%1$s</xliff:g>"</string>
     <string name="zen_mode_off" msgid="1736604456618147306">"Անջատված է"</string>
-    <string name="zen_mode_set_up" msgid="7457957033034460064">"Կարգավորել"</string>
+    <!-- no translation found for zen_mode_set_up (8231201163894922821) -->
+    <skip />
     <string name="zen_mode_no_manual_invocation" msgid="1769975741344633672">"Կառավարել կարգավորումներում"</string>
     <string name="zen_mode_active_modes" msgid="1625850411578488856">"{count,plural, =0{Ակտիվ ռեժիմներ չկան}=1{{mode} ռեժիմ ակտիվ է}one{# ռեժիմ ակտիվ է}other{# ռեժիմ ակտիվ է}}"</string>
     <string name="zen_priority_introduction" msgid="3159291973383796646">"Ձայները և թրթռոցները չեն անհանգստացնի ձեզ, բացի ձեր կողմից նշված զարթուցիչները, հիշեցումները, միջոցառումների ծանուցումները և զանգերը։ Դուք կլսեք ձեր ընտրածի նվագարկումը, այդ թվում՝ երաժշտություն, տեսանյութեր և խաղեր:"</string>
@@ -573,8 +574,7 @@
     <string name="notification_section_header_conversations" msgid="821834744538345661">"Զրույցներ"</string>
     <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Ջնջել բոլոր անձայն ծանուցումները"</string>
     <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Ծանուցումները չեն ցուցադրվի «Չանհանգստացնել» ռեժիմում"</string>
-    <!-- no translation found for modes_suppressing_shade_text (6037581130837903239) -->
-    <skip />
+    <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{Ծանուցումներ չկան}=1{Ծանուցումները դադարեցվել են «{mode}» ռեժիմի կողմից}=2{Ծանուցումները դադարեցվել են «{mode}» ու ևս մի ռեժիմի կողմից}one{Ծանուցումները դադարեցվել են «{mode}» ու ևս # ռեժիմի կողմից}other{Ծանուցումները դադարեցվել են «{mode}» ու ևս # ռեժիմի կողմից}}"</string>
     <string name="media_projection_action_text" msgid="3634906766918186440">"Սկսել հիմա"</string>
     <string name="empty_shade_text" msgid="8935967157319717412">"Ծանուցումներ չկան"</string>
     <string name="no_unseen_notif_text" msgid="395512586119868682">"Նոր ծանուցումներ չկան"</string>
@@ -673,6 +673,10 @@
     <string name="stream_notification_unavailable" msgid="4313854556205836435">"Հասանելի չէ, երբ զանգի ձայնն անջատված է"</string>
     <string name="stream_alarm_unavailable" msgid="4059817189292197839">"Հասանելի չէ․ «Չանհանգստացնել» ռեժիմը միացված է"</string>
     <string name="stream_media_unavailable" msgid="6823020894438959853">"Հասանելի չէ․ «Չանհանգստացնել» ռեժիմը միացված է"</string>
+    <!-- no translation found for stream_unavailable_by_modes (3674139029490353683) -->
+    <skip />
+    <!-- no translation found for stream_unavailable_by_unknown (6908434629318171588) -->
+    <skip />
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s: Հպեք՝ ձայնը միացնելու համար:"</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s: Հպեք՝ թրթռոցը միացնելու համար: Մատչելիության ծառայությունների ձայնը կարող է անջատվել:"</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s: Հպեք՝ ձայնն անջատելու համար: Մատչելիության ծառայությունների ձայնը կարող է անջատվել:"</string>
@@ -706,6 +710,7 @@
     <string name="show_demo_mode" msgid="3677956462273059726">"Ցուցադրական ռեժիմի ցուցադրում"</string>
     <string name="status_bar_ethernet" msgid="5690979758988647484">"Ethernet"</string>
     <string name="status_bar_alarm" msgid="87160847643623352">"Զարթուցիչ"</string>
+    <string name="active_mode_content_description" msgid="1627555562186515927">"«<xliff:g id="MODENAME">%1$s</xliff:g>» ռեժիմը միացված է"</string>
     <string name="wallet_title" msgid="5369767670735827105">"Wallet"</string>
     <string name="wallet_empty_state_label" msgid="7776761245237530394">"Վճարեք հեռախոսով՝ ավելի արագ և ապահով"</string>
     <string name="wallet_app_button_label" msgid="7123784239111190992">"Ցույց տալ բոլորը"</string>
@@ -1405,26 +1410,38 @@
     <string name="launch_touchpad_tutorial_notification_content" msgid="7931085031240753226">"Սովորեք օգտագործել հպահարթակի ժեստերը"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_title" msgid="1940023776496198762">"Կողմնորոշվեք ստեղնաշարի և հպահարթակի օգնությամբ"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Սովորեք օգտագործել հպահարթակի ժեստերը, ստեղնային դյուրանցումները և ավելին"</string>
-    <string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"«Հետ» ժեստ"</string>
-    <string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Հիմնական էկրան անցնելու ժեստ"</string>
+    <!-- no translation found for touchpad_tutorial_back_gesture_button (3104716365403620315) -->
+    <skip />
+    <!-- no translation found for touchpad_tutorial_home_gesture_button (8023973153559885624) -->
+    <skip />
     <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Դիտել վերջին հավելվածները"</string>
     <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Պատրաստ է"</string>
     <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Հետ գնալ"</string>
-    <string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"Հետ գնալու համար հպահարթակի վրա երեք մատով սահեցրեք ձախ կամ աջ։\n\nԻնչպես նաև կարող եք օգտագործել ստեղնային դյուրանցման գործողությունը + Esc։"</string>
-    <string name="touchpad_back_gesture_success_title" msgid="7240576648330612171">"Կեցցե՛ք"</string>
+    <!-- no translation found for touchpad_back_gesture_guidance (5352221087725906542) -->
+    <skip />
+    <!-- no translation found for touchpad_back_gesture_success_title (7370719098633023496) -->
+    <skip />
     <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"Դուք սովորեցիք հետ գնալու ժեստը։"</string>
     <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"Անցում հիմնական էկրան"</string>
-    <string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"Հիմնական էկրան վերադառնալու համար երեք մատը էկրանի ներքևից սահեցրեք վերև։"</string>
-    <string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Գերազանց է"</string>
-    <string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Դուք սովորեցիք հիմնական էկրան անցնելու ժեստը։"</string>
+    <!-- no translation found for touchpad_home_gesture_guidance (4178219118381915899) -->
+    <skip />
+    <!-- no translation found for touchpad_home_gesture_success_title (3648264553645798470) -->
+    <skip />
+    <!-- no translation found for touchpad_home_gesture_success_body (2590690589194027059) -->
+    <skip />
     <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"Դիտել վերջին հավելվածները"</string>
-    <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"Երեք մատը սահեցրեք վերև և սեղմած պահեք հպահարթակին։"</string>
+    <!-- no translation found for touchpad_recent_apps_gesture_guidance (6304446013842271822) -->
+    <skip />
     <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Կեցցե՛ք։"</string>
     <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Դուք կատարեցիք վերջին օգտագործված հավելվածների դիտման ժեստը։"</string>
-    <string name="tutorial_action_key_title" msgid="2659466586996495447">"Գործողության ստեղն"</string>
-    <string name="tutorial_action_key_guidance" msgid="5718948664616999196">"Բոլոր հավելվածներն օգտագործելու համար սեղմեք գործողության ստեղնը ստեղնաշարի վրա"</string>
-    <string name="tutorial_action_key_success_title" msgid="466467860120112933">"Շնորհավո՛ր"</string>
-    <string name="tutorial_action_key_success_body" msgid="7201991081652850430">"Դուք սովորեցիք գործողության ստեղնի ժեստը։\n\nԳործողություն + / ժեստը ցույց է տալիս ձեզ հասանելի բոլոր դյուրանցումները։"</string>
+    <!-- no translation found for tutorial_action_key_title (8172535792469008169) -->
+    <skip />
+    <!-- no translation found for tutorial_action_key_guidance (5040613427202799294) -->
+    <skip />
+    <!-- no translation found for tutorial_action_key_success_title (2371827347071979571) -->
+    <skip />
+    <!-- no translation found for tutorial_action_key_success_body (1688986269491357832) -->
+    <skip />
     <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Հետին լուսավորությամբ ստեղնաշար"</string>
     <string name="keyboard_backlight_value" msgid="7336398765584393538">"%1$d՝ %2$d-ից"</string>
     <string name="home_controls_dream_label" msgid="6567105701292324257">"Տան կառավարման տարրեր"</string>
@@ -1436,6 +1453,7 @@
     <string name="all_apps_edu_toast_content" msgid="8807496014667211562">"Բոլոր հավելվածները դիտելու համար սեղմեք գործողության ստեղնը ստեղնաշարի վրա"</string>
     <string name="redacted_notification_single_line_title" msgid="212019960919261670">"Կոդավորված"</string>
     <string name="redacted_notification_single_line_text" msgid="8684166405005242945">"Ապակողպել դիտելու համար"</string>
+    <string name="contextual_education_dialog_title" msgid="4630392552837487324">"Համատեքստային ուսուցում"</string>
     <string name="back_edu_notification_title" msgid="5624780717751357278">"Օգտագործեք ձեր հպահարթակը՝ վերադառնալու համար"</string>
     <string name="back_edu_notification_content" msgid="2497557451540954068">"Երեք մատը սահեցրեք ձախ կամ աջ։ Հպեք՝ ավելի շատ ժեստերի ծանոթանալու համար։"</string>
     <string name="home_edu_notification_title" msgid="6097902076909654045">"Օգտագործեք ձեր հպահարթակը՝ հիմնական էկրան անցնելու համար"</string>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index 906fde4..2c29275 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -98,7 +98,7 @@
     <string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"Batas kiri <xliff:g id="PERCENT">%1$d</xliff:g>%%"</string>
     <string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"Batas kanan <xliff:g id="PERCENT">%1$d</xliff:g>%%"</string>
     <string name="screenshot_work_profile_notification" msgid="203041724052970693">"Disimpan di <xliff:g id="APP">%1$s</xliff:g> di profil kerja"</string>
-    <string name="screenshot_private_profile_notification" msgid="1704440899154243171">"Disimpan di <xliff:g id="APP">%1$s</xliff:g> di profil pribadi"</string>
+    <string name="screenshot_private_profile_notification" msgid="1704440899154243171">"Disimpan di <xliff:g id="APP">%1$s</xliff:g> di profil privasi"</string>
     <string name="screenshot_default_files_app_name" msgid="8721579578575161912">"File"</string>
     <string name="screenshot_detected_template" msgid="7940376642921719915">"<xliff:g id="APPNAME">%1$s</xliff:g> mendeteksi screenshot ini."</string>
     <string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> dan aplikasi terbuka lainnya mendeteksi screenshot ini."</string>
@@ -440,7 +440,7 @@
     <string name="zen_mode_on" msgid="9085304934016242591">"Aktif"</string>
     <string name="zen_mode_on_with_details" msgid="7416143430557895497">"Aktif • <xliff:g id="TRIGGER_DESCRIPTION">%1$s</xliff:g>"</string>
     <string name="zen_mode_off" msgid="1736604456618147306">"Nonaktif"</string>
-    <string name="zen_mode_set_up" msgid="7457957033034460064">"Siapkan"</string>
+    <string name="zen_mode_set_up" msgid="8231201163894922821">"Tidak disetel"</string>
     <string name="zen_mode_no_manual_invocation" msgid="1769975741344633672">"Kelola di setelan"</string>
     <string name="zen_mode_active_modes" msgid="1625850411578488856">"{count,plural, =0{Tidak ada mode yang aktif}=1{{mode} aktif}other{# mode aktif}}"</string>
     <string name="zen_priority_introduction" msgid="3159291973383796646">"Anda tidak akan terganggu oleh suara dan getaran, kecuali dari alarm, pengingat, acara, dan penelepon yang Anda tentukan. Anda akan tetap mendengar apa pun yang telah dipilih untuk diputar, termasuk musik, video, dan game."</string>
@@ -573,8 +573,7 @@
     <string name="notification_section_header_conversations" msgid="821834744538345661">"Percakapan"</string>
     <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Hapus semua notifikasi senyap"</string>
     <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Notifikasi dijeda oleh mode Jangan Ganggu"</string>
-    <!-- no translation found for modes_suppressing_shade_text (6037581130837903239) -->
-    <skip />
+    <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{Tidak ada notifikasi}=1{Notifikasi dijeda oleh {mode}}=2{Notifikasi dijeda oleh {mode} dan satu mode lainnya}other{Notifikasi dijeda oleh {mode} dan # mode lainnya}}"</string>
     <string name="media_projection_action_text" msgid="3634906766918186440">"Mulai sekarang"</string>
     <string name="empty_shade_text" msgid="8935967157319717412">"Tidak ada notifikasi"</string>
     <string name="no_unseen_notif_text" msgid="395512586119868682">"Tidak ada notifikasi baru"</string>
@@ -673,6 +672,10 @@
     <string name="stream_notification_unavailable" msgid="4313854556205836435">"Tidak tersedia - Volume dering dibisukan"</string>
     <string name="stream_alarm_unavailable" msgid="4059817189292197839">"Tidak tersedia - Fitur Jangan Ganggu aktif"</string>
     <string name="stream_media_unavailable" msgid="6823020894438959853">"Tidak tersedia - Fitur Jangan Ganggu aktif"</string>
+    <!-- no translation found for stream_unavailable_by_modes (3674139029490353683) -->
+    <skip />
+    <!-- no translation found for stream_unavailable_by_unknown (6908434629318171588) -->
+    <skip />
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Ketuk untuk menyuarakan."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Ketuk untuk menyetel agar bergetar. Layanan aksesibilitas mungkin dibisukan."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Ketuk untuk membisukan. Layanan aksesibilitas mungkin dibisukan."</string>
@@ -706,6 +709,7 @@
     <string name="show_demo_mode" msgid="3677956462273059726">"Tampilkan mode demo"</string>
     <string name="status_bar_ethernet" msgid="5690979758988647484">"Ethernet"</string>
     <string name="status_bar_alarm" msgid="87160847643623352">"Alarm"</string>
+    <string name="active_mode_content_description" msgid="1627555562186515927">"<xliff:g id="MODENAME">%1$s</xliff:g> aktif"</string>
     <string name="wallet_title" msgid="5369767670735827105">"Wallet"</string>
     <string name="wallet_empty_state_label" msgid="7776761245237530394">"Siapkan metode pembayaran untuk melakukan pembelian dengan lebih cepat dan aman menggunakan ponsel Anda"</string>
     <string name="wallet_app_button_label" msgid="7123784239111190992">"Tampilkan semua"</string>
@@ -1405,26 +1409,26 @@
     <string name="launch_touchpad_tutorial_notification_content" msgid="7931085031240753226">"Pelajari gestur touchpad"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_title" msgid="1940023776496198762">"Menavigasi menggunakan keyboard dan touchpad"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Pelajari gestur touchpad, pintasan keyboard, dan lainnya"</string>
-    <string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Gestur kembali"</string>
-    <string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Gestur layar utama"</string>
+    <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"Kembali"</string>
+    <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Buka layar utama"</string>
     <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Lihat aplikasi terbaru"</string>
     <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Selesai"</string>
     <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Kembali"</string>
-    <string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"Untuk kembali, geser ke kiri atau kanan menggunakan tiga jari di touchpad.\n\nAnda juga dapat menggunakan pintasan keyboard Action + ECS untuk melakukannya."</string>
-    <string name="touchpad_back_gesture_success_title" msgid="7240576648330612171">"Bagus!"</string>
+    <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"Geser ke kiri atau kanan menggunakan tiga jari di touchpad"</string>
+    <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"Bagus!"</string>
     <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"Anda telah menyelesaikan gestur kembali."</string>
     <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"Buka layar utama"</string>
-    <string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"Untuk membuka layar utama kapan saja, geser ke atas menggunakan tiga jari dari bawah layar Anda."</string>
-    <string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Bagus!"</string>
-    <string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Anda telah menyelesaikan gestur buka layar utama."</string>
+    <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"Geser ke atas dengan tiga jari di touchpad"</string>
+    <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"Bagus!"</string>
+    <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"Anda telah menyelesaikan gestur buka layar utama"</string>
     <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"Lihat aplikasi terbaru"</string>
-    <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"Geser ke atas dan tahan menggunakan tiga jari di touchpad."</string>
+    <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"Geser ke atas dan tahan menggunakan tiga jari di touchpad"</string>
     <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Bagus!"</string>
     <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Anda telah menyelesaikan gestur untuk melihat aplikasi terbaru."</string>
-    <string name="tutorial_action_key_title" msgid="2659466586996495447">"Tombol tindakan"</string>
-    <string name="tutorial_action_key_guidance" msgid="5718948664616999196">"Untuk mengakses aplikasi, tekan tombol tindakan di keyboard."</string>
-    <string name="tutorial_action_key_success_title" msgid="466467860120112933">"Selamat!"</string>
-    <string name="tutorial_action_key_success_body" msgid="7201991081652850430">"Anda telah menyelesaikan gestur tombol tindakan.\n\nTindakan + / akan menampilkan semua pintasan yang Anda miliki."</string>
+    <string name="tutorial_action_key_title" msgid="8172535792469008169">"Lihat semua aplikasi"</string>
+    <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Tekan tombol tindakan di keyboard"</string>
+    <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Bagus!"</string>
+    <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Anda telah menyelesaikan gestur untuk melihat semua aplikasi"</string>
     <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Lampu latar keyboard"</string>
     <string name="keyboard_backlight_value" msgid="7336398765584393538">"Tingkat %1$d dari %2$d"</string>
     <string name="home_controls_dream_label" msgid="6567105701292324257">"Kontrol Rumah"</string>
@@ -1436,6 +1440,7 @@
     <string name="all_apps_edu_toast_content" msgid="8807496014667211562">"Untuk melihat semua aplikasi, tekan tombol tindakan di keyboard"</string>
     <string name="redacted_notification_single_line_title" msgid="212019960919261670">"Disamarkan"</string>
     <string name="redacted_notification_single_line_text" msgid="8684166405005242945">"Buka kunci untuk melihat"</string>
+    <string name="contextual_education_dialog_title" msgid="4630392552837487324">"Pendidikan kontekstual"</string>
     <string name="back_edu_notification_title" msgid="5624780717751357278">"Gunakan touchpad untuk kembali"</string>
     <string name="back_edu_notification_content" msgid="2497557451540954068">"Geser ke kiri atau kanan menggunakan tiga jari. Ketuk untuk mempelajari gestur lainnya."</string>
     <string name="home_edu_notification_title" msgid="6097902076909654045">"Gunakan touchpad untuk membuka layar utama"</string>
diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml
index 68f2c23..1897ba4 100644
--- a/packages/SystemUI/res/values-is/strings.xml
+++ b/packages/SystemUI/res/values-is/strings.xml
@@ -440,7 +440,7 @@
     <string name="zen_mode_on" msgid="9085304934016242591">"Kveikt"</string>
     <string name="zen_mode_on_with_details" msgid="7416143430557895497">"Kveikt • <xliff:g id="TRIGGER_DESCRIPTION">%1$s</xliff:g>"</string>
     <string name="zen_mode_off" msgid="1736604456618147306">"Slökkt"</string>
-    <string name="zen_mode_set_up" msgid="7457957033034460064">"Setja upp"</string>
+    <string name="zen_mode_set_up" msgid="8231201163894922821">"Ekki stillt"</string>
     <string name="zen_mode_no_manual_invocation" msgid="1769975741344633672">"Stjórna í stillingum"</string>
     <string name="zen_mode_active_modes" msgid="1625850411578488856">"{count,plural, =0{Engar virkar stillingar}=1{{mode} er virk}one{# stilling er virk}other{# stillingar eru virkar}}"</string>
     <string name="zen_priority_introduction" msgid="3159291973383796646">"Þú verður ekki fyrir truflunum frá hljóðmerkjum og titringi, fyrir utan vekjara, áminningar, viðburði og símtöl frá þeim sem þú leyfir fyrirfram. Þú heyrir áfram í öllu sem þú velur að spila, svo sem tónlist, myndskeiðum og leikjum."</string>
@@ -573,8 +573,7 @@
     <string name="notification_section_header_conversations" msgid="821834744538345661">"Samtöl"</string>
     <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Hreinsa allar þöglar tilkynningar"</string>
     <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Hlé gert á tilkynningum þar sem stillt er á „Ónáðið ekki“"</string>
-    <!-- no translation found for modes_suppressing_shade_text (6037581130837903239) -->
-    <skip />
+    <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{Engar tilkynningar}=1{Hlé gert á tilkynningum þar sem stillt er á {mode}}=2{Hlé gert á tilkynningum þar sem stillt er á {mode} og eina aðra stillingu}one{Hlé gert á tilkynningum þar sem stillt er á {mode} og # aðra stillingu}other{Hlé gert á tilkynningum þar sem stillt er á {mode} og # aðrar stillingar}}"</string>
     <string name="media_projection_action_text" msgid="3634906766918186440">"Byrja núna"</string>
     <string name="empty_shade_text" msgid="8935967157319717412">"Engar tilkynningar"</string>
     <string name="no_unseen_notif_text" msgid="395512586119868682">"Engar nýjar tilkynningar"</string>
@@ -673,6 +672,10 @@
     <string name="stream_notification_unavailable" msgid="4313854556205836435">"Ekki í boði þar sem hringing er þögguð"</string>
     <string name="stream_alarm_unavailable" msgid="4059817189292197839">"Ekki í boði því að kveikt er á „Ónáðið ekki“"</string>
     <string name="stream_media_unavailable" msgid="6823020894438959853">"Ekki í boði því að kveikt er á „Ónáðið ekki“"</string>
+    <!-- no translation found for stream_unavailable_by_modes (3674139029490353683) -->
+    <skip />
+    <!-- no translation found for stream_unavailable_by_unknown (6908434629318171588) -->
+    <skip />
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Ýttu til að hætta að þagga."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Ýttu til að stilla á titring. Hugsanlega verður slökkt á hljóði aðgengisþjónustu."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Ýttu til að þagga. Hugsanlega verður slökkt á hljóði aðgengisþjónustu."</string>
@@ -706,6 +709,7 @@
     <string name="show_demo_mode" msgid="3677956462273059726">"Sýna prufustillingu"</string>
     <string name="status_bar_ethernet" msgid="5690979758988647484">"Ethernet"</string>
     <string name="status_bar_alarm" msgid="87160847643623352">"Vekjari"</string>
+    <string name="active_mode_content_description" msgid="1627555562186515927">"Kveikt er á „<xliff:g id="MODENAME">%1$s</xliff:g>“"</string>
     <string name="wallet_title" msgid="5369767670735827105">"Veski"</string>
     <string name="wallet_empty_state_label" msgid="7776761245237530394">"Stilltu hlutina þannig að þú getir verslað með símanum á hraðari og öruggari hátt"</string>
     <string name="wallet_app_button_label" msgid="7123784239111190992">"Sýna allt"</string>
@@ -1405,26 +1409,26 @@
     <string name="launch_touchpad_tutorial_notification_content" msgid="7931085031240753226">"Nánar um bendingar á snertifleti"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_title" msgid="1940023776496198762">"Flettu með því að nota lyklaborðið og snertiflötinn"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Kynntu þér bendingar á snertifleti, flýtilykla og fleira"</string>
-    <string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Bending til að fara til baka"</string>
-    <string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Bending til að fara á upphafsskjá"</string>
+    <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"Til baka"</string>
+    <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Fara á heimaskjá"</string>
     <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Sjá nýleg forrit"</string>
     <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Lokið"</string>
     <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Til baka"</string>
-    <string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"Strjúktu til vinstri eða hægri með þremur fingrum hvar sem er á snertifletinum til að fara til baka.\n\nÞú getur einnig notað flýtileiðaraðgerðina + ESC til að gera þetta."</string>
-    <string name="touchpad_back_gesture_success_title" msgid="7240576648330612171">"Vel gert!"</string>
+    <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"Strjúktu til hægri eða vinstri á snertifletinum með þremur fingrum"</string>
+    <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"Flott!"</string>
     <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"Þú laukst við að kynna þér bendinguna „til baka“."</string>
     <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"Heim"</string>
-    <string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"Strjúktu upp frá neðri brún skjásins með þremur fingrum til að opna heimaskjáinn."</string>
-    <string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Flott!"</string>
-    <string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Þú laukst við að kynna þér bendinguna „heim“."</string>
+    <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"Strjúktu upp á snertifletinum með þremur fingrum"</string>
+    <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"Vel gert!"</string>
+    <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"Þú framkvæmdir bendinguna „Fara á heimaskjá“"</string>
     <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"Sjá nýleg forrit"</string>
-    <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"Strjúktu upp og haltu þremur fingrum inni á snertifletinum."</string>
+    <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"Strjúktu upp og haltu þremur fingrum inni á snertifletinum."</string>
     <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Vel gert!"</string>
     <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Þú framkvæmdir bendinguna til að sjá nýleg forrit."</string>
-    <string name="tutorial_action_key_title" msgid="2659466586996495447">"Aðgerðalykill"</string>
-    <string name="tutorial_action_key_guidance" msgid="5718948664616999196">"Ýttu á aðgerðalykilinn á lyklaborðinu til að opna forritin þín."</string>
-    <string name="tutorial_action_key_success_title" msgid="466467860120112933">"Til hamingju!"</string>
-    <string name="tutorial_action_key_success_body" msgid="7201991081652850430">"Þú laukst við að kynna þér bendinguna „aðgerðalykill“.\n\nAðgerðalykill + / sýnir þér alla flýtilykla sem eru í boði."</string>
+    <string name="tutorial_action_key_title" msgid="8172535792469008169">"Sjá öll forrit"</string>
+    <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Ýttu á aðgerðalykilinn á lyklaborðinu"</string>
+    <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Vel gert!"</string>
+    <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Þú framkvæmdir bendinguna „Sjá öll forrit“"</string>
     <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Baklýsing lyklaborðs"</string>
     <string name="keyboard_backlight_value" msgid="7336398765584393538">"Stig %1$d af %2$d"</string>
     <string name="home_controls_dream_label" msgid="6567105701292324257">"Heimastýringar"</string>
@@ -1436,6 +1440,7 @@
     <string name="all_apps_edu_toast_content" msgid="8807496014667211562">"Ýttu á aðgerðalykilinn á lyklaborðinu til að sjá öll forritin þín"</string>
     <string name="redacted_notification_single_line_title" msgid="212019960919261670">"Ritskoðað"</string>
     <string name="redacted_notification_single_line_text" msgid="8684166405005242945">"Taktu úr lás til að skoða"</string>
+    <string name="contextual_education_dialog_title" msgid="4630392552837487324">"Samhengismiðuð menntun"</string>
     <string name="back_edu_notification_title" msgid="5624780717751357278">"Notaðu snertiflötinn til að fara til baka"</string>
     <string name="back_edu_notification_content" msgid="2497557451540954068">"Strjúktu til vinstri eða hægri með þremur fingrum. Ýttu til að læra fleiri bendingar."</string>
     <string name="home_edu_notification_title" msgid="6097902076909654045">"Notaðu snertiflötinn til að fara á heimaskjá"</string>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index 4f8015c..2931b96 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -440,7 +440,8 @@
     <string name="zen_mode_on" msgid="9085304934016242591">"On"</string>
     <string name="zen_mode_on_with_details" msgid="7416143430557895497">"On • <xliff:g id="TRIGGER_DESCRIPTION">%1$s</xliff:g>"</string>
     <string name="zen_mode_off" msgid="1736604456618147306">"Off"</string>
-    <string name="zen_mode_set_up" msgid="7457957033034460064">"Configura"</string>
+    <!-- no translation found for zen_mode_set_up (8231201163894922821) -->
+    <skip />
     <string name="zen_mode_no_manual_invocation" msgid="1769975741344633672">"Gestisci nelle impostazioni"</string>
     <string name="zen_mode_active_modes" msgid="1625850411578488856">"{count,plural, =0{Nessuna modalità attiva}=1{{mode} è attiva}many{# di modalità sono attive}other{# modalità sono attive}}"</string>
     <string name="zen_priority_introduction" msgid="3159291973383796646">"Suoni e vibrazioni non ti disturberanno, ad eccezione di sveglie, promemoria, eventi, chiamate da contatti da te specificati ed elementi che hai scelto di continuare a riprodurre, inclusi video, musica e giochi."</string>
@@ -573,8 +574,7 @@
     <string name="notification_section_header_conversations" msgid="821834744538345661">"Conversazioni"</string>
     <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Cancella tutte le notifiche silenziose"</string>
     <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Notifiche messe in pausa in base alla modalità Non disturbare"</string>
-    <!-- no translation found for modes_suppressing_shade_text (6037581130837903239) -->
-    <skip />
+    <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{Nessuna notifica}=1{Notifica messa in pausa da {mode}}=2{Notifiche messe in pausa da {mode} e un\'altra modalità}many{Notifiche messe in pausa da {mode} e # di modalità}other{Notifiche messe in pausa da {mode} e altre # modalità}}"</string>
     <string name="media_projection_action_text" msgid="3634906766918186440">"Avvia adesso"</string>
     <string name="empty_shade_text" msgid="8935967157319717412">"Nessuna notifica"</string>
     <string name="no_unseen_notif_text" msgid="395512586119868682">"Nessuna nuova notifica"</string>
@@ -673,6 +673,10 @@
     <string name="stream_notification_unavailable" msgid="4313854556205836435">"Non disponibile con l\'audio disattivato"</string>
     <string name="stream_alarm_unavailable" msgid="4059817189292197839">"Non disponibile: modalità Non disturbare attiva"</string>
     <string name="stream_media_unavailable" msgid="6823020894438959853">"Non disponibili con \"Non disturbare\" attiva"</string>
+    <!-- no translation found for stream_unavailable_by_modes (3674139029490353683) -->
+    <skip />
+    <!-- no translation found for stream_unavailable_by_unknown (6908434629318171588) -->
+    <skip />
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Tocca per riattivare l\'audio."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Tocca per attivare la vibrazione. L\'audio dei servizi di accessibilità può essere disattivato."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Tocca per disattivare l\'audio. L\'audio dei servizi di accessibilità può essere disattivato."</string>
@@ -706,6 +710,7 @@
     <string name="show_demo_mode" msgid="3677956462273059726">"Mostra modalità demo"</string>
     <string name="status_bar_ethernet" msgid="5690979758988647484">"Ethernet"</string>
     <string name="status_bar_alarm" msgid="87160847643623352">"Sveglia"</string>
+    <string name="active_mode_content_description" msgid="1627555562186515927">"Programmazione <xliff:g id="MODENAME">%1$s</xliff:g> attiva"</string>
     <string name="wallet_title" msgid="5369767670735827105">"Wallet"</string>
     <string name="wallet_empty_state_label" msgid="7776761245237530394">"Imposta un metodo di pagamento per effettuare acquisti in modo più rapido e sicuro con il telefono"</string>
     <string name="wallet_app_button_label" msgid="7123784239111190992">"Mostra tutto"</string>
@@ -1405,26 +1410,38 @@
     <string name="launch_touchpad_tutorial_notification_content" msgid="7931085031240753226">"Impara i gesti con il touchpad"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_title" msgid="1940023776496198762">"Naviga usando la tastiera e il touchpad"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Scopri gesti con il touchpad, scorciatoie da tastiera e altro ancora"</string>
-    <string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Gesto Indietro"</string>
-    <string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Gesto Home"</string>
+    <!-- no translation found for touchpad_tutorial_back_gesture_button (3104716365403620315) -->
+    <skip />
+    <!-- no translation found for touchpad_tutorial_home_gesture_button (8023973153559885624) -->
+    <skip />
     <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Visualizza app recenti"</string>
     <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Fine"</string>
     <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Indietro"</string>
-    <string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"Per tornare indietro, scorri verso sinistra o verso destra utilizzando tre dita in un punto qualsiasi del touchpad.\n\nPuoi usare anche la scorciatoia da tastiera Action + Esc per farlo."</string>
-    <string name="touchpad_back_gesture_success_title" msgid="7240576648330612171">"Ottimo lavoro."</string>
+    <!-- no translation found for touchpad_back_gesture_guidance (5352221087725906542) -->
+    <skip />
+    <!-- no translation found for touchpad_back_gesture_success_title (7370719098633023496) -->
+    <skip />
     <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"Hai completato il gesto Indietro."</string>
     <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"Vai alla schermata Home"</string>
-    <string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"Per andare alla schermata Home, scorri verso l\'alto con tre dita dalla parte inferiore dello schermo."</string>
-    <string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Bene!"</string>
-    <string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Hai completato il gesto Vai alla schermata Home."</string>
+    <!-- no translation found for touchpad_home_gesture_guidance (4178219118381915899) -->
+    <skip />
+    <!-- no translation found for touchpad_home_gesture_success_title (3648264553645798470) -->
+    <skip />
+    <!-- no translation found for touchpad_home_gesture_success_body (2590690589194027059) -->
+    <skip />
     <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"Visualizza app recenti"</string>
-    <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"Scorri verso l\'alto e tieni premuto con tre dita sul touchpad."</string>
+    <!-- no translation found for touchpad_recent_apps_gesture_guidance (6304446013842271822) -->
+    <skip />
     <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Ottimo lavoro."</string>
     <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Hai completato il gesto Visualizza app recenti."</string>
-    <string name="tutorial_action_key_title" msgid="2659466586996495447">"Tasto azione"</string>
-    <string name="tutorial_action_key_guidance" msgid="5718948664616999196">"Per accedere alle tue app, premi il tasto azione sulla tastiera."</string>
-    <string name="tutorial_action_key_success_title" msgid="466467860120112933">"Complimenti!"</string>
-    <string name="tutorial_action_key_success_body" msgid="7201991081652850430">"Hai completato il gesto del tasto azione.\n\nAzione + / mostra tutte le scorciatoie disponibili."</string>
+    <!-- no translation found for tutorial_action_key_title (8172535792469008169) -->
+    <skip />
+    <!-- no translation found for tutorial_action_key_guidance (5040613427202799294) -->
+    <skip />
+    <!-- no translation found for tutorial_action_key_success_title (2371827347071979571) -->
+    <skip />
+    <!-- no translation found for tutorial_action_key_success_body (1688986269491357832) -->
+    <skip />
     <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Retroilluminazione della tastiera"</string>
     <string name="keyboard_backlight_value" msgid="7336398765584393538">"Livello %1$d di %2$d"</string>
     <string name="home_controls_dream_label" msgid="6567105701292324257">"Controlli della casa"</string>
@@ -1436,6 +1453,7 @@
     <string name="all_apps_edu_toast_content" msgid="8807496014667211562">"Per visualizzare tutte le tue app, premi il tasto azione sulla tastiera"</string>
     <string name="redacted_notification_single_line_title" msgid="212019960919261670">"Oscurata"</string>
     <string name="redacted_notification_single_line_text" msgid="8684166405005242945">"Sblocca per visualizzare"</string>
+    <string name="contextual_education_dialog_title" msgid="4630392552837487324">"Istruzione contestuale"</string>
     <string name="back_edu_notification_title" msgid="5624780717751357278">"Usa il touchpad per tornare indietro"</string>
     <string name="back_edu_notification_content" msgid="2497557451540954068">"Scorri verso sinistra o destra con tre dita. Tocca per scoprire altri gesti."</string>
     <string name="home_edu_notification_title" msgid="6097902076909654045">"Usa il touchpad per andare alla schermata Home"</string>
@@ -1445,7 +1463,7 @@
     <string name="all_apps_edu_notification_title" msgid="372262997265569063">"Usa la tastiera per visualizzare tutte le app"</string>
     <string name="all_apps_edu_notification_content" msgid="3255070575694025585">"Premi il tasto azione in qualsiasi momento. Tocca per scoprire altri gesti."</string>
     <string name="accessibility_deprecate_extra_dim_dialog_title" msgid="910988771011857460">"Ora l\'attenuazione extra è nel cursore della luminosità"</string>
-    <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="4453123359258743230">"Ora puoi usare l\'attenuazione extra per lo schermo abbassando il livello di luminosità ancora di più.\n\nDato che questa funzionalità ora fa parte del cursore della luminosità, le scorciatoie per l\'attenuazione extra vengono rimosse."</string>
+    <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="4453123359258743230">"Ora puoi usare l\'attenuazione extra per lo schermo abbassando ulteriormente il livello di luminosità.\n\nDato che questa funzionalità è ora integrata nel cursore della luminosità, le scorciatoie per l\'attenuazione extra vengono rimosse."</string>
     <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="3947537827396916005">"Rimuovi scorciatoie attenuazione extra"</string>
     <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="165474092660941104">"Scorciatoie attenuazione extra rimosse"</string>
     <string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"Connettività"</string>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index 3d7a25c..72fc195 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -440,7 +440,7 @@
     <string name="zen_mode_on" msgid="9085304934016242591">"מצב מופעל"</string>
     <string name="zen_mode_on_with_details" msgid="7416143430557895497">"פועל • <xliff:g id="TRIGGER_DESCRIPTION">%1$s</xliff:g>"</string>
     <string name="zen_mode_off" msgid="1736604456618147306">"מצב מושבת"</string>
-    <string name="zen_mode_set_up" msgid="7457957033034460064">"להגדרה"</string>
+    <string name="zen_mode_set_up" msgid="8231201163894922821">"לא הוגדר"</string>
     <string name="zen_mode_no_manual_invocation" msgid="1769975741344633672">"שינוי ב\'הגדרות\'"</string>
     <string name="zen_mode_active_modes" msgid="1625850411578488856">"{count,plural, =0{אין מצבים פעילים}=1{מצב פעיל אחד ({mode})}one{‫# מצבים פעילים}two{‫# מצבים פעילים}other{‫# מצבים פעילים}}"</string>
     <string name="zen_priority_introduction" msgid="3159291973383796646">"כדי לא להפריע לך, המכשיר לא ירטוט ולא ישמיע שום צליל, חוץ מהתראות, תזכורות, אירועים ושיחות ממתקשרים מסוימים לבחירתך. המצב הזה לא ישפיע על צלילים שהם חלק מתוכן שבחרת להפעיל, כמו מוזיקה, סרטונים ומשחקים."</string>
@@ -573,8 +573,7 @@
     <string name="notification_section_header_conversations" msgid="821834744538345661">"שיחות"</string>
     <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"ניקוי כל ההתראות השקטות"</string>
     <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"התראות הושהו על ידי מצב \'נא לא להפריע\'"</string>
-    <!-- no translation found for modes_suppressing_shade_text (6037581130837903239) -->
-    <skip />
+    <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{אין התראות}=1{ההתראות הושהו על ידי {mode}}=2{ההתראות הושהו על ידי {mode} ועל ידי מצב אחד נוסף}one{ההתראות הושהו על ידי {mode} ועל ידי # מצבים נוספים}other{ההתראות הושהו על ידי {mode} ועל ידי # מצבים נוספים}}"</string>
     <string name="media_projection_action_text" msgid="3634906766918186440">"כן, אפשר להתחיל"</string>
     <string name="empty_shade_text" msgid="8935967157319717412">"אין התראות"</string>
     <string name="no_unseen_notif_text" msgid="395512586119868682">"אין התראות חדשות"</string>
@@ -673,6 +672,10 @@
     <string name="stream_notification_unavailable" msgid="4313854556205836435">"לא זמין כי הצלצול מושתק"</string>
     <string name="stream_alarm_unavailable" msgid="4059817189292197839">"לא זמין כי התכונה \'נא לא להפריע\' מופעלת"</string>
     <string name="stream_media_unavailable" msgid="6823020894438959853">"לא זמין כי התכונה \'נא לא להפריע\' מופעלת"</string>
+    <!-- no translation found for stream_unavailable_by_modes (3674139029490353683) -->
+    <skip />
+    <!-- no translation found for stream_unavailable_by_unknown (6908434629318171588) -->
+    <skip />
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"‏%1$s. יש להקיש כדי לבטל את ההשתקה."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"‏%1$s. צריך להקיש כדי להגדיר רטט. ייתכן ששירותי הנגישות מושתקים."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"‏%1$s. יש להקיש כדי להשתיק. ייתכן ששירותי הנגישות יושתקו."</string>
@@ -706,6 +709,7 @@
     <string name="show_demo_mode" msgid="3677956462273059726">"הצגת מצב הדגמה"</string>
     <string name="status_bar_ethernet" msgid="5690979758988647484">"אתרנט"</string>
     <string name="status_bar_alarm" msgid="87160847643623352">"התראה"</string>
+    <string name="active_mode_content_description" msgid="1627555562186515927">"מצב <xliff:g id="MODENAME">%1$s</xliff:g> פועל"</string>
     <string name="wallet_title" msgid="5369767670735827105">"Wallet"</string>
     <string name="wallet_empty_state_label" msgid="7776761245237530394">"מגדירים אמצעי תשלום ונהנים מביצוע מהיר ומאובטח יותר של רכישות באמצעות הטלפון"</string>
     <string name="wallet_app_button_label" msgid="7123784239111190992">"הצגת הכול"</string>
@@ -1405,26 +1409,26 @@
     <string name="launch_touchpad_tutorial_notification_content" msgid="7931085031240753226">"מידע על התנועות בלוח המגע"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_title" msgid="1940023776496198762">"ניווט באמצעות המקלדת ולוח המגע"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"מידע על התנועות בלוח המגע, מקשי קיצור ועוד"</string>
-    <string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"תנועת חזרה"</string>
-    <string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"תנועת חזרה למסך הבית"</string>
+    <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"חזרה"</string>
+    <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"חזרה לדף הבית"</string>
     <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"הצגת האפליקציות האחרונות"</string>
     <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"סיום"</string>
     <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"חזרה"</string>
-    <string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"‏כדי לחזור אחורה, מחליקים שמאלה או ימינה עם שלוש אצבעות בכל מקום על לוח המגע.\n\nאפשר לבצע את הפעולה הזו גם באמצעות קיצור הדרך לפעולה + מקש ESC."</string>
-    <string name="touchpad_back_gesture_success_title" msgid="7240576648330612171">"מעולה!"</string>
+    <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"מחליקים שמאלה או ימינה עם שלוש אצבעות על לוח המגע"</string>
+    <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"איזה יופי!"</string>
     <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"השלמת את התנועה \'הקודם\'."</string>
-    <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"מעבר לדף הבית"</string>
-    <string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"כדי לעבור למסך הבית בכל שלב, צריך להחליק למעלה עם שלוש אצבעות מהחלק התחתון של המסך."</string>
-    <string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"איזה יופי!"</string>
-    <string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"השלמת את תנועת המעבר למסך הבית."</string>
+    <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"מעבר למסך הבית"</string>
+    <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"מחליקים כלפי מעלה עם שלוש אצבעות על לוח המגע"</string>
+    <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"מעולה!"</string>
+    <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"השלמת את תנועת החזרה למסך הבית"</string>
     <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"הצגת האפליקציות האחרונות"</string>
-    <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"מחליקים למעלה ולוחצים לחיצה ארוכה עם שלוש אצבעות על לוח המגע."</string>
+    <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"מחליקים למעלה ולוחצים לחיצה ארוכה עם שלוש אצבעות על לוח המגע"</string>
     <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"מעולה!"</string>
     <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"השלמת את התנועה להצגת האפליקציות האחרונות."</string>
-    <string name="tutorial_action_key_title" msgid="2659466586996495447">"מקש הפעולה"</string>
-    <string name="tutorial_action_key_guidance" msgid="5718948664616999196">"כדי לגשת לאפליקציות, מקישים על מקש הפעולה במקלדת."</string>
-    <string name="tutorial_action_key_success_title" msgid="466467860120112933">"כל הכבוד!"</string>
-    <string name="tutorial_action_key_success_body" msgid="7201991081652850430">"השלמת את התנועה של מקש הפעולה.\n\nלחיצה על מקש הפעולה + מקש / מציגה את כל מקשי הקיצור הזמינים."</string>
+    <string name="tutorial_action_key_title" msgid="8172535792469008169">"הצגת כל האפליקציות"</string>
+    <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"צריך להקיש על מקש הפעולה במקלדת"</string>
+    <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"כל הכבוד!"</string>
+    <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"השלמת את התנועה להצגת כל האפליקציות"</string>
     <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"התאורה האחורית במקלדת"</string>
     <string name="keyboard_backlight_value" msgid="7336398765584393538">"‏רמה %1$d מתוך %2$d"</string>
     <string name="home_controls_dream_label" msgid="6567105701292324257">"שליטה במכשירים"</string>
@@ -1436,6 +1440,7 @@
     <string name="all_apps_edu_toast_content" msgid="8807496014667211562">"כדי לראות את כל האפליקציות, מקישים על מקש הפעולה במקלדת"</string>
     <string name="redacted_notification_single_line_title" msgid="212019960919261670">"מצונזר"</string>
     <string name="redacted_notification_single_line_text" msgid="8684166405005242945">"צריך לבטל את הנעילה כדי לראות"</string>
+    <string name="contextual_education_dialog_title" msgid="4630392552837487324">"חינוך בהתאם להקשר"</string>
     <string name="back_edu_notification_title" msgid="5624780717751357278">"איך להשתמש בלוח המגע כדי לחזור אחורה"</string>
     <string name="back_edu_notification_content" msgid="2497557451540954068">"מחליקים ימינה או שמאלה עם שלוש אצבעות. ניתן להקיש כדי לקבל מידע נוסף על התנועות."</string>
     <string name="home_edu_notification_title" msgid="6097902076909654045">"איך להשתמש בלוח המגע כדי לעבור למסך הבית"</string>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index 3e29ed6..dcbfc8c 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -440,7 +440,7 @@
     <string name="zen_mode_on" msgid="9085304934016242591">"ON"</string>
     <string name="zen_mode_on_with_details" msgid="7416143430557895497">"ON • <xliff:g id="TRIGGER_DESCRIPTION">%1$s</xliff:g>"</string>
     <string name="zen_mode_off" msgid="1736604456618147306">"OFF"</string>
-    <string name="zen_mode_set_up" msgid="7457957033034460064">"設定"</string>
+    <string name="zen_mode_set_up" msgid="8231201163894922821">"未設定"</string>
     <string name="zen_mode_no_manual_invocation" msgid="1769975741344633672">"設定で管理"</string>
     <string name="zen_mode_active_modes" msgid="1625850411578488856">"{count,plural, =0{アクティブなモードはありません}=1{{mode} がアクティブです}other{# 個のモードがアクティブです}}"</string>
     <string name="zen_priority_introduction" msgid="3159291973383796646">"アラーム、リマインダー、予定、指定した人からの着信以外の音やバイブレーションに煩わされることはありません。音楽、動画、ゲームなど再生対象として選択したコンテンツは引き続き再生されます。"</string>
@@ -573,8 +573,7 @@
     <string name="notification_section_header_conversations" msgid="821834744538345661">"会話"</string>
     <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"サイレント通知がすべて消去されます"</string>
     <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"サイレント モードにより通知は一時停止中です"</string>
-    <!-- no translation found for modes_suppressing_shade_text (6037581130837903239) -->
-    <skip />
+    <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{通知なし}=1{{mode} により通知は一時停止中です}=2{{mode} と他 1 個のモードにより通知は一時停止中です}other{{mode} と他 # 個のモードにより通知は一時停止中です}}"</string>
     <string name="media_projection_action_text" msgid="3634906766918186440">"今すぐ開始"</string>
     <string name="empty_shade_text" msgid="8935967157319717412">"通知はありません"</string>
     <string name="no_unseen_notif_text" msgid="395512586119868682">"新しい通知はありません"</string>
@@ -673,6 +672,10 @@
     <string name="stream_notification_unavailable" msgid="4313854556205836435">"着信音がミュートされているため利用できません"</string>
     <string name="stream_alarm_unavailable" msgid="4059817189292197839">"サイレント モードが ON のため利用できません"</string>
     <string name="stream_media_unavailable" msgid="6823020894438959853">"サイレント モードが ON のため利用できません"</string>
+    <!-- no translation found for stream_unavailable_by_modes (3674139029490353683) -->
+    <skip />
+    <!-- no translation found for stream_unavailable_by_unknown (6908434629318171588) -->
+    <skip />
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s。タップしてミュートを解除します。"</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s。タップしてバイブレーションに設定します。ユーザー補助機能サービスがミュートされる場合があります。"</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s。タップしてミュートします。ユーザー補助機能サービスがミュートされる場合があります。"</string>
@@ -706,6 +709,7 @@
     <string name="show_demo_mode" msgid="3677956462273059726">"デモモードを表示"</string>
     <string name="status_bar_ethernet" msgid="5690979758988647484">"イーサネット"</string>
     <string name="status_bar_alarm" msgid="87160847643623352">"アラーム"</string>
+    <string name="active_mode_content_description" msgid="1627555562186515927">"<xliff:g id="MODENAME">%1$s</xliff:g>: ON"</string>
     <string name="wallet_title" msgid="5369767670735827105">"ウォレット"</string>
     <string name="wallet_empty_state_label" msgid="7776761245237530394">"スマートフォンを使ってよりすばやく安全に購入できるように設定しましょう"</string>
     <string name="wallet_app_button_label" msgid="7123784239111190992">"すべて表示"</string>
@@ -1405,26 +1409,26 @@
     <string name="launch_touchpad_tutorial_notification_content" msgid="7931085031240753226">"タッチパッド操作の詳細"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_title" msgid="1940023776496198762">"キーボードとタッチパッドを使用して移動する"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"タッチパッド操作やキーボード ショートカットなどの詳細"</string>
-    <string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"「戻る」ジェスチャー"</string>
-    <string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"「ホーム」ジェスチャー"</string>
+    <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"戻る"</string>
+    <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"ホームに移動"</string>
     <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"最近使ったアプリを表示する"</string>
     <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"完了"</string>
     <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"戻る"</string>
-    <string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"戻るには、3 本の指でタッチパッドを左右にスワイプします。\n\nキーボード ショートカットのアクション + ESC キーを使用して、この操作を行うこともできます。"</string>
-    <string name="touchpad_back_gesture_success_title" msgid="7240576648330612171">"お疲れさまでした。"</string>
+    <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"タッチパッドを 3 本の指で左右にスワイプします"</string>
+    <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"その調子です!"</string>
     <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"「戻る」操作を学習しました。"</string>
     <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"ホームに移動"</string>
-    <string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"3 本の指で画面を下から上にスワイプすると、ホーム画面にいつでも移動できます。"</string>
-    <string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"お疲れさまでした。"</string>
-    <string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"「ホームに移動」操作を学習しました。"</string>
+    <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"タッチパッドを 3 本の指で上にスワイプします"</string>
+    <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"よくできました!"</string>
+    <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"「ホームに移動」操作を学習しました"</string>
     <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"最近使ったアプリを表示する"</string>
-    <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"タッチパッドを 3 本の指で上にスワイプして長押しします。"</string>
+    <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"タッチパッドを 3 本の指で上にスワイプして長押しします"</string>
     <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"よくできました"</string>
     <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"「最近使ったアプリを表示する」操作を学習しました。"</string>
-    <string name="tutorial_action_key_title" msgid="2659466586996495447">"アクションキー"</string>
-    <string name="tutorial_action_key_guidance" msgid="5718948664616999196">"アプリにアクセスするには、キーボードのアクションキーを押します。"</string>
-    <string name="tutorial_action_key_success_title" msgid="466467860120112933">"お疲れさまでした。"</string>
-    <string name="tutorial_action_key_success_body" msgid="7201991081652850430">"アクションキー操作を学習しました。\n\nアクションキーと + キーを同時に押すと、利用可能なショートカットがすべて表示されます。"</string>
+    <string name="tutorial_action_key_title" msgid="8172535792469008169">"すべてのアプリを表示"</string>
+    <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"キーボードのアクションキーを押します"</string>
+    <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"完了です!"</string>
+    <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"「すべてのアプリを表示する」操作を学習しました"</string>
     <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"キーボード バックライト"</string>
     <string name="keyboard_backlight_value" msgid="7336398765584393538">"レベル %1$d/%2$d"</string>
     <string name="home_controls_dream_label" msgid="6567105701292324257">"ホーム コントロール"</string>
@@ -1436,6 +1440,7 @@
     <string name="all_apps_edu_toast_content" msgid="8807496014667211562">"すべてのアプリを表示するには、キーボードのアクションキーを押してください"</string>
     <string name="redacted_notification_single_line_title" msgid="212019960919261670">"削除済み"</string>
     <string name="redacted_notification_single_line_text" msgid="8684166405005242945">"表示するにはロックを解除してください"</string>
+    <string name="contextual_education_dialog_title" msgid="4630392552837487324">"コンテキスト メニューに関する説明"</string>
     <string name="back_edu_notification_title" msgid="5624780717751357278">"タッチパッドを使用して、前の画面に戻る"</string>
     <string name="back_edu_notification_content" msgid="2497557451540954068">"3 本の指で左または右にスワイプします。ジェスチャーの詳細を確認するにはタップしてください。"</string>
     <string name="home_edu_notification_title" msgid="6097902076909654045">"タッチパッドを使用して、ホームに移動する"</string>
diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml
index 539c186..65d8575 100644
--- a/packages/SystemUI/res/values-ka/strings.xml
+++ b/packages/SystemUI/res/values-ka/strings.xml
@@ -440,7 +440,7 @@
     <string name="zen_mode_on" msgid="9085304934016242591">"ჩართული"</string>
     <string name="zen_mode_on_with_details" msgid="7416143430557895497">"ჩართულია • <xliff:g id="TRIGGER_DESCRIPTION">%1$s</xliff:g>"</string>
     <string name="zen_mode_off" msgid="1736604456618147306">"გამორთული"</string>
-    <string name="zen_mode_set_up" msgid="7457957033034460064">"დაყენება"</string>
+    <string name="zen_mode_set_up" msgid="8231201163894922821">"არ არის დაყენებული"</string>
     <string name="zen_mode_no_manual_invocation" msgid="1769975741344633672">"პარამეტრებში მართვა"</string>
     <string name="zen_mode_active_modes" msgid="1625850411578488856">"{count,plural, =0{აქტიური რეჟიმები არ მოიძებნა}=1{{mode} აქტიურია}other{აქტიურია # რეჟიმი}}"</string>
     <string name="zen_priority_introduction" msgid="3159291973383796646">"თქვენ მიერ მითითებული მაღვიძარების, შეხსენებების, მოვლენებისა და ზარების გარდა, არავითარი ხმა და ვიბრაცია არ შეგაწუხებთ. თქვენ მაინც შეძლებთ სასურველი კონტენტის, მაგალითად, მუსიკის, ვიდეოებისა და თამაშების აუდიოს მოსმენა."</string>
@@ -573,8 +573,7 @@
     <string name="notification_section_header_conversations" msgid="821834744538345661">"საუბრები"</string>
     <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"ყველა ჩუმი შეტყობინების გასუფთავება"</string>
     <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"შეტყობინებები დაპაუზდა „არ შემაწუხოთ“ რეჟიმის მეშვეობით"</string>
-    <!-- no translation found for modes_suppressing_shade_text (6037581130837903239) -->
-    <skip />
+    <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{შეტყობინებები არ არის}=1{შეტყობინებები შეჩერებულია {mode}-ის გამო}=2{შეტყობინებები შეჩერებულია {mode}-ის და ერთი სხვა რეჟიმის გამო}other{შეტყობინებები შეჩერებულია {mode}-ის და # სხვა რეჟიმის გამო}}"</string>
     <string name="media_projection_action_text" msgid="3634906766918186440">"დაწყება ახლავე"</string>
     <string name="empty_shade_text" msgid="8935967157319717412">"შეტყობინებები არ არის."</string>
     <string name="no_unseen_notif_text" msgid="395512586119868682">"ახალი შეტყობინებები არ არის"</string>
@@ -673,6 +672,10 @@
     <string name="stream_notification_unavailable" msgid="4313854556205836435">"ზარის დადუმების გამო ხელმისაწვდომი არაა"</string>
     <string name="stream_alarm_unavailable" msgid="4059817189292197839">"მიუწვდომელია, ჩართულია „არ შემაწუხოთ“ რეჟიმი"</string>
     <string name="stream_media_unavailable" msgid="6823020894438959853">"მიუწვდომელია, ჩართულია „არ შემაწუხოთ“ რეჟიმი"</string>
+    <!-- no translation found for stream_unavailable_by_modes (3674139029490353683) -->
+    <skip />
+    <!-- no translation found for stream_unavailable_by_unknown (6908434629318171588) -->
+    <skip />
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. შეეხეთ დადუმების გასაუქმებლად."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. შეეხეთ ვიბრაციაზე დასაყენებლად. შეიძლება დადუმდეს მარტივი წვდომის სერვისებიც."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. შეეხეთ დასადუმებლად. შეიძლება დადუმდეს მარტივი წვდომის სერვისებიც."</string>
@@ -706,6 +709,7 @@
     <string name="show_demo_mode" msgid="3677956462273059726">"დემო-რეჟიმის ჩვენება"</string>
     <string name="status_bar_ethernet" msgid="5690979758988647484">"ეთერნეტი"</string>
     <string name="status_bar_alarm" msgid="87160847643623352">"მაღვიძარა"</string>
+    <string name="active_mode_content_description" msgid="1627555562186515927">"<xliff:g id="MODENAME">%1$s</xliff:g> ჩართულია"</string>
     <string name="wallet_title" msgid="5369767670735827105">"საფულე"</string>
     <string name="wallet_empty_state_label" msgid="7776761245237530394">"დააყენეთ შესყიდვების თქვენი ტელეფონით უფრო სწრაფად და უსაფრთხოდ შესასრულებლად"</string>
     <string name="wallet_app_button_label" msgid="7123784239111190992">"ყველას ჩვენება"</string>
@@ -1405,26 +1409,26 @@
     <string name="launch_touchpad_tutorial_notification_content" msgid="7931085031240753226">"სენსორული პანელის ჟესტების სწავლა"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_title" msgid="1940023776496198762">"ნავიგაცია კლავიატურის და სენსორული პანელის გამოყენებით"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"სენსორული პანელის ჟესტების, კლავიატურის მალსახმობების და სხვა ფუნქციების სწავლა"</string>
-    <string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"უკან დაბრუნების ჟესტი"</string>
-    <string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"მთავარ ეკრანზე გადასვლის ჟესტი"</string>
+    <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"უკან დაბრუნება"</string>
+    <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"მთავარ ეკრანზე გადასვლა"</string>
     <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"ბოლო აპების ნახვა"</string>
     <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"მზადაა"</string>
     <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"უკან დაბრუნება"</string>
-    <string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"უკან დასაბრუნებლად სენსორულ პანელზე გადაფურცლეთ მარცხნივ ან მარჯვნივ სამი თითის გამოყენებით ნებისმიერ ადგილას.\n\nამისთვის თქვენ ასევე შეგიძლიათ გამოიყენოთ კლავიატურის მალსახმობის მოქმედება + ESC."</string>
-    <string name="touchpad_back_gesture_success_title" msgid="7240576648330612171">"შესანიშნავია!"</string>
+    <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"თქვენს სენსორულ პანელზე სამი თითით გადაფურცლეთ მარცხნივ ან მარჯვნივ"</string>
+    <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"მშვენიერია!"</string>
     <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"თქვენ შეასრულეთ უკან დაბრუნების ჟესტი."</string>
     <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"მთავარზე გადასვლა"</string>
-    <string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"თქვენს მთავარ ეკრანზე ნებისმიერ დროს გადასასვლელად გადაფურცლეთ ეკრანის ქვემოდან ზემოთ სამი თითით."</string>
-    <string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"მშვენიერია!"</string>
-    <string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"თქვენ შეასრულეთ მთავარ ეკრანზე დაბრუნების ჟესტი."</string>
+    <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"თქვენს სენსორულ პანელზე სამი თითით გადაფურცლეთ ზევით"</string>
+    <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"შესანიშნავია!"</string>
+    <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"თქვენ შეასრულეთ მთავარ ეკრანზე გადასვლის ჟესტი"</string>
     <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"ბოლო აპების ნახვა"</string>
-    <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"თქვენს სენსორულ პანელზე სამი თითით გადაფურცლეთ ზემოთ და მოიცადეთ."</string>
+    <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"თქვენს სენსორულ პანელზე სამი თითით გადაფურცლეთ ზევით და ხანგრძლივად დააჭირეთ"</string>
     <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"შესანიშნავია!"</string>
     <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"თქვენ დაასრულეთ ბოლო აპების ხედის ჟესტი."</string>
-    <string name="tutorial_action_key_title" msgid="2659466586996495447">"მოქმედების კლავიში"</string>
-    <string name="tutorial_action_key_guidance" msgid="5718948664616999196">"აპებზე წვდომისთვის დააჭირეთ მოქმედების კლავიშს თქვენს კლავიატურაზე."</string>
-    <string name="tutorial_action_key_success_title" msgid="466467860120112933">"გილოცავთ!"</string>
-    <string name="tutorial_action_key_success_body" msgid="7201991081652850430">"თქვენ შეასრულეთ მოქმედების კლავიშის ჟესტი.\n\nქმედება + / აჩვენებს თქვენთვის ხელმისაწვდომ ყველა მალსახმობს."</string>
+    <string name="tutorial_action_key_title" msgid="8172535792469008169">"ყველა აპის ნახვა"</string>
+    <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"დააჭირეთ მოქმედების კლავიშს თქვენს კლავიატურაზე"</string>
+    <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"ყოჩაღ!"</string>
+    <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"თქვენ დაასრულეთ ყველა აპის ნახვის ჟესტი"</string>
     <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"კლავიატურის შენათება"</string>
     <string name="keyboard_backlight_value" msgid="7336398765584393538">"დონე: %1$d %2$d-დან"</string>
     <string name="home_controls_dream_label" msgid="6567105701292324257">"სახლის კონტროლი"</string>
@@ -1436,6 +1440,7 @@
     <string name="all_apps_edu_toast_content" msgid="8807496014667211562">"ყველა აპის სანახავად დააჭირეთ მოქმედების კლავიშს თქვენს კლავიატურაზე"</string>
     <string name="redacted_notification_single_line_title" msgid="212019960919261670">"ტექსტს ადევს ცენზურა"</string>
     <string name="redacted_notification_single_line_text" msgid="8684166405005242945">"განბლოკვა სანახავად"</string>
+    <string name="contextual_education_dialog_title" msgid="4630392552837487324">"კონტექსტური განათლება"</string>
     <string name="back_edu_notification_title" msgid="5624780717751357278">"უკან დასაბრუნებლად გამოიყენეთ სენსორული პანელი"</string>
     <string name="back_edu_notification_content" msgid="2497557451540954068">"გადაფურცლეთ მარცხნივ ან მარჯვნივ სამი თითით. შეეხეთ მეტი ჟესტის შესასწავლად."</string>
     <string name="home_edu_notification_title" msgid="6097902076909654045">"მთავარ გვერდზე გადასასვლელად გამოიყენეთ სენსორული პანელი"</string>
diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml
index 7343fa1..7478e76 100644
--- a/packages/SystemUI/res/values-kk/strings.xml
+++ b/packages/SystemUI/res/values-kk/strings.xml
@@ -440,7 +440,7 @@
     <string name="zen_mode_on" msgid="9085304934016242591">"Қосулы"</string>
     <string name="zen_mode_on_with_details" msgid="7416143430557895497">"Қосулы • <xliff:g id="TRIGGER_DESCRIPTION">%1$s</xliff:g>"</string>
     <string name="zen_mode_off" msgid="1736604456618147306">"Өшірулі"</string>
-    <string name="zen_mode_set_up" msgid="7457957033034460064">"Реттеу"</string>
+    <string name="zen_mode_set_up" msgid="8231201163894922821">"Орнатылмаған"</string>
     <string name="zen_mode_no_manual_invocation" msgid="1769975741344633672">"\"Параметрлер\" бөлімінде реттеу"</string>
     <string name="zen_mode_active_modes" msgid="1625850411578488856">"{count,plural, =0{Қосулы режим жоқ}=1{{mode} қосулы}other{# режим қосулы}}"</string>
     <string name="zen_priority_introduction" msgid="3159291973383796646">"Оятқыш, еске салғыш, іс-шара мен өзіңіз көрсеткен контактілердің қоңырауларынан басқа дыбыстар мен дірілдер мазаламайтын болады. Музыка, бейне және ойын сияқты медиафайлдарды қоссаңыз, оларды естисіз."</string>
@@ -573,8 +573,7 @@
     <string name="notification_section_header_conversations" msgid="821834744538345661">"Әңгімелер"</string>
     <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Барлық үнсіз хабарландыруларды өшіру"</string>
     <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Хабарландырулар Мазаламау режимінде кідіртілді"</string>
-    <!-- no translation found for modes_suppressing_shade_text (6037581130837903239) -->
-    <skip />
+    <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{Хабарландырулар жоқ.}=1{Хабарландыруларды {mode} режимі кідіртті.}=2{Хабарландыруларды {mode} және тағы бір режим кідіртті.}other{Хабарландыруларды {mode} және тағы # режим кідіртті.}}"</string>
     <string name="media_projection_action_text" msgid="3634906766918186440">"Қазір бастау"</string>
     <string name="empty_shade_text" msgid="8935967157319717412">"Хабарландырулар жоқ"</string>
     <string name="no_unseen_notif_text" msgid="395512586119868682">"Жаңа хабарландырулар жоқ"</string>
@@ -673,6 +672,10 @@
     <string name="stream_notification_unavailable" msgid="4313854556205836435">"Қолжетімді емес, шылдырлату өшірулі."</string>
     <string name="stream_alarm_unavailable" msgid="4059817189292197839">"Мазаламау режимі қосылғандықтан өзгерту мүмкін емес."</string>
     <string name="stream_media_unavailable" msgid="6823020894438959853">"Мазаламау режимі қосылғандықтан өзгерту мүмкін емес."</string>
+    <!-- no translation found for stream_unavailable_by_modes (3674139029490353683) -->
+    <skip />
+    <!-- no translation found for stream_unavailable_by_unknown (6908434629318171588) -->
+    <skip />
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Дыбысын қосу үшін түртіңіз."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Діріл режимін орнату үшін түртіңіз. Арнайы мүмкіндік қызметтерінің дыбысы өшуі мүмкін."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Дыбысын өшіру үшін түртіңіз. Арнайы мүмкіндік қызметтерінің дыбысы өшуі мүмкін."</string>
@@ -706,6 +709,7 @@
     <string name="show_demo_mode" msgid="3677956462273059726">"Демо режимін көрсету"</string>
     <string name="status_bar_ethernet" msgid="5690979758988647484">"Ethernet"</string>
     <string name="status_bar_alarm" msgid="87160847643623352">"Оятқыш"</string>
+    <string name="active_mode_content_description" msgid="1627555562186515927">"<xliff:g id="MODENAME">%1$s</xliff:g> қосулы."</string>
     <string name="wallet_title" msgid="5369767670735827105">"Wallet"</string>
     <string name="wallet_empty_state_label" msgid="7776761245237530394">"Телефоныңызбен бұрынғыдан да жылдам әрі қауіпсіз сатып алу үшін параметрлерді орнатыңыз."</string>
     <string name="wallet_app_button_label" msgid="7123784239111190992">"Барлығын көрсету"</string>
@@ -1405,26 +1409,26 @@
     <string name="launch_touchpad_tutorial_notification_content" msgid="7931085031240753226">"Сенсорлық тақта қимылдарын үйреніңіз."</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_title" msgid="1940023776496198762">"Пернетақтамен және сенсорлық тақтамен жұмыс істеңіз"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Сенсорлық тақта қимылдарын, перне тіркесімдерін және т.б. үйреніңіз."</string>
-    <string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Артқа қайтару қимылы"</string>
-    <string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Негізгі бетке қайтару қимылы"</string>
+    <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"Артқа"</string>
+    <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Негізгі бетке өту"</string>
     <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Соңғы қолданбаларды көру"</string>
     <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Дайын"</string>
     <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Артқа"</string>
-    <string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"Артқа қайту үшін сенсорлық тақтаның кез келген жерін үш саусақпен солға не оңға сырғытыңыз.\n\nСондай-ақ Action + ESC перне тіркесімін пайдалануға болады."</string>
-    <string name="touchpad_back_gesture_success_title" msgid="7240576648330612171">"Жарайсыз!"</string>
+    <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"Сенсорлық тақтада үш саусақпен оңға немесе солға сырғытыңыз."</string>
+    <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"Керемет!"</string>
     <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"Артқа қайту қимылын аяқтадыңыз."</string>
     <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"Негізгі экранға өту"</string>
-    <string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"Негізгі экранға кез келген уақытта өту үшін экранның төменгі жағынан жоғары қарай үш саусағыңызбен сырғытыңыз."</string>
-    <string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Жақсы нәтиже!"</string>
-    <string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Негізгі экранға қайту қимылын аяқтадыңыз."</string>
+    <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"Сенсорлық тақтада үш саусақпен жоғары сырғытыңыз."</string>
+    <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"Жарайсыз!"</string>
+    <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"Негізгі экранға қайту қимылын орындадыңыз."</string>
     <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"Соңғы қолданбаларды көру"</string>
-    <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"Сенсорлық тақтада үш саусақпен жоғары сырғытып, басып тұрыңыз."</string>
+    <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"Сенсорлық тақтада үш саусақпен жоғары сырғытып, басып тұрыңыз."</string>
     <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Жарайсыз!"</string>
     <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Соңғы қолданбаларды көру қимылын орындадыңыз."</string>
-    <string name="tutorial_action_key_title" msgid="2659466586996495447">"Әрекет пернесі"</string>
-    <string name="tutorial_action_key_guidance" msgid="5718948664616999196">"Қолданбаларыңызға кіру үшін пернетақтадағы әрекет пернесін басыңыз."</string>
-    <string name="tutorial_action_key_success_title" msgid="466467860120112933">"Құттықтаймыз!"</string>
-    <string name="tutorial_action_key_success_body" msgid="7201991081652850430">"Әрекет пернесі қимылын аяқтадыңыз.\n\n\"+ /\" әрекеті сіз үшін қолжетімді барлық таңбашаны көрсетеді."</string>
+    <string name="tutorial_action_key_title" msgid="8172535792469008169">"Барлық қолданбаны көру"</string>
+    <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Пернетақтадағы әрекет пернесін басыңыз."</string>
+    <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Жарайсыз!"</string>
+    <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Барлық қолданбаны көру қимылын орындадыңыз."</string>
     <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Пернетақта жарығы"</string>
     <string name="keyboard_backlight_value" msgid="7336398765584393538">"Деңгей: %1$d/%2$d"</string>
     <string name="home_controls_dream_label" msgid="6567105701292324257">"Үй басқару элементтері"</string>
@@ -1436,6 +1440,7 @@
     <string name="all_apps_edu_toast_content" msgid="8807496014667211562">"Пернетақтада әрекет пернесін басып, барлық қолданбаны көре аласыз."</string>
     <string name="redacted_notification_single_line_title" msgid="212019960919261670">"Жасырылған"</string>
     <string name="redacted_notification_single_line_text" msgid="8684166405005242945">"Көру үшін құлыпты ашыңыз."</string>
+    <string name="contextual_education_dialog_title" msgid="4630392552837487324">"Контекстік білім"</string>
     <string name="back_edu_notification_title" msgid="5624780717751357278">"Артқа қайту үшін сенсорлық тақтаны қолданыңыз"</string>
     <string name="back_edu_notification_content" msgid="2497557451540954068">"Үш саусақпен солға не оңға сырғытыңыз. Басқа қимылдарды үйрену үшін түртіңіз."</string>
     <string name="home_edu_notification_title" msgid="6097902076909654045">"Негізгі бетке өту үшін сенсорлық тақтаны қолданыңыз"</string>
diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml
index 1174635..d0f3f84 100644
--- a/packages/SystemUI/res/values-km/strings.xml
+++ b/packages/SystemUI/res/values-km/strings.xml
@@ -440,7 +440,7 @@
     <string name="zen_mode_on" msgid="9085304934016242591">"បើក"</string>
     <string name="zen_mode_on_with_details" msgid="7416143430557895497">"បើក • <xliff:g id="TRIGGER_DESCRIPTION">%1$s</xliff:g>"</string>
     <string name="zen_mode_off" msgid="1736604456618147306">"បិទ"</string>
-    <string name="zen_mode_set_up" msgid="7457957033034460064">"រៀបចំ"</string>
+    <string name="zen_mode_set_up" msgid="8231201163894922821">"មិនបានកំណត់"</string>
     <string name="zen_mode_no_manual_invocation" msgid="1769975741344633672">"គ្រប់គ្រង​នៅ​ក្នុង​ការកំណត់"</string>
     <string name="zen_mode_active_modes" msgid="1625850411578488856">"{count,plural, =0{គ្មានមុខងារ​ដែលកំពុងដំណើរការទេ}=1{{mode} កំពុង​ដំណើរការ}other{មុខងារ # កំពុងដំណើរការ}}"</string>
     <string name="zen_priority_introduction" msgid="3159291973383796646">"សំឡេង និងរំញ័រនឹងមិន​រំខានដល់អ្នកឡើយ លើកលែងតែម៉ោងរោទ៍ ការរំលឹក ព្រឹត្តិការណ៍ និងអ្នកហៅទូរសព្ទដែលអ្នកបញ្ជាក់ប៉ុណ្ណោះ។ អ្នកនឹងនៅតែឮសំឡេងសកម្មភាពគ្រប់យ៉ាងដែលអ្នកលេងដដែល រួមទាំងតន្រ្តី វីដេអូ និងហ្គេម។"</string>
@@ -573,8 +573,7 @@
     <string name="notification_section_header_conversations" msgid="821834744538345661">"ការសន្ទនា"</string>
     <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"សម្អាត​ការជូនដំណឹង​ស្ងាត់ទាំងអស់"</string>
     <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"ការជូនដំណឹង​បានផ្អាក​ដោយ​មុខងារកុំរំខាន"</string>
-    <!-- no translation found for modes_suppressing_shade_text (6037581130837903239) -->
-    <skip />
+    <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{គ្មាន​ការជូន​ដំណឹង}=1{ការជូនដំណឹង​ត្រូវបាន​ផ្អាកដោយ {mode}}=2{ការជូនដំណឹង​ត្រូវបាន​ផ្អាកដោយ {mode} និង​មុខងារមួយ​ផ្សេងទៀត}other{ការជូនដំណឹង​ត្រូវបាន​ផ្អាកដោយ {mode} និង​មុខងារ # ផ្សេងទៀត}}"</string>
     <string name="media_projection_action_text" msgid="3634906766918186440">"ចាប់ផ្ដើម​ឥឡូវ"</string>
     <string name="empty_shade_text" msgid="8935967157319717412">"គ្មាន​ការ​ជូនដំណឹង"</string>
     <string name="no_unseen_notif_text" msgid="395512586119868682">"គ្មាន​ការ​ជូន​ដំណឹង​​ថ្មីៗទេ"</string>
@@ -673,6 +672,10 @@
     <string name="stream_notification_unavailable" msgid="4313854556205836435">"មិន​អាច​ប្រើ​បាន​ទេ​ ព្រោះ​សំឡេង​រោទ៍​ត្រូវ​បាន​បិទ"</string>
     <string name="stream_alarm_unavailable" msgid="4059817189292197839">"មិនអាចប្រើបានទេ ដោយសារមុខងារកុំ​រំខានត្រូវបានបើក"</string>
     <string name="stream_media_unavailable" msgid="6823020894438959853">"មិនអាចប្រើបានទេ ដោយសារមុខងារកុំ​រំខានត្រូវបានបើក"</string>
+    <!-- no translation found for stream_unavailable_by_modes (3674139029490353683) -->
+    <skip />
+    <!-- no translation found for stream_unavailable_by_unknown (6908434629318171588) -->
+    <skip />
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s។ ប៉ះដើម្បីបើកសំឡេង។"</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s។ ប៉ះដើម្បីកំណត់ឲ្យញ័រ។ សេវាកម្មលទ្ធភាពប្រើប្រាស់អាចនឹងត្រូវបានបិទសំឡេង។"</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s។ ប៉ះដើម្បីបិទសំឡេង។ សេវាកម្មលទ្ធភាពប្រើប្រាស់អាចនឹងត្រូវបានបិទសំឡេង។"</string>
@@ -706,6 +709,7 @@
     <string name="show_demo_mode" msgid="3677956462273059726">"បង្ហាញរបៀបសាកល្បង"</string>
     <string name="status_bar_ethernet" msgid="5690979758988647484">"អ៊ីសឺរណិត"</string>
     <string name="status_bar_alarm" msgid="87160847643623352">"ម៉ោងរោទ៍"</string>
+    <string name="active_mode_content_description" msgid="1627555562186515927">"<xliff:g id="MODENAME">%1$s</xliff:g> ត្រូវបាន​បើក"</string>
     <string name="wallet_title" msgid="5369767670735827105">"Wallet"</string>
     <string name="wallet_empty_state_label" msgid="7776761245237530394">"ធ្វើការ​រៀបចំ ដើម្បី​ធ្វើការទិញ​កាន់តែលឿន​ជាងមុន សុវត្ថិភាព​ជាងមុន ដោយ​ប្រើ​ទូរសព្ទ​របស់អ្នក"</string>
     <string name="wallet_app_button_label" msgid="7123784239111190992">"បង្ហាញ​ទាំងអស់"</string>
@@ -1405,26 +1409,26 @@
     <string name="launch_touchpad_tutorial_notification_content" msgid="7931085031240753226">"ស្វែងយល់អំពីចលនាផ្ទាំងប៉ះ"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_title" msgid="1940023776496198762">"រុករកដោយប្រើក្ដារចុច និងផ្ទាំងប៉ះរបស់អ្នក"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"ស្វែងយល់អំពីចលនាផ្ទាំងប៉ះ ផ្លូវកាត់​ក្ដារ​ចុច និងអ្វីៗជាច្រើនទៀត"</string>
-    <string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"ចលនាថយក្រោយ"</string>
-    <string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"ចលនាទៅទំព័រដើម"</string>
+    <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"ថយ​ក្រោយ"</string>
+    <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"ទៅទំព័រដើម"</string>
     <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"មើលកម្មវិធីថ្មីៗ"</string>
     <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"រួចរាល់"</string>
     <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"ថយ​ក្រោយ"</string>
-    <string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"ដើម្បីថយក្រោយ សូមអូសទៅឆ្វេង ឬស្ដាំដោយប្រើ​​ម្រាមដៃបីនៅត្រង់ណាក៏បានលើផ្ទាំងប៉ះ។\n\nអ្នកក៏អាចប្រើសកម្មភាពផ្លូវកាត់ក្ដារចុច + ESC សម្រាប់ការធ្វើបែបនេះ។"</string>
-    <string name="touchpad_back_gesture_success_title" msgid="7240576648330612171">"ធ្វើបានល្អ!"</string>
+    <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"អូសទៅឆ្វេង ឬស្ដាំដោយប្រើ​ម្រាមដៃបីនៅលើផ្ទាំងប៉ះរបស់អ្នក"</string>
+    <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"ល្អ!"</string>
     <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"អ្នក​បានបញ្ចប់​ចលនា​ថយក្រោយ​ហើយ។"</string>
     <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"ទៅទំព័រដើម"</string>
-    <string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"ដើម្បីចូលទៅអេក្រង់ដើមរបស់អ្នកនៅពេលណាក៏បាន សូមអូសឡើងលើដោយប្រើម្រាមដៃបីពីផ្នែកខាងក្រោមនៃអេក្រង់របស់អ្នក។"</string>
-    <string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"ល្អ!"</string>
-    <string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"អ្នក​បានបញ្ចប់​ចលនា​ចូលទៅកាន់​ទំព័រដើម​ហើយ។"</string>
+    <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"អូសឡើងលើដោយប្រើម្រាមដៃបី​នៅលើផ្ទាំងប៉ះរបស់អ្នក"</string>
+    <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"ធ្វើបានល្អ!"</string>
+    <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"អ្នក​បានបញ្ចប់​ចលនា​ចូលទៅកាន់​ទំព័រដើម​ហើយ"</string>
     <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"មើលកម្មវិធីថ្មីៗ"</string>
-    <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"អូសឡើងលើ ហើយសង្កត់ឱ្យជាប់ដោយប្រើម្រាមដៃបីលើផ្ទាំងប៉ះរបស់អ្នក។"</string>
+    <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"អូសឡើងលើ ហើយសង្កត់ឱ្យជាប់ដោយប្រើម្រាមដៃបីលើផ្ទាំងប៉ះរបស់អ្នក"</string>
     <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"ធ្វើបានល្អ!"</string>
     <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"អ្នកបានបញ្ចប់ការមើលចលនាកម្មវិធីថ្មីៗ។"</string>
-    <string name="tutorial_action_key_title" msgid="2659466586996495447">"គ្រាប់ចុចសកម្មភាព"</string>
-    <string name="tutorial_action_key_guidance" msgid="5718948664616999196">"ដើម្បីចូលប្រើប្រាស់កម្មវិធីរបស់អ្នក សូមចុចគ្រាប់ចុចសកម្មភាពនៅលើក្ដារចុចរបស់អ្នក។"</string>
-    <string name="tutorial_action_key_success_title" msgid="466467860120112933">"សូមអបអរសាទរ!"</string>
-    <string name="tutorial_action_key_success_body" msgid="7201991081652850430">"អ្នកបានបញ្ចប់មេរៀនអំពីចលនាសម្រាប់គ្រាប់ចុចសកម្មភាព។\n\nគ្រាប់ចុចសកម្មភាព + / បង្ហាញផ្លូវកាត់ទាំងអស់ដែលអ្នកអាចប្រើបាន។"</string>
+    <string name="tutorial_action_key_title" msgid="8172535792469008169">"មើល​កម្មវិធី​ទាំងអស់"</string>
+    <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"ចុចគ្រាប់ចុចសកម្មភាពលើក្ដារចុចរបស់អ្នក"</string>
+    <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"ធ្វើបាន​ល្អ!"</string>
+    <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"អ្នកបានបញ្ចប់ចលនាមើលកម្មវិធីទាំងអស់ហើយ"</string>
     <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"ពន្លឺក្រោយក្ដារចុច"</string>
     <string name="keyboard_backlight_value" msgid="7336398765584393538">"កម្រិតទី %1$d នៃ %2$d"</string>
     <string name="home_controls_dream_label" msgid="6567105701292324257">"ការគ្រប់គ្រង​ផ្ទះ"</string>
@@ -1436,6 +1440,7 @@
     <string name="all_apps_edu_toast_content" msgid="8807496014667211562">"ដើម្បីមើលកម្មវិធីទាំងអស់របស់អ្នក សូមចុចគ្រាប់ចុចសកម្មភាពនៅលើក្ដារចុចរបស់អ្នក"</string>
     <string name="redacted_notification_single_line_title" msgid="212019960919261670">"បាន​កែ​លម្អ​ពាក្យពេចន៍"</string>
     <string name="redacted_notification_single_line_text" msgid="8684166405005242945">"ដោះសោដើម្បីមើល"</string>
+    <string name="contextual_education_dialog_title" msgid="4630392552837487324">"ការអប់រំ​តាមបរិបទ"</string>
     <string name="back_edu_notification_title" msgid="5624780717751357278">"ប្រើផ្ទាំងប៉ះរបស់អ្នក ដើម្បីថយក្រោយ"</string>
     <string name="back_edu_notification_content" msgid="2497557451540954068">"អូសទៅឆ្វេង ឬស្ដាំដោយប្រើ​ម្រាមដៃបី។ ចុច ដើម្បីស្វែងយល់បន្ថែមអំពីចលនា។"</string>
     <string name="home_edu_notification_title" msgid="6097902076909654045">"ប្រើផ្ទាំងប៉ះរបស់អ្នក ដើម្បីចូលទៅទំព័រដើម"</string>
diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml
index 52daecb..57a8cdf 100644
--- a/packages/SystemUI/res/values-kn/strings.xml
+++ b/packages/SystemUI/res/values-kn/strings.xml
@@ -440,7 +440,7 @@
     <string name="zen_mode_on" msgid="9085304934016242591">"ಆನ್ ಆಗಿದೆ"</string>
     <string name="zen_mode_on_with_details" msgid="7416143430557895497">"<xliff:g id="TRIGGER_DESCRIPTION">%1$s</xliff:g> • ನಲ್ಲಿ"</string>
     <string name="zen_mode_off" msgid="1736604456618147306">"ಆಫ್ ಆಗಿದೆ"</string>
-    <string name="zen_mode_set_up" msgid="7457957033034460064">"ಸೆಟಪ್ ಮಾಡಿ"</string>
+    <string name="zen_mode_set_up" msgid="8231201163894922821">"ಸೆಟ್ ಮಾಡಿಲ್ಲ"</string>
     <string name="zen_mode_no_manual_invocation" msgid="1769975741344633672">"ಸೆಟ್ಟಿಂಗ್‌ಗಳಲ್ಲಿ ನಿರ್ವಹಿಸಿ"</string>
     <string name="zen_mode_active_modes" msgid="1625850411578488856">"{count,plural, =0{ಯಾವುದೇ ಸಕ್ರಿಯ ಮೋಡ್‌ಗಳಿಲ್ಲ}=1{{mode} ಸಕ್ರಿಯವಾಗಿದೆ}one{# ಮೋಡ್‌ಗಳು ಸಕ್ರಿಯವಾಗಿವೆ}other{# ಮೋಡ್‌ಗಳು ಸಕ್ರಿಯವಾಗಿವೆ}}"</string>
     <string name="zen_priority_introduction" msgid="3159291973383796646">"ಅಲಾರಾಂಗಳು, ಜ್ಞಾಪನೆಗಳು, ಈವೆಂಟ್‌ಗಳು ಹಾಗೂ ನೀವು ಸೂಚಿಸಿರುವ ಕರೆದಾರರನ್ನು ಹೊರತುಪಡಿಸಿ ಬೇರಾವುದೇ ಸದ್ದುಗಳು ಅಥವಾ ವೈಬ್ರೇಶನ್‌ಗಳು ನಿಮಗೆ ತೊಂದರೆ ನೀಡುವುದಿಲ್ಲ. ಹಾಗಿದ್ದರೂ, ನೀವು ಪ್ಲೇ ಮಾಡುವ ಸಂಗೀತ, ವೀಡಿಯೊಗಳು ಮತ್ತು ಆಟಗಳ ಆಡಿಯೊವನ್ನು ನೀವು ಕೇಳಿಸಿಕೊಳ್ಳುತ್ತೀರಿ."</string>
@@ -573,8 +573,7 @@
     <string name="notification_section_header_conversations" msgid="821834744538345661">"ಸಂಭಾಷಣೆಗಳು"</string>
     <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"ಎಲ್ಲಾ ನಿಶ್ಶಬ್ಧ ಅಧಿಸೂಚನೆಗಳನ್ನು ತೆರವುಗೊಳಿಸಿ"</string>
     <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"ಅಡಚಣೆ ಮಾಡಬೇಡಿ ಎನ್ನುವ ಮೂಲಕ ಅಧಿಸೂಚನೆಗಳನ್ನು ವಿರಾಮಗೊಳಿಸಲಾಗಿದೆ"</string>
-    <!-- no translation found for modes_suppressing_shade_text (6037581130837903239) -->
-    <skip />
+    <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{ಯಾವುದೇ ನೋಟಿಫಿಕೇಶನ್‌ಗಳು ಇಲ್ಲ}=1{ನೋಟಿಫಿಕೇಶನ್‌ಗಳನ್ನು {mode} ವಿರಾಮಗೊಳಿಸಿದೆ}=2{ನೋಟಿಫಿಕೇಶನ್‌ಗಳನ್ನು {mode} ಹಾಗೂ ಇತರ ಒಂದು ಮೋಡ್ ವಿರಾಮಗೊಳಿಸಿವೆ}one{ನೋಟಿಫಿಕೇಶನ್‌ಗಳನ್ನು {mode} ಹಾಗೂ ಇತರ # ಮೋಡ್‌ಗಳು ವಿರಾಮಗೊಳಿಸಿವೆ}other{ನೋಟಿಫಿಕೇಶನ್‌ಗಳನ್ನು {mode} ಹಾಗೂ ಇತರ # ಮೋಡ್‌ಗಳು ವಿರಾಮಗೊಳಿಸಿವೆ}}"</string>
     <string name="media_projection_action_text" msgid="3634906766918186440">"ಈಗ ಪ್ರಾರಂಭಿಸಿ"</string>
     <string name="empty_shade_text" msgid="8935967157319717412">"ಯಾವುದೇ ಅಧಿಸೂಚನೆಗಳಿಲ್ಲ"</string>
     <string name="no_unseen_notif_text" msgid="395512586119868682">"ಯಾವುದೇ ಹೊಸ ಅಧಿಸೂಚನೆಗಳಿಲ್ಲ"</string>
@@ -673,6 +672,10 @@
     <string name="stream_notification_unavailable" msgid="4313854556205836435">"ರಿಂಗ್ ಮ್ಯೂಟ್ ಆಗಿರುವ ಕಾರಣ ಲಭ್ಯವಿಲ್ಲ"</string>
     <string name="stream_alarm_unavailable" msgid="4059817189292197839">"ಅಡಚಣೆ ಮಾಡಬೇಡಿ ಫೀಚರ್ ಆನ್ ಆಗಿರುವುದರಿಂದ ಲಭ್ಯವಿಲ್ಲ"</string>
     <string name="stream_media_unavailable" msgid="6823020894438959853">"ಅಡಚಣೆ ಮಾಡಬೇಡಿ ಫೀಚರ್ ಆನ್ ಆಗಿರುವುದರಿಂದ ಲಭ್ಯವಿಲ್ಲ"</string>
+    <!-- no translation found for stream_unavailable_by_modes (3674139029490353683) -->
+    <skip />
+    <!-- no translation found for stream_unavailable_by_unknown (6908434629318171588) -->
+    <skip />
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. ಅನ್‌ಮ್ಯೂಟ್‌ ಮಾಡುವುದಕ್ಕಾಗಿ ಟ್ಯಾಪ್ ಮಾಡಿ."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. ಕಂಪನಕ್ಕೆ ಹೊಂದಿಸಲು ಟ್ಯಾಪ್ ಮಾಡಿ. ಆ್ಯಕ್ಸೆಸಿಬಿಲಿಟಿ ಸೇವೆಗಳನ್ನು ಮ್ಯೂಟ್‌ ಮಾಡಬಹುದು."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. ಮ್ಯೂಟ್ ಮಾಡಲು ಟ್ಯಾಪ್ ಮಾಡಿ. ಆ್ಯಕ್ಸೆಸಿಬಿಲಿಟಿ ಸೇವೆಗಳನ್ನು ಮ್ಯೂಟ್‌ ಮಾಡಬಹುದು."</string>
@@ -706,6 +709,7 @@
     <string name="show_demo_mode" msgid="3677956462273059726">"ಡೆಮೊ ಮೋಡ್ ತೋರಿಸು"</string>
     <string name="status_bar_ethernet" msgid="5690979758988647484">"ಇಥರ್ನೆಟ್"</string>
     <string name="status_bar_alarm" msgid="87160847643623352">"ಅಲಾರಮ್"</string>
+    <string name="active_mode_content_description" msgid="1627555562186515927">"<xliff:g id="MODENAME">%1$s</xliff:g> ಆನ್ ಆಗಿದೆ"</string>
     <string name="wallet_title" msgid="5369767670735827105">"ವಾಲೆಟ್"</string>
     <string name="wallet_empty_state_label" msgid="7776761245237530394">"ನಿಮ್ಮ ಫೋನ್ ಮೂಲಕ ವೇಗವಾದ, ಹೆಚ್ಚು ಸುರಕ್ಷಿತ ಖರೀದಿಗಳನ್ನು ಮಾಡಲು ಸೆಟಪ್ ಮಾಡಿಕೊಳ್ಳಿ"</string>
     <string name="wallet_app_button_label" msgid="7123784239111190992">"ಎಲ್ಲವನ್ನೂ ತೋರಿಸಿ"</string>
@@ -1405,26 +1409,26 @@
     <string name="launch_touchpad_tutorial_notification_content" msgid="7931085031240753226">"ಟಚ್‌ಪ್ಯಾಡ್ ಗೆಸ್ಚರ್‌ಗಳನ್ನು ಕಲಿಯಿರಿ"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_title" msgid="1940023776496198762">"ನಿಮ್ಮ ಕೀಬೋರ್ಡ್ ಮತ್ತು ಟಚ್‌ಪ್ಯಾಡ್ ಬಳಸಿ ನ್ಯಾವಿಗೇಟ್ ಮಾಡಿ"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"ಟಚ್‌ಪ್ಯಾಡ್ ಗೆಸ್ಚರ್‌ಗಳು, ಕೀಬೋರ್ಡ್‌ಗಳ ಶಾರ್ಟ್‌ಕಟ್‌ಗಳು ಮತ್ತು ಹೆಚ್ಚಿನದನ್ನು ತಿಳಿಯಿರಿ"</string>
-    <string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"ಹಿಂಬದಿ ಗೆಸ್ಚರ್"</string>
-    <string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"ಹೋಮ್ ಗೆಸ್ಚರ್"</string>
+    <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"ಹಿಂದಿರುಗಿ"</string>
+    <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"ಮುಖಪುಟಕ್ಕೆ ಹೋಗಿ"</string>
     <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"ಇತ್ತೀಚಿನ ಆ್ಯಪ್‌ಗಳನ್ನು ವೀಕ್ಷಿಸಿ"</string>
     <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"ಮುಗಿದಿದೆ"</string>
     <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"ಹಿಂತಿರುಗಿ"</string>
-    <string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"ಹಿಂತಿರುಗಲು, ಟಚ್‌ಪ್ಯಾಡ್‌ನಲ್ಲಿ ಎಲ್ಲಿಯಾದರೂ ಮೂರು ಬೆರಳುಗಳನ್ನು ಬಳಸಿ ಎಡ ಅಥವಾ ಬಲಕ್ಕೆ ಸ್ವೈಪ್ ಮಾಡಿ.\n\nಇದಕ್ಕಾಗಿ ನೀವು ಕೀಬೋರ್ಡ್ ಶಾರ್ಟ್‌ಕಟ್ Action + ESC ಅನ್ನು ಸಹ ಬಳಸಬಹುದು."</string>
-    <string name="touchpad_back_gesture_success_title" msgid="7240576648330612171">"ಭೇಷ್!"</string>
+    <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"ನಿಮ್ಮ ಟಚ್‌ಪ್ಯಾಡ್‌ನಲ್ಲಿ ಮೂರು ಬೆರಳುಗಳನ್ನು ಬಳಸಿ ಎಡ ಅಥವಾ ಬಲಕ್ಕೆ ಸ್ವೈಪ್ ಮಾಡಿ"</string>
+    <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"ಚೆನ್ನಾಗಿದೆ!"</string>
     <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"ನೀವು ಗೋ ಬ್ಯಾಕ್ ಗೆಸ್ಚರ್ ಅನ್ನು ಪೂರ್ಣಗೊಳಿಸಿದ್ದೀರಿ."</string>
     <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"ಮುಖಪುಟಕ್ಕೆ ಹೋಗಿ"</string>
-    <string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"ಯಾವುದೇ ಸಮಯದಲ್ಲಿ ನಿಮ್ಮ ಹೋಮ್ ಸ್ಕ್ರೀನ್‌ಗೆ ಹೋಗಲು, ನಿಮ್ಮ ಸ್ಕ್ರೀನ್ ಕೆಳಗಿನಿಂದ ಮೂರು ಬೆರಳುಗಳಿಂದ ಮೇಲಕ್ಕೆ ಸ್ವೈಪ್ ಮಾಡಿ."</string>
-    <string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"ಭೇಷ್!"</string>
-    <string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"ನೀವು ಗೋ ಹೋಮ್ ಗೆಸ್ಚರ್ ಅನ್ನು ಪೂರ್ಣಗೊಳಿಸಿದ್ದೀರಿ."</string>
+    <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"ಟಚ್‌ಪ್ಯಾಡ್‌ನಲ್ಲಿ ಮೂರು ಬೆರಳಿಂದ ಮೇಲಕ್ಕೆ ಸ್ವೈಪ್ ಮಾಡಿ"</string>
+    <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"ಭೇಷ್!"</string>
+    <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"ನೀವು ಗೋ ಹೋಮ್ ಗೆಸ್ಚರ್ ಅನ್ನು ಪೂರ್ಣಗೊಳಿಸಿದ್ದೀರಿ"</string>
     <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"ಇತ್ತೀಚಿನ ಆ್ಯಪ್‌ಗಳನ್ನು ವೀಕ್ಷಿಸಿ"</string>
-    <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"ನಿಮ್ಮ ಟಚ್‌ಪ್ಯಾಡ್‌ನಲ್ಲಿ ಮೂರು ಬೆರಳುಗಳನ್ನು ಬಳಸಿ ಮೇಲಕ್ಕೆ ಸ್ವೈಪ್ ಮಾಡಿ ಮತ್ತು ಹಿಡಿದುಕೊಳ್ಳಿ."</string>
+    <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"ನಿಮ್ಮ ಟಚ್‌ಪ್ಯಾಡ್‌ನಲ್ಲಿ ಮೂರು ಬೆರಳುಗಳನ್ನು ಬಳಸಿ ಮೇಲಕ್ಕೆ ಸ್ವೈಪ್ ಮಾಡಿ ಮತ್ತು ಹೋಲ್ಡ್ ಮಾಡಿ"</string>
     <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"ಭೇಷ್‌!"</string>
     <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"ನೀವು ಇತ್ತೀಚಿನ ಆ್ಯಪ್‌ಗಳ ಗೆಸ್ಚರ್‌ ವೀಕ್ಷಣೆಯನ್ನು ಪೂರ್ಣಗೊಳಿಸಿದ್ದೀರಿ."</string>
-    <string name="tutorial_action_key_title" msgid="2659466586996495447">"ಆ್ಯಕ್ಷನ್‌ ಕೀ"</string>
-    <string name="tutorial_action_key_guidance" msgid="5718948664616999196">"ನಿಮ್ಮ ಆ್ಯಪ್‌ಗಳನ್ನು ಆ್ಯಕ್ಸೆಸ್ ಮಾಡಲು, ನಿಮ್ಮ ಕೀಬೋರ್ಡ್‌ನಲ್ಲಿರುವ ಆ್ಯಕ್ಷನ್‌ ಕೀಯನ್ನು ಒತ್ತಿರಿ."</string>
-    <string name="tutorial_action_key_success_title" msgid="466467860120112933">"ಅಭಿನಂದನೆಗಳು!"</string>
-    <string name="tutorial_action_key_success_body" msgid="7201991081652850430">"ನೀವು ಆ್ಯಕ್ಷನ್‌ ಕೀ ಗೆಸ್ಚರ್ ಅನ್ನು ಪೂರ್ಣಗೊಳಿಸಿದ್ದೀರಿ.\n\nನಿಮಗೆ ಲಭ್ಯವಿರುವ ಎಲ್ಲಾ ಶಾರ್ಟ್‌ಕಟ್‌ಗಳನ್ನು ಆ್ಯಕ್ಷನ್‌ + / ತೋರಿಸುತ್ತದೆ."</string>
+    <string name="tutorial_action_key_title" msgid="8172535792469008169">"ಎಲ್ಲಾ ಆ್ಯಪ್‌ಗಳನ್ನು ವೀಕ್ಷಿಸಿ"</string>
+    <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"ನಿಮ್ಮ ಕೀಬೋರ್ಡ್‌ನಲ್ಲಿ ಆ್ಯಕ್ಷನ್‌ ಕೀಯನ್ನು ಒತ್ತಿ"</string>
+    <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"ಭೇಷ್!"</string>
+    <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"ನೀವು ಎಲ್ಲಾ ಆ್ಯಪ್‌ಗಳ ಗೆಸ್ಚರ್‌ ವೀಕ್ಷಣೆಯನ್ನು ಪೂರ್ಣಗೊಳಿಸಿದ್ದೀರಿ"</string>
     <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"ಕೀಬೋರ್ಡ್ ಬ್ಯಾಕ್‌ಲೈಟ್"</string>
     <string name="keyboard_backlight_value" msgid="7336398765584393538">"%2$d ರಲ್ಲಿ %1$d ಮಟ್ಟ"</string>
     <string name="home_controls_dream_label" msgid="6567105701292324257">"ಮನೆ ನಿಯಂತ್ರಣಗಳು"</string>
@@ -1436,6 +1440,7 @@
     <string name="all_apps_edu_toast_content" msgid="8807496014667211562">"ನಿಮ್ಮ ಎಲ್ಲಾ ಆ್ಯಪ್‌ಗಳನ್ನು ವೀಕ್ಷಿಸಲು, ನಿಮ್ಮ ಕೀಬೋರ್ಡ್‌ನಲ್ಲಿರುವ ಆ್ಯಕ್ಷನ್‌ ಕೀಯನ್ನು ಒತ್ತಿರಿ"</string>
     <string name="redacted_notification_single_line_title" msgid="212019960919261670">"ಅರ್ಥಬದ್ಧವಾಗಿಸಲಾಗಿದೆ"</string>
     <string name="redacted_notification_single_line_text" msgid="8684166405005242945">"ನೋಡಲು ಅನ್‌ಲಾಕ್ ಮಾಡಿ"</string>
+    <string name="contextual_education_dialog_title" msgid="4630392552837487324">"ಸಂದರ್ಭೋಚಿತ ಶಿಕ್ಷಣ"</string>
     <string name="back_edu_notification_title" msgid="5624780717751357278">"ಹಿಂತಿರುಗಲು ನಿಮ್ಮ ಟಚ್‌ಪ್ಯಾಡ್ ಅನ್ನು ಬಳಸಿ"</string>
     <string name="back_edu_notification_content" msgid="2497557451540954068">"ಮೂರು ಬೆರಳುಗಳಿಂದ ಎಡಕ್ಕೆ ಅಥವಾ ಬಲಕ್ಕೆ ಸ್ವೈಪ್ ಮಾಡಿ. ಇನ್ನಷ್ಟು ಗೆಸ್ಚರ್‌ಗಳನ್ನು ತಿಳಿಯಲು ಟ್ಯಾಪ್ ಮಾಡಿ."</string>
     <string name="home_edu_notification_title" msgid="6097902076909654045">"ಹೋಮ್‌ಗೆ ಹೋಗಲು ನಿಮ್ಮ ಟಚ್‌ಪ್ಯಾಡ್ ಅನ್ನು ಬಳಸಿ"</string>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index 9a9f3eb..9775ad5 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -440,7 +440,7 @@
     <string name="zen_mode_on" msgid="9085304934016242591">"사용"</string>
     <string name="zen_mode_on_with_details" msgid="7416143430557895497">"켜짐 • <xliff:g id="TRIGGER_DESCRIPTION">%1$s</xliff:g>"</string>
     <string name="zen_mode_off" msgid="1736604456618147306">"사용 안함"</string>
-    <string name="zen_mode_set_up" msgid="7457957033034460064">"설정"</string>
+    <string name="zen_mode_set_up" msgid="8231201163894922821">"설정되지 않음"</string>
     <string name="zen_mode_no_manual_invocation" msgid="1769975741344633672">"설정에서 관리"</string>
     <string name="zen_mode_active_modes" msgid="1625850411578488856">"{count,plural, =0{활성화된 모드 없음}=1{{mode} 모드가 활성화됨}other{모드 #개가 활성화됨}}"</string>
     <string name="zen_priority_introduction" msgid="3159291973383796646">"알람, 알림, 일정 및 지정한 발신자로부터 받은 전화를 제외한 소리와 진동을 끕니다. 음악, 동영상, 게임 등 재생하도록 선택한 소리는 정상적으로 들립니다."</string>
@@ -573,8 +573,7 @@
     <string name="notification_section_header_conversations" msgid="821834744538345661">"대화"</string>
     <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"무음 알림 모두 삭제"</string>
     <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"방해 금지 모드로 알림이 일시중지됨"</string>
-    <!-- no translation found for modes_suppressing_shade_text (6037581130837903239) -->
-    <skip />
+    <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{알림 없음}=1{{mode} 모드로 인해 알림이 일시중지되었습니다.}=2{{mode} 및 다른 모드로 인해 알림이 일시중지되었습니다.}other{{mode} 및 다른 모드 #개로 인해 알림이 일시중지되었습니다.}}"</string>
     <string name="media_projection_action_text" msgid="3634906766918186440">"시작하기"</string>
     <string name="empty_shade_text" msgid="8935967157319717412">"알림 없음"</string>
     <string name="no_unseen_notif_text" msgid="395512586119868682">"새로운 알림 없음"</string>
@@ -673,6 +672,10 @@
     <string name="stream_notification_unavailable" msgid="4313854556205836435">"벨소리가 음소거되어 있으므로 사용할 수 없음"</string>
     <string name="stream_alarm_unavailable" msgid="4059817189292197839">"방해 금지 모드로 설정되어 있어 사용할 수 없음"</string>
     <string name="stream_media_unavailable" msgid="6823020894438959853">"방해 금지 모드로 설정되어 있어 사용할 수 없음"</string>
+    <!-- no translation found for stream_unavailable_by_modes (3674139029490353683) -->
+    <skip />
+    <!-- no translation found for stream_unavailable_by_unknown (6908434629318171588) -->
+    <skip />
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. 탭하여 음소거를 해제하세요."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. 탭하여 진동으로 설정하세요. 접근성 서비스가 음소거될 수 있습니다."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. 탭하여 음소거로 설정하세요. 접근성 서비스가 음소거될 수 있습니다."</string>
@@ -706,6 +709,7 @@
     <string name="show_demo_mode" msgid="3677956462273059726">"데모 모드 표시"</string>
     <string name="status_bar_ethernet" msgid="5690979758988647484">"이더넷"</string>
     <string name="status_bar_alarm" msgid="87160847643623352">"알람"</string>
+    <string name="active_mode_content_description" msgid="1627555562186515927">"<xliff:g id="MODENAME">%1$s</xliff:g> 사용 중"</string>
     <string name="wallet_title" msgid="5369767670735827105">"월렛"</string>
     <string name="wallet_empty_state_label" msgid="7776761245237530394">"설정하여 휴대전화로 더욱 빠르고 안전하게 구매하세요."</string>
     <string name="wallet_app_button_label" msgid="7123784239111190992">"모두 표시"</string>
@@ -1405,26 +1409,26 @@
     <string name="launch_touchpad_tutorial_notification_content" msgid="7931085031240753226">"터치패드 동작 알아보기"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_title" msgid="1940023776496198762">"키보드와 터치패드를 사용하여 이동"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"터치패드 동작, 단축키 등 알아보기"</string>
-    <string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"뒤로 동작"</string>
-    <string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"홈 동작"</string>
+    <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"뒤로 이동"</string>
+    <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"홈으로 이동"</string>
     <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"최근 앱 보기"</string>
     <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"완료"</string>
     <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"뒤로"</string>
-    <string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"돌아가려면 세 손가락을 사용해 터치패드의 아무 곳이나 왼쪽 또는 오른쪽으로 스와이프합니다.\n\n키보드 단축키 Action + ESC를 사용할 수도 있습니다."</string>
-    <string name="touchpad_back_gesture_success_title" msgid="7240576648330612171">"아주 좋습니다"</string>
+    <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"세 손가락을 사용해 터치패드에서 왼쪽 또는 오른쪽으로 스와이프하세요."</string>
+    <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"훌륭합니다"</string>
     <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"돌아가기 동작을 완료했습니다."</string>
     <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"홈으로 이동"</string>
-    <string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"언제든지 홈 화면으로 이동하려면 세 손가락으로 화면 하단에서 위로 스와이프하세요."</string>
-    <string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"좋습니다"</string>
-    <string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"홈으로 이동 동작을 완료했습니다."</string>
+    <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"세 손가락을 사용해 터치패드에서 위로 스와이프하세요."</string>
+    <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"아주 좋습니다"</string>
+    <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"홈으로 이동 동작을 완료했습니다."</string>
     <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"최근 앱 보기"</string>
-    <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"터치패드에서 세 손가락을 사용해 위로 스와이프한 후 잠시 기다리세요."</string>
+    <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"세 손가락을 사용해 터치패드에서 위로 스와이프한 후 잠시 기다리세요."</string>
     <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"아주 좋습니다"</string>
     <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"최근 앱 보기 동작을 완료했습니다."</string>
-    <string name="tutorial_action_key_title" msgid="2659466586996495447">"작업 키"</string>
-    <string name="tutorial_action_key_guidance" msgid="5718948664616999196">"앱에 액세스하려면 키보드의 작업 키를 누르세요."</string>
-    <string name="tutorial_action_key_success_title" msgid="466467860120112933">"축하합니다"</string>
-    <string name="tutorial_action_key_success_body" msgid="7201991081652850430">"작업 키 동작을 완료했습니다.\n\n작업 키 + /를 누르면 사용 가능한 모든 단축키가 표시됩니다."</string>
+    <string name="tutorial_action_key_title" msgid="8172535792469008169">"모든 앱 보기"</string>
+    <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"키보드의 작업 키를 누르세요."</string>
+    <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"잘하셨습니다"</string>
+    <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"모든 앱 보기 동작을 완료했습니다."</string>
     <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"키보드 백라이트"</string>
     <string name="keyboard_backlight_value" msgid="7336398765584393538">"%2$d단계 중 %1$d단계"</string>
     <string name="home_controls_dream_label" msgid="6567105701292324257">"홈 컨트롤"</string>
@@ -1436,6 +1440,7 @@
     <string name="all_apps_edu_toast_content" msgid="8807496014667211562">"모든 앱을 보려면 키보드의 작업 키를 누르세요"</string>
     <string name="redacted_notification_single_line_title" msgid="212019960919261670">"수정됨"</string>
     <string name="redacted_notification_single_line_text" msgid="8684166405005242945">"잠금 해제하여 보기"</string>
+    <string name="contextual_education_dialog_title" msgid="4630392552837487324">"컨텍스트 교육"</string>
     <string name="back_edu_notification_title" msgid="5624780717751357278">"터치패드를 사용하여 돌아가기"</string>
     <string name="back_edu_notification_content" msgid="2497557451540954068">"세 손가락을 사용해 왼쪽 또는 오른쪽으로 스와이프하세요. 더 많은 동작을 알아보려면 탭하세요."</string>
     <string name="home_edu_notification_title" msgid="6097902076909654045">"터치패드를 사용하여 홈으로 이동"</string>
@@ -1444,8 +1449,8 @@
     <string name="overview_edu_notification_content" msgid="3578204677648432500">"세 손가락을 사용해 위로 스와이프한 다음 잠시 기다리세요. 더 많은 동작을 알아보려면 탭하세요."</string>
     <string name="all_apps_edu_notification_title" msgid="372262997265569063">"키보드를 사용하여 모든 앱 보기"</string>
     <string name="all_apps_edu_notification_content" msgid="3255070575694025585">"언제든지 작업 키를 누릅니다. 더 많은 동작을 알아보려면 탭하세요."</string>
-    <string name="accessibility_deprecate_extra_dim_dialog_title" msgid="910988771011857460">"이제 \'더 어둡게\' 기능이 밝기 슬라이더에 추가되었습니다"</string>
-    <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="4453123359258743230">"이제 밝기 수준을 더 낮춰 화면을 더 어둡게 만들 수 있습니다.\n\n이 기능은 이제 밝기 슬라이더에 포함되므로 \'더 어둡게\' 단축키가 삭제됩니다."</string>
+    <string name="accessibility_deprecate_extra_dim_dialog_title" msgid="910988771011857460">"\'더 어둡게\' 기능이 밝기 슬라이더에 추가되었습니다"</string>
+    <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="4453123359258743230">"이제 밝기 수준을 더 낮춰 화면을 더 어둡게 만들 수 있습니다.\n\n밝기 슬라이더에서 이 기능을 이용할 수 있으므로 \'더 어둡게\' 단축키가 삭제됩니다."</string>
     <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="3947537827396916005">"\'더 어둡게\' 단축키 삭제"</string>
     <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="165474092660941104">"\'더 어둡게\' 단축키가 삭제되었습니다."</string>
     <string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"연결"</string>
diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml
index 33ebf6d..80b75b9 100644
--- a/packages/SystemUI/res/values-ky/strings.xml
+++ b/packages/SystemUI/res/values-ky/strings.xml
@@ -440,7 +440,7 @@
     <string name="zen_mode_on" msgid="9085304934016242591">"Күйүк"</string>
     <string name="zen_mode_on_with_details" msgid="7416143430557895497">"Күйүк • <xliff:g id="TRIGGER_DESCRIPTION">%1$s</xliff:g>"</string>
     <string name="zen_mode_off" msgid="1736604456618147306">"Өчүк"</string>
-    <string name="zen_mode_set_up" msgid="7457957033034460064">"Тууралоо"</string>
+    <string name="zen_mode_set_up" msgid="8231201163894922821">"Туураланган эмес"</string>
     <string name="zen_mode_no_manual_invocation" msgid="1769975741344633672">"Параметрлерден тескөө"</string>
     <string name="zen_mode_active_modes" msgid="1625850411578488856">"{count,plural, =0{Жигердүү режимдер жок}=1{{mode} иштеп жатат}other{# режим иштеп жатат}}"</string>
     <string name="zen_priority_introduction" msgid="3159291973383796646">"Ойготкучтардан, эскертүүлөрдөн, жылнаамадагы иш-чараларды эстеткичтерден жана белгиленген байланыштардын чалууларынан тышкары башка үндөр жана дирилдөөлөр тынчыңызды албайт. Бирок ойнотулуп жаткан музыканы, видеолорду жана оюндарды мурдагыдай эле уга бересиз."</string>
@@ -573,8 +573,7 @@
     <string name="notification_section_header_conversations" msgid="821834744538345661">"Сүйлөшүүлөр"</string>
     <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Бардык үнсүз билдирмелерди өчүрүү"</string>
     <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"\"Тынчымды алба\" режиминде билдирмелер тындырылды"</string>
-    <!-- no translation found for modes_suppressing_shade_text (6037581130837903239) -->
-    <skip />
+    <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{Билдирмелер жок}=1{{mode} режими билдирмелерди тындырды}=2{{mode} жана дагы бир режим билдирмелерди тындырды}other{{mode} жана дагы # режим билдирмелерди тындырды}}"</string>
     <string name="media_projection_action_text" msgid="3634906766918186440">"Азыр баштоо"</string>
     <string name="empty_shade_text" msgid="8935967157319717412">"Билдирме жок"</string>
     <string name="no_unseen_notif_text" msgid="395512586119868682">"Жаңы билдирмелер жок"</string>
@@ -673,6 +672,10 @@
     <string name="stream_notification_unavailable" msgid="4313854556205836435">"Үнсүз режимде жеткиликсиз"</string>
     <string name="stream_alarm_unavailable" msgid="4059817189292197839">"\"Тынчымды алба\" режими күйүк болгондуктан, жеткиликсиз"</string>
     <string name="stream_media_unavailable" msgid="6823020894438959853">"\"Тынчымды алба\" режими күйүк болгондуктан, жеткиликсиз"</string>
+    <!-- no translation found for stream_unavailable_by_modes (3674139029490353683) -->
+    <skip />
+    <!-- no translation found for stream_unavailable_by_unknown (6908434629318171588) -->
+    <skip />
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Үнүн чыгаруу үчүн таптап коюңуз."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Дирилдөөгө коюу үчүн таптап коюңуз. Атайын мүмкүнчүлүктөр кызматынын үнүн өчүрүп койсо болот."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Үнүн өчүрүү үчүн таптап коюңуз. Атайын мүмкүнчүлүктөр кызматынын үнүн өчүрүп койсо болот."</string>
@@ -706,6 +709,7 @@
     <string name="show_demo_mode" msgid="3677956462273059726">"Демо режимин көрсөтүү"</string>
     <string name="status_bar_ethernet" msgid="5690979758988647484">"Ethernet"</string>
     <string name="status_bar_alarm" msgid="87160847643623352">"Ойготкуч"</string>
+    <string name="active_mode_content_description" msgid="1627555562186515927">"<xliff:g id="MODENAME">%1$s</xliff:g> күйүк"</string>
     <string name="wallet_title" msgid="5369767670735827105">"Капчык"</string>
     <string name="wallet_empty_state_label" msgid="7776761245237530394">"Телефонуңуз менен тез жана коопсуз сатып алуу үчүн жөндөңүз"</string>
     <string name="wallet_app_button_label" msgid="7123784239111190992">"Баарын көрсөтүү"</string>
@@ -1405,26 +1409,26 @@
     <string name="launch_touchpad_tutorial_notification_content" msgid="7931085031240753226">"Сенсордук тактадагы жаңсоолорду үйрөнүп алыңыз"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_title" msgid="1940023776496198762">"Нерселерге баскычтоп жана сенсордук такта аркылуу өтүңүз"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Сенсордук тактадагы жаңсоолор, ыкчам баскычтар жана башкалар жөнүндө билип алыңыз"</string>
-    <string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Артка кайтуу жаңсоосу"</string>
-    <string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Башкы бетке өтүү жаңсоосу"</string>
+    <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"Артка кайтуу"</string>
+    <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Башкы бетке өтүү"</string>
     <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Акыркы колдонмолорду көрүү"</string>
     <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Бүттү"</string>
     <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Артка кайтуу"</string>
-    <string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"Кайтуу үчүн сенсордук тактанын каалаган жерин үч манжаңыз менен солго же оңго сүрүңүз.\n\nОшондой эле Action + ESC баскычтарынын айкалышын колдоно аласыз."</string>
-    <string name="touchpad_back_gesture_success_title" msgid="7240576648330612171">"Азаматсыз!"</string>
+    <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"Сенсордук тактаны үч манжаңыз менен солго же оңго сүрүңүз"</string>
+    <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"Сонун!"</string>
     <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"\"Артка\" жаңсоосу боюнча үйрөткүчтү бүтүрдүңүз."</string>
     <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"Башкы бетке өтүү"</string>
-    <string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"Каалаган убакта башкы экранга өтүү үчүн экранды үч манжаңыз менен ылдыйдан жогору карай сүрүңүз."</string>
-    <string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Сонун!"</string>
-    <string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"\"Башкы бетке өтүү\" жаңсоосун үйрөндүңүз."</string>
+    <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"Сенсордук тактаны үч манжаңыз менен жогору сүрүңүз"</string>
+    <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"Азаматсыз!"</string>
+    <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"\"Башкы бетке өтүү\" жаңсоосун үйрөндүңүз"</string>
     <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"Акыркы колдонмолорду көрүү"</string>
-    <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"Сенсордук тактаны үч манжаңыз менен өйдө сүрүп, кармап туруңуз."</string>
+    <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"Сенсордук тактаны үч манжаңыз менен өйдө сүрүп, кармап туруңуз"</string>
     <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Азаматсыз!"</string>
     <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Акыркы колдонмолорду көрүү жаңсоосун аткардыңыз."</string>
-    <string name="tutorial_action_key_title" msgid="2659466586996495447">"Аракет баскычы"</string>
-    <string name="tutorial_action_key_guidance" msgid="5718948664616999196">"Бардык колдонмолоруңузду көрүү үчүн баскычтобуңуздагы аракет баскычын басыңыз"</string>
-    <string name="tutorial_action_key_success_title" msgid="466467860120112933">"Куттуктайбыз!"</string>
-    <string name="tutorial_action_key_success_body" msgid="7201991081652850430">"Аракет баскычынын жаңсоосун аткардыңыз.\n\n+ / аракети бардык жеткиликтүү ыкчам баскычтарды көрсөтөт."</string>
+    <string name="tutorial_action_key_title" msgid="8172535792469008169">"Бардык колдонмолорду көрүү"</string>
+    <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Баскычтобуңуздагы аракет баскычын басыңыз"</string>
+    <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Эң жакшы!"</string>
+    <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Бардык колдонмолорду көрүү жаңсоосун аткардыңыз"</string>
     <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Баскычтоптун жарыгы"</string>
     <string name="keyboard_backlight_value" msgid="7336398765584393538">"%2$d ичинен %1$d-деңгээл"</string>
     <string name="home_controls_dream_label" msgid="6567105701292324257">"Үйдөгү түзмөктөрдү тескөө"</string>
@@ -1436,6 +1440,7 @@
     <string name="all_apps_edu_toast_content" msgid="8807496014667211562">"Бардык колдонмолоруңузду көрүү үчүн баскычтобуңуздагы аракет баскычын басыңыз"</string>
     <string name="redacted_notification_single_line_title" msgid="212019960919261670">"Жашырылды"</string>
     <string name="redacted_notification_single_line_text" msgid="8684166405005242945">"Көрүү үчүн кулпусун ачыңыз"</string>
+    <string name="contextual_education_dialog_title" msgid="4630392552837487324">"Контексттик билим берүү"</string>
     <string name="back_edu_notification_title" msgid="5624780717751357278">"Артка кайтуу үчүн сенсордук тактаны колдонуңуз"</string>
     <string name="back_edu_notification_content" msgid="2497557451540954068">"Үч манжаңыз менен солго же оңго сүрүңүз. Башка жаңсоолорду үйрөнүү үчүн таптаңыз."</string>
     <string name="home_edu_notification_title" msgid="6097902076909654045">"Башкы бетке өтүү үчүн сенсордук тактаны колдонуңуз"</string>
@@ -1445,7 +1450,7 @@
     <string name="all_apps_edu_notification_title" msgid="372262997265569063">"Бардык колдонмолорду көрүү үчүн баскычтобуңузду колдонуңуз"</string>
     <string name="all_apps_edu_notification_content" msgid="3255070575694025585">"Каалаганда аракет баскычын басыңыз. Башка жаңсоолорду үйрөнүү үчүн таптаңыз."</string>
     <string name="accessibility_deprecate_extra_dim_dialog_title" msgid="910988771011857460">"Кошумча караңгылатуу эми жарыктык сыдырмасында жайгашкан"</string>
-    <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="4453123359258743230">"Эми экрандын жарыктыктыгынын деңгээлин азайтып, экранды кошумча караңгылата аласыз.\n\nБул функция эми жарыктык сыдырмасынын бир бөлүгү болуп калгандыктан, кошумча караңгылатуунун ыкчам баскычтары өтүрүлөт."</string>
+    <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="4453123359258743230">"Эми экрандын жарыктыктыгынын деңгээлин азайтып, аны кошумча караңгылата аласыз.\n\nБул функция эми жарыктык сыдырмасынын бир бөлүгү болуп калгандыктан, кошумча караңгылатуунун ыкчам баскычтары өчүрүлөт."</string>
     <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="3947537827396916005">"Кошумча караңгылатуу ыкчам баскычтарын өчүрүү"</string>
     <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="165474092660941104">"Кошумча караңгылатуу ыкчам баскычтары өчүрүлдү"</string>
     <string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"Байланыш"</string>
diff --git a/packages/SystemUI/res/values-land/config.xml b/packages/SystemUI/res/values-land/config.xml
index db526b1..b5efeb5 100644
--- a/packages/SystemUI/res/values-land/config.xml
+++ b/packages/SystemUI/res/values-land/config.xml
@@ -25,6 +25,9 @@
 
     <integer name="quick_settings_num_columns">4</integer>
 
+    <!-- The number of columns in the infinite grid QuickSettings -->
+    <integer name="quick_settings_infinite_grid_num_columns">8</integer>
+
     <!-- The number of columns that the top level tiles span in the QuickSettings -->
     <integer name="quick_settings_user_time_settings_tile_span">2</integer>
 
diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml
index 410f7d5..3a09b2a 100644
--- a/packages/SystemUI/res/values-lo/strings.xml
+++ b/packages/SystemUI/res/values-lo/strings.xml
@@ -440,7 +440,7 @@
     <string name="zen_mode_on" msgid="9085304934016242591">"ເປີດ"</string>
     <string name="zen_mode_on_with_details" msgid="7416143430557895497">"ເປີດ • <xliff:g id="TRIGGER_DESCRIPTION">%1$s</xliff:g>"</string>
     <string name="zen_mode_off" msgid="1736604456618147306">"ປິດ"</string>
-    <string name="zen_mode_set_up" msgid="7457957033034460064">"ຕັ້ງຄ່າ"</string>
+    <string name="zen_mode_set_up" msgid="8231201163894922821">"ຍັງບໍ່ໄດ້ຕັ້ງ"</string>
     <string name="zen_mode_no_manual_invocation" msgid="1769975741344633672">"ຈັດການໃນການຕັ້ງຄ່າ"</string>
     <string name="zen_mode_active_modes" msgid="1625850411578488856">"{count,plural, =0{ບໍ່ມີໂໝດທີ່ເຮັດວຽກຢູ່}=1{{mode} ເຮັດວຽກຢູ່}other{# ໂໝດເຮັດວຽກຢູ່}}"</string>
     <string name="zen_priority_introduction" msgid="3159291973383796646">"ທ່ານຈະບໍ່ໄດ້ຮັບການລົບກວນຈາກສຽງ ແລະ ການສັ່ນເຕືອນ, ຍົກເວັ້ນໃນເວລາໂມງປຸກດັງ, ມີການແຈ້ງເຕືອນ ຫຼື ມີສາຍໂທເຂົ້າຈາກຜູ້ໂທທີ່ທ່ານລະບຸໄວ້. ທ່ານອາດຍັງຄົງໄດ້ຍິນຫາກທ່ານເລືອກຫຼິ້ນເພງ, ວິດີໂອ ແລະ ເກມ."</string>
@@ -573,8 +573,7 @@
     <string name="notification_section_header_conversations" msgid="821834744538345661">"ການສົນທະນາ"</string>
     <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"ລຶບລ້າງການແຈ້ງເຕືອນແບບງຽບທັງໝົດ"</string>
     <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"ຢຸດການແຈ້ງເຕືອນໂດຍໂໝດຫ້າມລົບກວນແລ້ວ"</string>
-    <!-- no translation found for modes_suppressing_shade_text (6037581130837903239) -->
-    <skip />
+    <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{ບໍ່ມີການແຈ້ງເຕືອນ}=1{{mode} ຢຸດການແຈ້ງເຕືອນໄວ້ຊົ່ວຄາວ}=2{{mode} ແລະ ອີກ 1 ໂໝດຢຸດການແຈ້ງເຕືອນໄວ້ຊົ່ວຄາວ}other{{mode} ແລະ ອີກ # ໂໝດຢຸດການແຈ້ງເຕືອນໄວ້ຊົ່ວຄາວ}}"</string>
     <string name="media_projection_action_text" msgid="3634906766918186440">"ເລີ່ມດຽວນີ້"</string>
     <string name="empty_shade_text" msgid="8935967157319717412">"ບໍ່ມີການແຈ້ງເຕືອນ"</string>
     <string name="no_unseen_notif_text" msgid="395512586119868682">"ບໍ່ມີການແຈ້ງເຕືອນໃໝ່"</string>
@@ -673,6 +672,10 @@
     <string name="stream_notification_unavailable" msgid="4313854556205836435">"ບໍ່ມີໃຫ້ໃຊ້ເນື່ອງຈາກມີການປິດສຽງໂທເຂົ້າ"</string>
     <string name="stream_alarm_unavailable" msgid="4059817189292197839">"ບໍ່ມີໃຫ້ຍ້ອນວ່າຫ້າມລົບກວນເປີດຢູ່"</string>
     <string name="stream_media_unavailable" msgid="6823020894438959853">"ບໍ່ມີໃຫ້ຍ້ອນວ່າຫ້າມລົບກວນເປີດຢູ່"</string>
+    <!-- no translation found for stream_unavailable_by_modes (3674139029490353683) -->
+    <skip />
+    <!-- no translation found for stream_unavailable_by_unknown (6908434629318171588) -->
+    <skip />
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. ແຕະເພື່ອເຊົາປິດສຽງ."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. ແຕະເພື່ອຕັ້ງເປັນສັ່ນ. ບໍລິການຊ່ວຍເຂົ້າເຖິງອາດຖືກປິດສຽງໄວ້."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. ແຕະເພື່ອປິດສຽງ. ບໍລິການຊ່ວຍເຂົ້າເຖິງອາດຖືກປິດສຽງໄວ້."</string>
@@ -706,6 +709,7 @@
     <string name="show_demo_mode" msgid="3677956462273059726">"ສະ​ແດງ​ໂຫມດ​ສາ​ທິດ"</string>
     <string name="status_bar_ethernet" msgid="5690979758988647484">"ອີ​ເທ​ເນັດ"</string>
     <string name="status_bar_alarm" msgid="87160847643623352">"ໂມງປຸກ"</string>
+    <string name="active_mode_content_description" msgid="1627555562186515927">"<xliff:g id="MODENAME">%1$s</xliff:g> ເປີດຢູ່"</string>
     <string name="wallet_title" msgid="5369767670735827105">"Wallet"</string>
     <string name="wallet_empty_state_label" msgid="7776761245237530394">"ຕັ້ງຄ່າເພື່ອຊື້ດ້ວຍໂທລະສັບຂອງທ່ານໄດ້ໄວຂຶ້ນ ແລະ ປອດໄພຂຶ້ນ"</string>
     <string name="wallet_app_button_label" msgid="7123784239111190992">"ສະແດງທັງໝົດ"</string>
@@ -1405,26 +1409,26 @@
     <string name="launch_touchpad_tutorial_notification_content" msgid="7931085031240753226">"ສຶກສາທ່າທາງຂອງແຜ່ນສຳຜັດ"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_title" msgid="1940023776496198762">"ນຳທາງໂດຍໃຊ້ແປ້ນພິມ ແລະ ແຜ່ນສຳຜັດຂອງທ່ານ"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"ສຶກສາທ່າທາງຂອງແຜ່ນສຳຜັດ, ຄີລັດ ແລະ ອື່ນໆ"</string>
-    <string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"ທ່າທາງສຳລັບກັບຄືນ"</string>
-    <string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"ທ່າທາງສຳລັບໜ້າຫຼັກ"</string>
+    <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"ກັບຄືນ"</string>
+    <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"ໄປຫາໜ້າຫຼັກ"</string>
     <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"ເບິ່ງແອັບຫຼ້າສຸດ"</string>
     <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"ແລ້ວໆ"</string>
     <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"ກັບຄືນ"</string>
-    <string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"ເພື່ອກັບຄືນ, ໃຫ້ໃຊ້ 3 ນິ້ວປັດຊ້າຍ ຫຼື ຂວາບ່ອນໃດກໍໄດ້ເທິງແຜ່ນສຳຜັດ.\n\nທ່ານຍັງສາມາດໃຊ້ຄຳສັ່ງຄີລັດ + ESC ສຳລັບການດຳເນີນການນີ້ໄດ້ນຳ."</string>
-    <string name="touchpad_back_gesture_success_title" msgid="7240576648330612171">"ເກັ່ງຫຼາຍ!"</string>
+    <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"ປັດຊ້າຍ ຫຼື ຂວາໂດຍໃຊ້ມືສາມນິ້ວຢູ່ແຜ່ນສໍາຜັດຂອງທ່ານ"</string>
+    <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"ດີ!"</string>
     <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"ທ່ານໃຊ້ທ່າທາງກັບຄືນສຳເລັດແລ້ວ."</string>
     <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"ໄປຫາໜ້າຫຼັກ"</string>
-    <string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"ເພື່ອໄປຫາໜ້າຫຼັກຂອງທ່ານຕອນໃດກໍໄດ້, ໃຫ້ປັດຂຶ້ນດ້ວຍສາມນິ້ວຈາກລຸ່ມສຸດຂອງໜ້າຈໍຂອງທ່ານ."</string>
-    <string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"ດີຫຼາຍ!"</string>
-    <string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"ທ່ານໃຊ້ທ່າທາງໄປໜ້າຫຼັກສຳເລັດແລ້ວ."</string>
+    <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"ປັດຂຶ້ນໂດຍໃຊ້ມືສາມນິ້ວຢູ່ແຜ່ນສໍາຜັດຂອງທ່ານ"</string>
+    <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"ດີຫຼາຍ!"</string>
+    <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"ທ່ານໃຊ້ທ່າທາງໄປໜ້າຫຼັກສຳເລັດແລ້ວ"</string>
     <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"ເບິ່ງແອັບຫຼ້າສຸດ"</string>
-    <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"ໃຊ້ 3 ນິ້ວປັດຂຶ້ນແລ້ວຄ້າງໄວ້ຢູ່ແຜ່ນສໍາຜັດຂອງທ່ານ."</string>
+    <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"ປັດຂຶ້ນໂດຍໃຊ້ມືສາມນິ້ວແລ້ວຄ້າງໄວ້ຢູ່ແຜ່ນສໍາຜັດຂອງທ່ານ"</string>
     <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"ດີຫຼາຍ!"</string>
     <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"ທ່ານເບິ່ງທ່າທາງຂອງແອັບຫຼ້າສຸດສຳເລັດແລ້ວ."</string>
-    <string name="tutorial_action_key_title" msgid="2659466586996495447">"ປຸ່ມຄຳສັ່ງ"</string>
-    <string name="tutorial_action_key_guidance" msgid="5718948664616999196">"ເພື່ອເຂົ້າເຖິງແອັບ, ໃຫ້ກົດປຸ່ມຄຳສັ່ງຢູ່ແປ້ນພິມຂອງທ່ານ."</string>
-    <string name="tutorial_action_key_success_title" msgid="466467860120112933">"ຂໍສະແດງຄວາມຍິນດີ!"</string>
-    <string name="tutorial_action_key_success_body" msgid="7201991081652850430">"ທ່ານໃຊ້ທ່າທາງປຸ່ມຄຳສັ່ງສໍາເລັດແລ້ວ.\n\nຄໍາສັ່ງ + / ຈະສະແດງທາງລັດທັງໝົດທີ່ທ່ານມີ."</string>
+    <string name="tutorial_action_key_title" msgid="8172535792469008169">"ເບິ່ງແອັບທັງໝົດ"</string>
+    <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"ກົດປຸ່ມຄຳສັ່ງຢູ່ແປ້ນພິມຂອງທ່ານ"</string>
+    <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"ດີຫຼາຍ!"</string>
+    <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"ທ່ານເບິ່ງທ່າທາງຂອງແອັບທັງໝົດສຳເລັດແລ້ວ"</string>
     <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"ໄຟປຸ່ມແປ້ນພິມ"</string>
     <string name="keyboard_backlight_value" msgid="7336398765584393538">"ລະດັບທີ %1$d ຈາກ %2$d"</string>
     <string name="home_controls_dream_label" msgid="6567105701292324257">"ການຄວບຄຸມເຮືອນ"</string>
@@ -1436,6 +1440,7 @@
     <string name="all_apps_edu_toast_content" msgid="8807496014667211562">"ເພື່ອເບິ່ງແອັບທັງໝົດຂອງທ່ານ, ໃຫ້ກົດປຸ່ມຄຳສັ່ງຢູ່ແປ້ນພິມຂອງທ່ານ"</string>
     <string name="redacted_notification_single_line_title" msgid="212019960919261670">"ປົກປິດໄວ້ແລ້ວ"</string>
     <string name="redacted_notification_single_line_text" msgid="8684166405005242945">"ປົດລັອກເພື່ອເບິ່ງ"</string>
+    <string name="contextual_education_dialog_title" msgid="4630392552837487324">"ການສຶກສາຕາມບໍລິບົດ"</string>
     <string name="back_edu_notification_title" msgid="5624780717751357278">"ໃຊ້ແຜ່ນສໍາຜັດຂອງທ່ານເພື່ອກັບຄືນ"</string>
     <string name="back_edu_notification_content" msgid="2497557451540954068">"ໃຊ້ 3 ນິ້ວປັດຊ້າຍ ຫຼື ຂວາ. ແຕະເພື່ອສຶກສາທ່າທາງເພີ່ມເຕີມ."</string>
     <string name="home_edu_notification_title" msgid="6097902076909654045">"ໃຊ້ແຜ່ນສໍາຜັດຂອງທ່ານເພື່ອໄປຫາໜ້າຫຼັກ"</string>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index 67ead23..f3f383e 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -440,7 +440,7 @@
     <string name="zen_mode_on" msgid="9085304934016242591">"Įjungta"</string>
     <string name="zen_mode_on_with_details" msgid="7416143430557895497">"Įjungta • <xliff:g id="TRIGGER_DESCRIPTION">%1$s</xliff:g>"</string>
     <string name="zen_mode_off" msgid="1736604456618147306">"Išjungta"</string>
-    <string name="zen_mode_set_up" msgid="7457957033034460064">"Nustatyti"</string>
+    <string name="zen_mode_set_up" msgid="8231201163894922821">"Nenustatyta"</string>
     <string name="zen_mode_no_manual_invocation" msgid="1769975741344633672">"Tvarkyti skiltyje „Nustatymai“"</string>
     <string name="zen_mode_active_modes" msgid="1625850411578488856">"{count,plural, =0{Nėra aktyvių režimų}=1{Aktyvus režimas „{mode}“}one{# aktyvus režimas}few{# aktyvūs režimai}many{# aktyvaus režimo}other{# aktyvių režimų}}"</string>
     <string name="zen_priority_introduction" msgid="3159291973383796646">"Jūsų netrikdys garsai ir vibravimas, išskyrus nurodytų signalų, priminimų, įvykių ir skambintojų garsus. Vis tiek girdėsite viską, ką pasirinksite leisti, įskaitant muziką, vaizdo įrašus ir žaidimus."</string>
@@ -573,8 +573,7 @@
     <string name="notification_section_header_conversations" msgid="821834744538345661">"Pokalbiai"</string>
     <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Išvalyti visus tylius pranešimus"</string>
     <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Pranešimai pristabdyti naudojant netrukdymo režimą"</string>
-    <!-- no translation found for modes_suppressing_shade_text (6037581130837903239) -->
-    <skip />
+    <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{Nėra pranešimų}=1{Pranešimai pristabdyti naudojant režimą „{mode}“}=2{Pranešimai pristabdyti naudojant režimą „{mode}“ ir dar vieną režimą}one{Pranešimai pristabdyti naudojant režimą „{mode}“ ir dar # režimą}few{Pranešimai pristabdyti naudojant režimą „{mode}“ ir dar # režimus}many{Pranešimai pristabdyti naudojant režimą „{mode}“ ir dar # režimo}other{Pranešimai pristabdyti naudojant režimą „{mode}“ ir dar # režimų}}"</string>
     <string name="media_projection_action_text" msgid="3634906766918186440">"Pradėti dabar"</string>
     <string name="empty_shade_text" msgid="8935967157319717412">"Nėra įspėjimų"</string>
     <string name="no_unseen_notif_text" msgid="395512586119868682">"Naujų pranešimų nėra"</string>
@@ -673,6 +672,10 @@
     <string name="stream_notification_unavailable" msgid="4313854556205836435">"Nepasiekiama, nes skambutis nutildytas"</string>
     <string name="stream_alarm_unavailable" msgid="4059817189292197839">"Nepasiekiama, nes įjungtas netrukdymo režimas"</string>
     <string name="stream_media_unavailable" msgid="6823020894438959853">"Nepasiekiama, nes įjungtas netrukdymo režimas"</string>
+    <!-- no translation found for stream_unavailable_by_modes (3674139029490353683) -->
+    <skip />
+    <!-- no translation found for stream_unavailable_by_unknown (6908434629318171588) -->
+    <skip />
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Palieskite, kad įjungtumėte garsą."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Palieskite, kad nustatytumėte vibravimą. Gali būti nutildytos pritaikymo neįgaliesiems paslaugos."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Palieskite, kad nutildytumėte. Gali būti nutildytos pritaikymo neįgaliesiems paslaugos."</string>
@@ -706,6 +709,7 @@
     <string name="show_demo_mode" msgid="3677956462273059726">"Rodyti demonstraciniu režimu"</string>
     <string name="status_bar_ethernet" msgid="5690979758988647484">"Eternetas"</string>
     <string name="status_bar_alarm" msgid="87160847643623352">"Signalas"</string>
+    <string name="active_mode_content_description" msgid="1627555562186515927">"Tvarkaraštis „<xliff:g id="MODENAME">%1$s</xliff:g>“ įjungtas"</string>
     <string name="wallet_title" msgid="5369767670735827105">"Wallet"</string>
     <string name="wallet_empty_state_label" msgid="7776761245237530394">"Nustatykite, kad galėtumėte greičiau ir saugiau pirkti telefonu"</string>
     <string name="wallet_app_button_label" msgid="7123784239111190992">"Rodyti viską"</string>
@@ -1405,26 +1409,26 @@
     <string name="launch_touchpad_tutorial_notification_content" msgid="7931085031240753226">"Sužinokite jutiklinės dalies gestus"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_title" msgid="1940023776496198762">"Naršykite naudodamiesi klaviatūra ir jutikline dalimi"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Sužinokite jutiklinės dalies gestus, sparčiuosius klavišus ir kt."</string>
-    <string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Grįžimo atgal gestas"</string>
-    <string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Pagrindinio ekrano gestas"</string>
+    <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"Grįžti"</string>
+    <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Eikite į pagrindinį puslapį"</string>
     <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Peržiūrėti naujausias programas"</string>
     <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Atlikta"</string>
     <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Grįžti"</string>
-    <string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"Jei norite grįžti, perbraukite kairėn arba dešinėn trimis pirštais bet kurioje jutiklinės dalies vietoje.\n\nTaip pat galite naudoti šį spartųjį klavišą: veiksmų klavišas + klavišas „Esc“."</string>
-    <string name="touchpad_back_gesture_success_title" msgid="7240576648330612171">"Puiku!"</string>
+    <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"Braukite kairėn arba dešinėn trimis pirštais bet kur jutiklinėje dalyje"</string>
+    <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"Šaunu!"</string>
     <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"Atlikote grįžimo atgal gestą."</string>
     <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"Eikite į pagrindinį ekraną"</string>
-    <string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"Jei norite bet kada pasiekti pagrindinį ekraną, perbraukite aukštyn trim pirštais iš ekrano apačios."</string>
-    <string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Šaunu!"</string>
-    <string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Atlikote perėjimo į pagrindinį ekraną gestą."</string>
+    <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"Braukite viršun trimis pirštais bet kur jutiklinėje dalyje"</string>
+    <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"Puiku!"</string>
+    <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"Atlikote perėjimo į pagrindinį ekraną gestą"</string>
     <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"Peržiūrėti naujausias programas"</string>
-    <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"Jutiklinėje dalyje perbraukite aukštyn trimis pirštais ir palaikykite."</string>
+    <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"Braukite viršun trimis pirštais bet kur jutiklinėje dalyje ir palaikykite"</string>
     <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Puiku!"</string>
     <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Atlikote naujausių programų peržiūros gestą."</string>
-    <string name="tutorial_action_key_title" msgid="2659466586996495447">"Veiksmų klavišas"</string>
-    <string name="tutorial_action_key_guidance" msgid="5718948664616999196">"Jei norite pasiekti programas, paspauskite klaviatūros veiksmų klavišą."</string>
-    <string name="tutorial_action_key_success_title" msgid="466467860120112933">"Sveikiname!"</string>
-    <string name="tutorial_action_key_success_body" msgid="7201991081652850430">"Atlikote veiksmų klavišo gestą.\n\nVeiksmas + / rodo visus pasiekiamus sparčiuosius klavišus."</string>
+    <string name="tutorial_action_key_title" msgid="8172535792469008169">"Žr. visas programas"</string>
+    <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Paspauskite klaviatūros veiksmų klavišą"</string>
+    <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Puikiai padirbėta!"</string>
+    <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Atlikote visų programų peržiūros gestą"</string>
     <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Klaviatūros foninis apšvietimas"</string>
     <string name="keyboard_backlight_value" msgid="7336398765584393538">"%1$d lygis iš %2$d"</string>
     <string name="home_controls_dream_label" msgid="6567105701292324257">"Namų sistemos valdymas"</string>
@@ -1436,6 +1440,7 @@
     <string name="all_apps_edu_toast_content" msgid="8807496014667211562">"Jei norite peržiūrėti visas programas, paspauskite klaviatūros veiksmų klavišą"</string>
     <string name="redacted_notification_single_line_title" msgid="212019960919261670">"Paslėpta"</string>
     <string name="redacted_notification_single_line_text" msgid="8684166405005242945">"Atrakinkite, kad peržiūrėtumėte"</string>
+    <string name="contextual_education_dialog_title" msgid="4630392552837487324">"Kontekstinis švietimas"</string>
     <string name="back_edu_notification_title" msgid="5624780717751357278">"Naudokite klaviatūrą, kad grįžtumėte atgal"</string>
     <string name="back_edu_notification_content" msgid="2497557451540954068">"Perbraukite į kairę ar dešinę trimis pirštais. Palieskite, kad sužinotumėte daugiau gestų."</string>
     <string name="home_edu_notification_title" msgid="6097902076909654045">"Naudokite jutiklinę dalį, jei norite eiti į pagrindinį ekraną"</string>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index 53e0baa..9c22eed 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -440,7 +440,7 @@
     <string name="zen_mode_on" msgid="9085304934016242591">"Ieslēgts"</string>
     <string name="zen_mode_on_with_details" msgid="7416143430557895497">"Ieslēgts • <xliff:g id="TRIGGER_DESCRIPTION">%1$s</xliff:g>"</string>
     <string name="zen_mode_off" msgid="1736604456618147306">"Izslēgts"</string>
-    <string name="zen_mode_set_up" msgid="7457957033034460064">"Iestatīt"</string>
+    <string name="zen_mode_set_up" msgid="8231201163894922821">"Nav iestatīts"</string>
     <string name="zen_mode_no_manual_invocation" msgid="1769975741344633672">"Pārvaldīt iestatījumos"</string>
     <string name="zen_mode_active_modes" msgid="1625850411578488856">"{count,plural, =0{Nav aktīvu režīmu}=1{Režīms “{mode}” ir aktīvs}zero{# režīmi ir aktīvi}one{# režīms ir aktīvs}other{# režīmi ir aktīvi}}"</string>
     <string name="zen_priority_introduction" msgid="3159291973383796646">"Jūs netraucēs skaņas un vibrācija, izņemot signālus, atgādinājumus, pasākumus un zvanītājus, ko būsiet norādījis. Jūs joprojām dzirdēsiet atskaņošanai izvēlētos vienumus, tostarp mūziku, videoklipus un spēles."</string>
@@ -573,8 +573,7 @@
     <string name="notification_section_header_conversations" msgid="821834744538345661">"Sarunas"</string>
     <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Notīrīt visus klusos paziņojumus"</string>
     <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Paziņojumi pārtraukti, izmantojot iestatījumu “Netraucēt”"</string>
-    <!-- no translation found for modes_suppressing_shade_text (6037581130837903239) -->
-    <skip />
+    <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{Nav paziņojumu}=1{Paziņojumu rādīšana ir pārtraukta režīma “{mode}” dēļ}=2{Paziņojumu rādīšana ir pārtraukta režīma “{mode}” un vēl viena režīma dēļ}zero{Paziņojumu rādīšana ir pārtraukta režīma “{mode}” un vēl # režīmu dēļ}one{Paziņojumu rādīšana ir pārtraukta režīma “{mode}” un vēl # režīma dēļ}other{Paziņojumu rādīšana ir pārtraukta režīma “{mode}” un vēl # režīmu dēļ}}"</string>
     <string name="media_projection_action_text" msgid="3634906766918186440">"Sākt tūlīt"</string>
     <string name="empty_shade_text" msgid="8935967157319717412">"Nav paziņojumu"</string>
     <string name="no_unseen_notif_text" msgid="395512586119868682">"Nav jaunu paziņojumu"</string>
@@ -673,6 +672,10 @@
     <string name="stream_notification_unavailable" msgid="4313854556205836435">"Nevar mainīt, jo izslēgts skaņas signāls"</string>
     <string name="stream_alarm_unavailable" msgid="4059817189292197839">"Nav pieejams, jo ir ieslēgts režīms Netraucēt"</string>
     <string name="stream_media_unavailable" msgid="6823020894438959853">"Nav pieejams, jo ir ieslēgts režīms Netraucēt"</string>
+    <!-- no translation found for stream_unavailable_by_modes (3674139029490353683) -->
+    <skip />
+    <!-- no translation found for stream_unavailable_by_unknown (6908434629318171588) -->
+    <skip />
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Pieskarieties, lai ieslēgtu skaņu."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Pieskarieties, lai iestatītu uz vibrozvanu. Var tikt izslēgti pieejamības pakalpojumu signāli."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Pieskarieties, lai izslēgtu skaņu. Var tikt izslēgti pieejamības pakalpojumu signāli."</string>
@@ -706,6 +709,7 @@
     <string name="show_demo_mode" msgid="3677956462273059726">"Rādīt demonstrācijas režīmu"</string>
     <string name="status_bar_ethernet" msgid="5690979758988647484">"Tīkls Ethernet"</string>
     <string name="status_bar_alarm" msgid="87160847643623352">"Signāls"</string>
+    <string name="active_mode_content_description" msgid="1627555562186515927">"Režīms “<xliff:g id="MODENAME">%1$s</xliff:g>” ir ieslēgts"</string>
     <string name="wallet_title" msgid="5369767670735827105">"Maks"</string>
     <string name="wallet_empty_state_label" msgid="7776761245237530394">"Iestatiet, lai ātrāk un drošāk veiktu pirkumus, izmantojot tālruni"</string>
     <string name="wallet_app_button_label" msgid="7123784239111190992">"Rādīt visu"</string>
@@ -1405,26 +1409,26 @@
     <string name="launch_touchpad_tutorial_notification_content" msgid="7931085031240753226">"Apgūstiet skārienpaliktņa žestus."</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_title" msgid="1940023776496198762">"Pārvietošanās, izmantojot tastatūru un skārienpaliktni"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Uzziniet par skārienpaliktņa žestiem, īsinājumtaustiņiem un citām iespējām."</string>
-    <string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Žests pāriešanai atpakaļ"</string>
-    <string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Žests pāriešanai uz sākumu"</string>
+    <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"Atpakaļ"</string>
+    <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Pāriet uz sākuma ekrānu"</string>
     <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Skatīt nesen izmantotās lietotnes"</string>
     <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Gatavs"</string>
     <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Atpakaļ"</string>
-    <string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"Lai atgrieztos, ar trīs pirkstiem velciet pa kreisi vai pa labi jebkurā vietā uz skārienpaliktņa.\n\nVarat arī izmantot šim nolūkam īsinājumtaustiņus: darbību taustiņu + Esc."</string>
-    <string name="touchpad_back_gesture_success_title" msgid="7240576648330612171">"Lieliski!"</string>
+    <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"Skārienpaliktnī ar trīs pirkstiem velciet pa kreisi vai pa labi."</string>
+    <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"Lieliski!"</string>
     <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"Jūs sekmīgi veicāt atgriešanās žestu."</string>
     <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"Pāreja uz sākuma ekrānu"</string>
-    <string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"Lai jebkurā brīdī pārietu uz sākuma ekrānu, ar trim pirkstiem velciet augšup no ekrāna apakšdaļas."</string>
-    <string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Lieliski!"</string>
-    <string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Jūs sekmīgi veicāt sākuma ekrāna atvēršanas žestu."</string>
+    <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"Skārienpaliktnī ar trīs pirkstiem velciet augšup."</string>
+    <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"Lieliski!"</string>
+    <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"Jūs sekmīgi veicāt sākuma ekrāna atvēršanas žestu."</string>
     <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"Nesen izmantoto lietotņu skatīšana"</string>
-    <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"Skārienpaliktnī ar trīs pirkstiem velciet augšup un turiet."</string>
+    <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"Skārienpaliktnī ar trīs pirkstiem velciet augšup un turiet."</string>
     <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Lieliski!"</string>
     <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Jūs sekmīgi veicāt nesen izmantoto lietotņu skatīšanas žestu."</string>
-    <string name="tutorial_action_key_title" msgid="2659466586996495447">"Darbību taustiņš"</string>
-    <string name="tutorial_action_key_guidance" msgid="5718948664616999196">"Lai piekļūtu savām lietotnēm, tastatūrā nospiediet darbību taustiņu."</string>
-    <string name="tutorial_action_key_success_title" msgid="466467860120112933">"Apsveicam!"</string>
-    <string name="tutorial_action_key_success_body" msgid="7201991081652850430">"Jūs pabeidzāt darbību taustiņa žesta apmācību.\n\nNospiežot darbību taustiņu un taustiņu “/”, tiks parādīti visi pieejamie īsinājumtaustiņi."</string>
+    <string name="tutorial_action_key_title" msgid="8172535792469008169">"Skatīt visas lietotnes"</string>
+    <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Tastatūrā nospiediet darbību taustiņu."</string>
+    <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Lieliski!"</string>
+    <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Jūs sekmīgi veicāt visu lietotņu skatīšanas žestu."</string>
     <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Tastatūras fona apgaismojums"</string>
     <string name="keyboard_backlight_value" msgid="7336398765584393538">"Līmenis numur %1$d, kopā ir %2$d"</string>
     <string name="home_controls_dream_label" msgid="6567105701292324257">"Mājas kontrolierīces"</string>
@@ -1436,6 +1440,7 @@
     <string name="all_apps_edu_toast_content" msgid="8807496014667211562">"Lai skatītu visas savas lietotnes, tastatūrā nospiediet darbību taustiņu."</string>
     <string name="redacted_notification_single_line_title" msgid="212019960919261670">"Rediģēts"</string>
     <string name="redacted_notification_single_line_text" msgid="8684166405005242945">"Lai skatītu, atbloķējiet"</string>
+    <string name="contextual_education_dialog_title" msgid="4630392552837487324">"Kontekstuāla pamācība"</string>
     <string name="back_edu_notification_title" msgid="5624780717751357278">"Atgriešanās, izmantojot skārienpaliktni"</string>
     <string name="back_edu_notification_content" msgid="2497557451540954068">"Ar trīs pirkstiem velciet pa kreisi vai pa labi. Lai apgūtu citus žestus, pieskarieties šeit."</string>
     <string name="home_edu_notification_title" msgid="6097902076909654045">"Pāriešana uz sākuma ekrānu, izmantojot skārienpaliktni"</string>
diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml
index 86c93ac..6e37907 100644
--- a/packages/SystemUI/res/values-mk/strings.xml
+++ b/packages/SystemUI/res/values-mk/strings.xml
@@ -440,7 +440,8 @@
     <string name="zen_mode_on" msgid="9085304934016242591">"Вклучено"</string>
     <string name="zen_mode_on_with_details" msgid="7416143430557895497">"Вклучено: <xliff:g id="TRIGGER_DESCRIPTION">%1$s</xliff:g>"</string>
     <string name="zen_mode_off" msgid="1736604456618147306">"Исклучено"</string>
-    <string name="zen_mode_set_up" msgid="7457957033034460064">"Поставете"</string>
+    <!-- no translation found for zen_mode_set_up (8231201163894922821) -->
+    <skip />
     <string name="zen_mode_no_manual_invocation" msgid="1769975741344633672">"Управувајте во поставките"</string>
     <string name="zen_mode_active_modes" msgid="1625850411578488856">"{count,plural, =0{Нема активни режими}=1{Активен е {mode}}one{Активни се # режим}other{Активни се # режими}}"</string>
     <string name="zen_priority_introduction" msgid="3159291973383796646">"Нема да ве вознемируваат звуци и вибрации, освен од аларми, потсетници, настани и повикувачи што ќе ги наведете. Сѐ уште ќе слушате сѐ што ќе изберете да пуштите, како музика, видеа и игри."</string>
@@ -573,8 +574,7 @@
     <string name="notification_section_header_conversations" msgid="821834744538345661">"Разговори"</string>
     <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Избриши ги сите бесчујни известувања"</string>
     <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Известувањата се паузирани од „Не вознемирувај“"</string>
-    <!-- no translation found for modes_suppressing_shade_text (6037581130837903239) -->
-    <skip />
+    <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{Нема известувања}=1{Известувањата ги паузираше {mode}}=2{Известувањата ги паузираа {mode} и уште еден режим}one{Известувањата ги паузираа {mode} и уште # режим}other{Известувањата ги паузираа {mode} и уште # режими}}"</string>
     <string name="media_projection_action_text" msgid="3634906766918186440">"Започни сега"</string>
     <string name="empty_shade_text" msgid="8935967157319717412">"Нема известувања"</string>
     <string name="no_unseen_notif_text" msgid="395512586119868682">"Нема нови известувања"</string>
@@ -673,6 +673,10 @@
     <string name="stream_notification_unavailable" msgid="4313854556205836435">"Недостапно бидејќи звукот е исклучен"</string>
     <string name="stream_alarm_unavailable" msgid="4059817189292197839">"Недостапно бидејќи е вклучено „Не вознемирувај“"</string>
     <string name="stream_media_unavailable" msgid="6823020894438959853">"Недостапно бидејќи е вклучено „Не вознемирувај“"</string>
+    <!-- no translation found for stream_unavailable_by_modes (3674139029490353683) -->
+    <skip />
+    <!-- no translation found for stream_unavailable_by_unknown (6908434629318171588) -->
+    <skip />
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Допрете за да вклучите звук."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Допрете за да поставите на вибрации. Можеби ќе се исклучи звукот на услугите за достапност."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Допрете за да исклучите звук. Можеби ќе се исклучи звукот на услугите за достапност."</string>
@@ -706,6 +710,7 @@
     <string name="show_demo_mode" msgid="3677956462273059726">"Прикажи демо-режим"</string>
     <string name="status_bar_ethernet" msgid="5690979758988647484">"Етернет"</string>
     <string name="status_bar_alarm" msgid="87160847643623352">"Аларм"</string>
+    <string name="active_mode_content_description" msgid="1627555562186515927">"Режимот „<xliff:g id="MODENAME">%1$s</xliff:g>“ е вклучен"</string>
     <string name="wallet_title" msgid="5369767670735827105">"Wallet"</string>
     <string name="wallet_empty_state_label" msgid="7776761245237530394">"Поставете за да купувате побрзо и побезбедно преку вашиот телефон"</string>
     <string name="wallet_app_button_label" msgid="7123784239111190992">"Прикажи ги сите"</string>
@@ -1405,26 +1410,38 @@
     <string name="launch_touchpad_tutorial_notification_content" msgid="7931085031240753226">"Научете движења за допирната подлога"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_title" msgid="1940023776496198762">"Движете се со користење на тастатурата и допирната подлога"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Научете движења за допирната подлога, кратенки од тастатурата и друго"</string>
-    <string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Движење за назад"</string>
-    <string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Движење за почетен екран"</string>
+    <!-- no translation found for touchpad_tutorial_back_gesture_button (3104716365403620315) -->
+    <skip />
+    <!-- no translation found for touchpad_tutorial_home_gesture_button (8023973153559885624) -->
+    <skip />
     <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Прегледајте ги неодамнешните апликации"</string>
     <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Готово"</string>
     <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Назад"</string>
-    <string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"За да се вратите назад, повлечете налево или надесно со три прста каде било на допирната подлога.\n\nЗа ова може да ја користите и кратенката од тастатурата Action + ESC."</string>
-    <string name="touchpad_back_gesture_success_title" msgid="7240576648330612171">"Одлично сторено!"</string>
+    <!-- no translation found for touchpad_back_gesture_guidance (5352221087725906542) -->
+    <skip />
+    <!-- no translation found for touchpad_back_gesture_success_title (7370719098633023496) -->
+    <skip />
     <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"Го научивте движењето за враќање назад."</string>
     <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"Одете на почетниот екран"</string>
-    <string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"За да одите на вашиот почетен екран кога сакате, повлечете нагоре со три прсти од дното на екранот."</string>
-    <string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Одлично!"</string>
-    <string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Го научивте движењето за враќање на почетниот екран."</string>
+    <!-- no translation found for touchpad_home_gesture_guidance (4178219118381915899) -->
+    <skip />
+    <!-- no translation found for touchpad_home_gesture_success_title (3648264553645798470) -->
+    <skip />
+    <!-- no translation found for touchpad_home_gesture_success_body (2590690589194027059) -->
+    <skip />
     <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"Прегледајте ги неодамнешните апликации"</string>
-    <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"Повлечете нагоре и задржете со три прста на допирната подлога."</string>
+    <!-- no translation found for touchpad_recent_apps_gesture_guidance (6304446013842271822) -->
+    <skip />
     <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Одлично!"</string>
     <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Го завршивте движењето за прегледување на неодамнешните апликации."</string>
-    <string name="tutorial_action_key_title" msgid="2659466586996495447">"Копче за дејство"</string>
-    <string name="tutorial_action_key_guidance" msgid="5718948664616999196">"За да пристапите до апликациите, притиснете го копчето за дејство на тастатурата."</string>
-    <string name="tutorial_action_key_success_title" msgid="466467860120112933">"Честитки!"</string>
-    <string name="tutorial_action_key_success_body" msgid="7201991081652850430">"Го научивте движењето со копчето за дејство.\n\nДејство + / ги прикажува сите кратенки што ги имате на располагање."</string>
+    <!-- no translation found for tutorial_action_key_title (8172535792469008169) -->
+    <skip />
+    <!-- no translation found for tutorial_action_key_guidance (5040613427202799294) -->
+    <skip />
+    <!-- no translation found for tutorial_action_key_success_title (2371827347071979571) -->
+    <skip />
+    <!-- no translation found for tutorial_action_key_success_body (1688986269491357832) -->
+    <skip />
     <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Осветлување на тастатура"</string>
     <string name="keyboard_backlight_value" msgid="7336398765584393538">"Ниво %1$d од %2$d"</string>
     <string name="home_controls_dream_label" msgid="6567105701292324257">"Контроли за домот"</string>
@@ -1436,6 +1453,7 @@
     <string name="all_apps_edu_toast_content" msgid="8807496014667211562">"Притиснете го копчето за дејство на тастатурата за да ги видите сите апликации"</string>
     <string name="redacted_notification_single_line_title" msgid="212019960919261670">"Редактирано"</string>
     <string name="redacted_notification_single_line_text" msgid="8684166405005242945">"Отклучете за приказ"</string>
+    <string name="contextual_education_dialog_title" msgid="4630392552837487324">"Контекстуално образование"</string>
     <string name="back_edu_notification_title" msgid="5624780717751357278">"Користете ја допирната подлога за да се вратите назад"</string>
     <string name="back_edu_notification_content" msgid="2497557451540954068">"Повлечете налево или надесно со три прста. Допрете за да научите повеќе движења."</string>
     <string name="home_edu_notification_title" msgid="6097902076909654045">"Користете ја допирната подлога за да одите на почетниот екран"</string>
diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml
index 6958679..bf446d9 100644
--- a/packages/SystemUI/res/values-ml/strings.xml
+++ b/packages/SystemUI/res/values-ml/strings.xml
@@ -440,7 +440,7 @@
     <string name="zen_mode_on" msgid="9085304934016242591">"ഓണാണ്"</string>
     <string name="zen_mode_on_with_details" msgid="7416143430557895497">"ഓണാണ് • <xliff:g id="TRIGGER_DESCRIPTION">%1$s</xliff:g>"</string>
     <string name="zen_mode_off" msgid="1736604456618147306">"ഓഫാണ്"</string>
-    <string name="zen_mode_set_up" msgid="7457957033034460064">"സജ്ജീകരിക്കുക"</string>
+    <string name="zen_mode_set_up" msgid="8231201163894922821">"സജ്ജീകരിച്ചിട്ടില്ല"</string>
     <string name="zen_mode_no_manual_invocation" msgid="1769975741344633672">"ക്രമീകരണത്തിൽ മാനേജ് ചെയ്യുക"</string>
     <string name="zen_mode_active_modes" msgid="1625850411578488856">"{count,plural, =0{സജീവ മോഡുകൾ ഒന്നുമില്ല}=1{{mode} സജീവമാണ്}other{# മോഡുകൾ സജീവമാണ്}}"</string>
     <string name="zen_priority_introduction" msgid="3159291973383796646">"നിങ്ങൾ സജ്ജീകരിച്ച അലാറങ്ങൾ, റിമൈൻഡറുകൾ, ഇവന്റുകൾ, കോളർമാർ എന്നിവയിൽ നിന്നുള്ള ശബ്‌ദങ്ങളും വൈബ്രേഷനുകളുമൊഴികെ മറ്റൊന്നും നിങ്ങളെ ശല്യപ്പെടുത്തുകയില്ല. സംഗീതം, വീഡിയോകൾ, ഗെയിമുകൾ എന്നിവയുൾപ്പെടെ പ്ലേ ചെയ്യുന്നതെന്തും നിങ്ങൾക്ക് ‌തുടർന്നും കേൾക്കാൻ കഴിയും."</string>
@@ -573,8 +573,7 @@
     <string name="notification_section_header_conversations" msgid="821834744538345661">"സംഭാഷണങ്ങൾ"</string>
     <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"എല്ലാ നിശബ്‌ദ അറിയിപ്പുകളും മായ്ക്കുക"</string>
     <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"\'ശല്യപ്പെടുത്തരുത്\' വഴി അറിയിപ്പുകൾ താൽക്കാലികമായി നിർത്തി"</string>
-    <!-- no translation found for modes_suppressing_shade_text (6037581130837903239) -->
-    <skip />
+    <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{അറിയിപ്പുകൾ ഒന്നുമില്ല}=1{{mode}, അറിയിപ്പുകൾ താൽക്കാലികമായി നിർത്തിയിരിക്കുന്നു}=2{{mode} എന്നതും മറ്റൊരു മോഡും, അറിയിപ്പുകൾ താൽക്കാലികമായി നിർത്തിയിരിക്കുന്നു}other{{mode} എന്നതും മറ്റ് # മോഡുകളും, അറിയിപ്പുകൾ താൽക്കാലികമായി നിർത്തിയിരിക്കുന്നു}}"</string>
     <string name="media_projection_action_text" msgid="3634906766918186440">"ഇപ്പോൾ ആരംഭിക്കുക"</string>
     <string name="empty_shade_text" msgid="8935967157319717412">"അറിയിപ്പുകൾ ഒന്നുമില്ല"</string>
     <string name="no_unseen_notif_text" msgid="395512586119868682">"പുതിയ അറിയിപ്പുകളൊന്നുമില്ല"</string>
@@ -673,6 +672,10 @@
     <string name="stream_notification_unavailable" msgid="4313854556205836435">"റിംഗ് മ്യൂട്ട് ചെയ്തതിനാൽ ലഭ്യമല്ല"</string>
     <string name="stream_alarm_unavailable" msgid="4059817189292197839">"ശല്യപ്പെടുത്തരുത് ഓണായതിനാൽ ലഭ്യമല്ല"</string>
     <string name="stream_media_unavailable" msgid="6823020894438959853">"ശല്യപ്പെടുത്തരുത് ഓണായതിനാൽ ലഭ്യമല്ല"</string>
+    <!-- no translation found for stream_unavailable_by_modes (3674139029490353683) -->
+    <skip />
+    <!-- no translation found for stream_unavailable_by_unknown (6908434629318171588) -->
+    <skip />
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. അൺമ്യൂട്ടുചെയ്യുന്നതിന് ടാപ്പുചെയ്യുക."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. വൈബ്രേറ്റിലേക്ക് സജ്ജമാക്കുന്നതിന് ടാപ്പുചെയ്യുക. ഉപയോഗസഹായി സേവനങ്ങൾ മ്യൂട്ടുചെയ്യപ്പെട്ടേക്കാം."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. മ്യൂട്ടുചെയ്യുന്നതിന് ടാപ്പുചെയ്യുക. ഉപയോഗസഹായി സേവനങ്ങൾ മ്യൂട്ടുചെയ്യപ്പെട്ടേക്കാം."</string>
@@ -706,6 +709,7 @@
     <string name="show_demo_mode" msgid="3677956462273059726">"ഡെമോ മോഡ് കാണിക്കുക"</string>
     <string name="status_bar_ethernet" msgid="5690979758988647484">"ഇതർനെറ്റ്"</string>
     <string name="status_bar_alarm" msgid="87160847643623352">"അലാറം"</string>
+    <string name="active_mode_content_description" msgid="1627555562186515927">"<xliff:g id="MODENAME">%1$s</xliff:g> ഓണാണ്"</string>
     <string name="wallet_title" msgid="5369767670735827105">"Wallet"</string>
     <string name="wallet_empty_state_label" msgid="7776761245237530394">"നിങ്ങളുടെ ഫോൺ ഉപയോഗിച്ച് വാങ്ങലുകൾ വേഗത്തിലും സുരക്ഷിതമായും നടത്താനുള്ള സജ്ജീകരണം നടത്തുക"</string>
     <string name="wallet_app_button_label" msgid="7123784239111190992">"എല്ലാം കാണിക്കുക"</string>
@@ -1405,26 +1409,26 @@
     <string name="launch_touchpad_tutorial_notification_content" msgid="7931085031240753226">"ടച്ച്പാഡ് ജെസ്ച്ചറുകൾ മനസ്സിലാക്കുക"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_title" msgid="1940023776496198762">"നിങ്ങളുടെ കീപാഡ്, ടച്ച്‌പാഡ് എന്നിവ ഉപയോഗിച്ച് നാവിഗേറ്റ് ചെയ്യുക"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"ടച്ച്‌പാഡ് ജെസ്ച്ചറുകൾ, കീബോർഡ് കുറുക്കുവഴികൾ എന്നിവയും മറ്റും മനസ്സിലാക്കുക"</string>
-    <string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"\'മടങ്ങുക\' ജെസ്ച്ചർ"</string>
-    <string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"ഹോം ജെസ്‌ച്ചർ"</string>
+    <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"മടങ്ങുക"</string>
+    <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"ഹോമിലേക്ക് പോകുക"</string>
     <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"അടുത്തിടെയുള്ള ആപ്പുകൾ കാണുക"</string>
     <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"പൂർത്തിയായി"</string>
     <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"മടങ്ങുക"</string>
-    <string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"തിരികെ പോകാൻ, ടച്ച്പാഡിൽ എവിടെയെങ്കിലും മൂന്ന് വിരലുകൾ ഉപയോഗിച്ച് ഇടത്തേക്കോ വലത്തേക്കോ സ്വൈപ്പ് ചെയ്യുക.\n\nഇതിന് Action + ESC കീബോഡ് കുറുക്കുവഴികളും നിങ്ങൾക്ക് ഉപയോഗിക്കാം."</string>
-    <string name="touchpad_back_gesture_success_title" msgid="7240576648330612171">"കൊള്ളാം!"</string>
+    <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"ടച്ച്‌പാഡിൽ മൂന്ന് വിരലുകൾ കൊണ്ട് ഇടത്തേക്കോ വലത്തേക്കോ സ്വൈപ്പ് ചെയ്യുക"</string>
+    <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"കൊള്ളാം!"</string>
     <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"മടങ്ങുക ജെസ്ച്ചർ നിങ്ങൾ പൂർത്തിയാക്കി."</string>
     <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"ഹോമിലേക്ക് പോകൂ"</string>
-    <string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"ഏതുസമയത്തും ഹോം സ്ക്രീനിലേക്ക് പോകാൻ, മൂന്ന് വിരലുകൾ ഉപയോഗിച്ച് സ്ക്രീനിന്റെ താഴെ നിന്ന് മുകളിലേക്ക് സ്വൈപ്പ് ചെയ്യൂ."</string>
-    <string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"കൊള്ളാം!"</string>
-    <string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"ഹോമിലേക്ക് പോകുക ജെസ്ച്ചർ നിങ്ങൾ പൂർത്തിയാക്കി."</string>
+    <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"ടച്ച്‌പാഡിൽ മൂന്ന് വിരലുകൾ ഉപയോഗിച്ച് മുകളിലേക്ക് സ്വൈപ്പ് ചെയ്യുക"</string>
+    <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"കൊള്ളാം!"</string>
+    <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"ഹോം ജെസ്ച്ചർ നിങ്ങൾ പൂർത്തിയാക്കി"</string>
     <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"അടുത്തിടെയുള്ള ആപ്പുകൾ കാണുക"</string>
-    <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"നിങ്ങളുടെ ടച്ച്പാഡിൽ മൂന്ന് വിരലുകൾ കൊണ്ട് മുകളിലേക്ക് സ്വൈപ്പ് ചെയ്‌ത് പിടിക്കുക."</string>
+    <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"നിങ്ങളുടെ ടച്ച്പാഡിൽ മൂന്ന് വിരലുകൾ കൊണ്ട് മുകളിലേക്ക് സ്വൈപ്പ് ചെയ്‌ത് പിടിക്കുക"</string>
     <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"കൊള്ളാം!"</string>
     <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"അടുത്തിടെയുള്ള ആപ്പുകൾ കാണുക എന്ന ജെസ്ച്ചർ നിങ്ങൾ പൂർത്തിയാക്കി."</string>
-    <string name="tutorial_action_key_title" msgid="2659466586996495447">"Action കീ"</string>
-    <string name="tutorial_action_key_guidance" msgid="5718948664616999196">"നിങ്ങളുടെ ആപ്പുകൾ ആക്‌സസ് ചെയ്യാൻ, നിങ്ങളുടെ കീബോർഡിലെ Action കീ അമർത്തുക."</string>
-    <string name="tutorial_action_key_success_title" msgid="466467860120112933">"അഭിനന്ദനങ്ങൾ!"</string>
-    <string name="tutorial_action_key_success_body" msgid="7201991081652850430">"നിങ്ങൾ Action കീ ജെസ്ച്ചർ പൂർത്തിയാക്കി.\n\nനിങ്ങൾക്ക് ലഭ്യമാകുന്ന എല്ലാ കുറുക്കുവഴികളും Action + / കാണിക്കുന്നു."</string>
+    <string name="tutorial_action_key_title" msgid="8172535792469008169">"എല്ലാ ആപ്പുകളും കാണുക"</string>
+    <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"നിങ്ങളുടെ കീബോർഡിലെ ആക്ഷൻ കീ അമർത്തുക"</string>
+    <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"അഭിനന്ദനങ്ങൾ!"</string>
+    <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"\'എല്ലാ ആപ്പുകളും കാണുക\' ജെസ്ച്ചർ നിങ്ങൾ പൂർത്തിയാക്കി"</string>
     <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"കീബോഡ് ബാക്ക്‌ലൈറ്റ്"</string>
     <string name="keyboard_backlight_value" msgid="7336398765584393538">"%2$d-ൽ %1$d-ാമത്തെ ലെവൽ"</string>
     <string name="home_controls_dream_label" msgid="6567105701292324257">"ഹോം കൺട്രോളുകൾ"</string>
@@ -1436,6 +1440,7 @@
     <string name="all_apps_edu_toast_content" msgid="8807496014667211562">"എല്ലാ ആപ്പുകളും കാണാൻ, നിങ്ങളുടെ കീബോർഡിലെ ആക്‌ഷൻ കീ അമർത്തുക"</string>
     <string name="redacted_notification_single_line_title" msgid="212019960919261670">"മറച്ചത്"</string>
     <string name="redacted_notification_single_line_text" msgid="8684166405005242945">"കാണാൻ, അൺലോക്ക് ചെയ്യുക"</string>
+    <string name="contextual_education_dialog_title" msgid="4630392552837487324">"സന്ദർഭോചിത വിദ്യാഭ്യാസം"</string>
     <string name="back_edu_notification_title" msgid="5624780717751357278">"തിരികെ പോകാൻ നിങ്ങളുടെ ടച്ച്‌പാഡ് ഉപയോഗിക്കുക"</string>
     <string name="back_edu_notification_content" msgid="2497557451540954068">"മൂന്ന് വിരലുകൾ കൊണ്ട് ഇടത്തേക്കോ വലത്തേക്കോ സ്വൈപ്പ് ചെയ്യൂ. കൂടുതൽ ജെസ്ച്ചറുകളറിയാൻ ടാപ്പ് ചെയ്യൂ."</string>
     <string name="home_edu_notification_title" msgid="6097902076909654045">"ഹോമിലേക്ക് പോകാൻ നിങ്ങളുടെ ടച്ച്‌പാഡ് ഉപയോഗിക്കുക"</string>
diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml
index 95ff970..1bd6768 100644
--- a/packages/SystemUI/res/values-mn/strings.xml
+++ b/packages/SystemUI/res/values-mn/strings.xml
@@ -440,7 +440,8 @@
     <string name="zen_mode_on" msgid="9085304934016242591">"Асаалттай"</string>
     <string name="zen_mode_on_with_details" msgid="7416143430557895497">"Асаасан • <xliff:g id="TRIGGER_DESCRIPTION">%1$s</xliff:g>"</string>
     <string name="zen_mode_off" msgid="1736604456618147306">"Унтраалттай"</string>
-    <string name="zen_mode_set_up" msgid="7457957033034460064">"Тохируулах"</string>
+    <!-- no translation found for zen_mode_set_up (8231201163894922821) -->
+    <skip />
     <string name="zen_mode_no_manual_invocation" msgid="1769975741344633672">"Тохиргоонд удирдах"</string>
     <string name="zen_mode_active_modes" msgid="1625850411578488856">"{count,plural, =0{Ямар ч идэвхтэй горим байхгүй}=1{{mode} идэвхтэй байна}other{# горим идэвхтэй байна}}"</string>
     <string name="zen_priority_introduction" msgid="3159291973383796646">"Танд сэрүүлэг, сануулга, арга хэмжээ, таны сонгосон дуудлага илгээгчээс бусад дуу, чичиргээ саад болохгүй. Та хөгжим, видео, тоглоом зэрэг тоглуулахыг хүссэн бүх зүйлээ сонсох боломжтой хэвээр байна."</string>
@@ -573,8 +574,7 @@
     <string name="notification_section_header_conversations" msgid="821834744538345661">"Харилцан яриа"</string>
     <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Бүх чимээгүй мэдэгдлийг арилгах"</string>
     <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Бүү саад бол горимын түр зогсоосон мэдэгдэл"</string>
-    <!-- no translation found for modes_suppressing_shade_text (6037581130837903239) -->
-    <skip />
+    <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{Мэдэгдэл байхгүй}=1{Мэдэгдлийг {mode} түр зогсоосон}=2{Мэдэгдлийг {mode} болон өөр нэг горим түр зогсоосон}other{Мэдэгдлийг {mode} болон өөр # горим түр зогсоосон}}"</string>
     <string name="media_projection_action_text" msgid="3634906766918186440">"Одоо эхлүүлэх"</string>
     <string name="empty_shade_text" msgid="8935967157319717412">"Мэдэгдэл байхгүй"</string>
     <string name="no_unseen_notif_text" msgid="395512586119868682">"Шинэ мэдэгдэл алга"</string>
@@ -673,6 +673,10 @@
     <string name="stream_notification_unavailable" msgid="4313854556205836435">"Хонхны дууг хаасан тул боломжгүй"</string>
     <string name="stream_alarm_unavailable" msgid="4059817189292197839">"Бүү саад бол асаалттай тул боломжгүй"</string>
     <string name="stream_media_unavailable" msgid="6823020894438959853">"Бүү саад бол асаалттай тул боломжгүй"</string>
+    <!-- no translation found for stream_unavailable_by_modes (3674139029490353683) -->
+    <skip />
+    <!-- no translation found for stream_unavailable_by_unknown (6908434629318171588) -->
+    <skip />
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Дууг нь нээхийн тулд товшино уу."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Чичиргээнд тохируулахын тулд товшино уу. Хүртээмжийн үйлчилгээний дууг хаасан."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Дууг нь хаахын тулд товшино уу. Хүртээмжийн үйлчилгээний дууг хаасан."</string>
@@ -706,6 +710,7 @@
     <string name="show_demo_mode" msgid="3677956462273059726">"Демо горимыг харуулах"</string>
     <string name="status_bar_ethernet" msgid="5690979758988647484">"Этернет"</string>
     <string name="status_bar_alarm" msgid="87160847643623352">"Сэрүүлэг"</string>
+    <string name="active_mode_content_description" msgid="1627555562186515927">"<xliff:g id="MODENAME">%1$s</xliff:g> асаалттай байна"</string>
     <string name="wallet_title" msgid="5369767670735827105">"Wallet"</string>
     <string name="wallet_empty_state_label" msgid="7776761245237530394">"Утсаараа илүү хурдан, аюулгүй худалдан авалт хийхийн тулд тохируулгыг авна уу"</string>
     <string name="wallet_app_button_label" msgid="7123784239111190992">"Бүгдийг харуулах"</string>
@@ -1405,26 +1410,38 @@
     <string name="launch_touchpad_tutorial_notification_content" msgid="7931085031240753226">"Мэдрэгч самбарын зангааг мэдэж аваарай"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_title" msgid="1940023776496198762">"Гар эсвэл мэдрэгч самбараа ашиглан шилжээрэй"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Мэдрэгч самбарын зангаа, товчлуурын шууд холбоос болон бусад зүйлийг мэдэж аваарай"</string>
-    <string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Буцах зангаа"</string>
-    <string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Үндсэн нүүрний зангаа"</string>
+    <!-- no translation found for touchpad_tutorial_back_gesture_button (3104716365403620315) -->
+    <skip />
+    <!-- no translation found for touchpad_tutorial_home_gesture_button (8023973153559885624) -->
+    <skip />
     <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Саяхны аппуудыг харах"</string>
     <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Болсон"</string>
     <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Буцах"</string>
-    <string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"Буцахын тулд мэдрэгч самбар дээр гурван хуруугаар хүссэн газраа зүүн эсвэл баруун тийш шударна уу.\n\nТа мөн үүнийг хийхэд Action + ESC товчлуурын шууд холбоосыг ашиглах боломжтой."</string>
-    <string name="touchpad_back_gesture_success_title" msgid="7240576648330612171">"Үнэхээр сайн ажиллалаа!"</string>
+    <!-- no translation found for touchpad_back_gesture_guidance (5352221087725906542) -->
+    <skip />
+    <!-- no translation found for touchpad_back_gesture_success_title (7370719098633023496) -->
+    <skip />
     <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"Та буцах зангааг гүйцэтгэлээ."</string>
     <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"Үндсэн нүүр лүү очих"</string>
-    <string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"Үндсэн нүүр лүүгээ хүссэн үедээ очихын тулд дэлгэцийнхээ доод талаас гурван хуруугаараа дээш шударна уу."</string>
-    <string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Янзтай!"</string>
-    <string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Та үндсэн нүүр лүү очих зангааг гүйцэтгэлээ."</string>
+    <!-- no translation found for touchpad_home_gesture_guidance (4178219118381915899) -->
+    <skip />
+    <!-- no translation found for touchpad_home_gesture_success_title (3648264553645798470) -->
+    <skip />
+    <!-- no translation found for touchpad_home_gesture_success_body (2590690589194027059) -->
+    <skip />
     <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"Саяхны аппуудыг харах"</string>
-    <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"Мэдрэгч самбар дээрээ гурван хуруугаа ашиглан дээш шудраад, удаан дарна уу."</string>
+    <!-- no translation found for touchpad_recent_apps_gesture_guidance (6304446013842271822) -->
+    <skip />
     <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Сайн байна!"</string>
     <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Та саяхны аппуудыг харах зангааг гүйцэтгэсэн."</string>
-    <string name="tutorial_action_key_title" msgid="2659466586996495447">"Тусгай товчлуур"</string>
-    <string name="tutorial_action_key_guidance" msgid="5718948664616999196">"Аппууддаа хандахын тулд гар дээр тань байх тусгай товчлуурыг дарна уу."</string>
-    <string name="tutorial_action_key_success_title" msgid="466467860120112933">"Баяр хүргэе!"</string>
-    <string name="tutorial_action_key_success_body" msgid="7201991081652850430">"Та тусгай товчлуурын зангааг гүйцэтгэлээ.\n\nТусгай товчлуур болох + / нь танд боломжтой бүх товчлолыг харуулна."</string>
+    <!-- no translation found for tutorial_action_key_title (8172535792469008169) -->
+    <skip />
+    <!-- no translation found for tutorial_action_key_guidance (5040613427202799294) -->
+    <skip />
+    <!-- no translation found for tutorial_action_key_success_title (2371827347071979571) -->
+    <skip />
+    <!-- no translation found for tutorial_action_key_success_body (1688986269491357832) -->
+    <skip />
     <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Гарын арын гэрэл"</string>
     <string name="keyboard_backlight_value" msgid="7336398765584393538">"%2$d-с %1$d-р түвшин"</string>
     <string name="home_controls_dream_label" msgid="6567105701292324257">"Гэрийн удирдлага"</string>
@@ -1436,6 +1453,7 @@
     <string name="all_apps_edu_toast_content" msgid="8807496014667211562">"Бүх аппаа харахын тулд гар дээр тань байх тусгай товчлуурыг дарна уу"</string>
     <string name="redacted_notification_single_line_title" msgid="212019960919261670">"Хассан"</string>
     <string name="redacted_notification_single_line_text" msgid="8684166405005242945">"Харахын тулд түгжээг тайлна уу"</string>
+    <string name="contextual_education_dialog_title" msgid="4630392552837487324">"Хам сэдэвт боловсрол"</string>
     <string name="back_edu_notification_title" msgid="5624780717751357278">"Буцахын тулд мэдрэгч самбараа ашиглах"</string>
     <string name="back_edu_notification_content" msgid="2497557451540954068">"Гурван хуруугаараа зүүн эсвэл баруун тийш шударна уу. Илүү олон зангаа сурахын тулд товшино уу."</string>
     <string name="home_edu_notification_title" msgid="6097902076909654045">"Нүүр хуудас руу очихын тулд мэдрэгч самбараа ашиглах"</string>
diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml
index 1473929..60718b9 100644
--- a/packages/SystemUI/res/values-mr/strings.xml
+++ b/packages/SystemUI/res/values-mr/strings.xml
@@ -440,7 +440,7 @@
     <string name="zen_mode_on" msgid="9085304934016242591">"सुरू आहे"</string>
     <string name="zen_mode_on_with_details" msgid="7416143430557895497">"सुरू • <xliff:g id="TRIGGER_DESCRIPTION">%1$s</xliff:g>"</string>
     <string name="zen_mode_off" msgid="1736604456618147306">"बंद आहे"</string>
-    <string name="zen_mode_set_up" msgid="7457957033034460064">"सेट करा"</string>
+    <string name="zen_mode_set_up" msgid="8231201163894922821">"सेट केलेले नाही"</string>
     <string name="zen_mode_no_manual_invocation" msgid="1769975741344633672">"सेटिंग्जमध्ये व्यवस्थापित करा"</string>
     <string name="zen_mode_active_modes" msgid="1625850411578488856">"{count,plural, =0{कोणतेही अ‍ॅक्टिव्ह मोड नाहीत}=1{{mode} अ‍ॅक्टिव्ह आहे}other{# मोड अ‍ॅक्टिव्ह आहेत}}"</string>
     <string name="zen_priority_introduction" msgid="3159291973383796646">"अलार्म, रिमाइंडर, इव्‍हेंट आणि तुम्ही निश्चित केलेल्या कॉलर व्यतिरिक्त तुम्हाला कोणत्याही आवाज आणि कंपनांचा व्यत्त्यय आणला जाणार नाही. तरीही तुम्ही प्ले करायचे ठरवलेले कोणतेही संगीत, व्हिडिओ आणि गेमचे आवाज ऐकू शकतात."</string>
@@ -573,8 +573,7 @@
     <string name="notification_section_header_conversations" msgid="821834744538345661">"संभाषणे"</string>
     <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"सर्व सायलंट सूचना साफ करा"</string>
     <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"व्यत्यय आणून नकाद्वारे सूचना थांबवल्या"</string>
-    <!-- no translation found for modes_suppressing_shade_text (6037581130837903239) -->
-    <skip />
+    <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{कोणतेही नोटिफिकेशन नाही}=1{{mode} द्वारे नोटिफिकेशन थांबवली आहेत}=2{{mode} द्वारे आणि आणखी एका मोडद्वारे नोटिफिकेशन थांबवली आहेत}other{{mode} द्वारे आणि आणखी # मोडद्वारे नोटिफिकेशन थांबवली आहेत}}"</string>
     <string name="media_projection_action_text" msgid="3634906766918186440">"आता सुरू करा"</string>
     <string name="empty_shade_text" msgid="8935967157319717412">"सूचना नाहीत"</string>
     <string name="no_unseen_notif_text" msgid="395512586119868682">"नवीन सूचना नाहीत"</string>
@@ -673,6 +672,10 @@
     <string name="stream_notification_unavailable" msgid="4313854556205836435">"रिंग म्यूट केल्यामुळे उपलब्ध नाही"</string>
     <string name="stream_alarm_unavailable" msgid="4059817189292197839">"व्यत्यय आणू नका हे सुरू असल्यामुळे उपलब्ध नाही"</string>
     <string name="stream_media_unavailable" msgid="6823020894438959853">"व्यत्यय आणू नका हे सुरू असल्यामुळे उपलब्ध नाही"</string>
+    <!-- no translation found for stream_unavailable_by_modes (3674139029490353683) -->
+    <skip />
+    <!-- no translation found for stream_unavailable_by_unknown (6908434629318171588) -->
+    <skip />
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. अनम्यूट करण्यासाठी टॅप करा."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. व्हायब्रेट सेट करण्यासाठी टॅप करा. प्रवेशयोग्यता सेवा म्यूट केल्या जाऊ शकतात."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. म्यूट करण्यासाठी टॅप करा. प्रवेशक्षमता सेवा म्यूट केल्या जाऊ शकतात."</string>
@@ -706,6 +709,7 @@
     <string name="show_demo_mode" msgid="3677956462273059726">"डेमो मोड दर्शवा"</string>
     <string name="status_bar_ethernet" msgid="5690979758988647484">"इथरनेट"</string>
     <string name="status_bar_alarm" msgid="87160847643623352">"अलार्म"</string>
+    <string name="active_mode_content_description" msgid="1627555562186515927">"<xliff:g id="MODENAME">%1$s</xliff:g> हे सुरू आहे"</string>
     <string name="wallet_title" msgid="5369767670735827105">"Wallet"</string>
     <string name="wallet_empty_state_label" msgid="7776761245237530394">"तुमचा फोन वापरून जलदरीत्या, अधिक सुरक्षित खरेदी करण्यासाठी सेट करा"</string>
     <string name="wallet_app_button_label" msgid="7123784239111190992">"सर्व दाखवा"</string>
@@ -1405,26 +1409,26 @@
     <string name="launch_touchpad_tutorial_notification_content" msgid="7931085031240753226">"टचपॅड जेश्चर जाणून घ्या"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_title" msgid="1940023776496198762">"तुमचा कीबोर्ड आणि टचपॅड वापरून नेव्हिगेट करा"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"टचपॅड जेश्चर, कीबोर्ड शॉर्टकट आणि आणखी बरेच काही जाणून घ्या"</string>
-    <string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"मागे जा जेश्चर"</string>
-    <string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"होम जेश्चर"</string>
+    <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"मागे जा"</string>
+    <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"होमवर जा"</string>
     <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"अलीकडील अ‍ॅप्स पहा"</string>
     <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"पूर्ण झाले"</string>
     <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"मागे जा"</string>
-    <string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"मागे जाण्यासाठी, तीन बोटांनी टचपॅडवर कुठेही डावीकडे किंवा उजवीकडे स्वाइप करा.\n\nतुम्ही यासाठी Action + ESC हा कीबोर्ड शॉर्टकटदेखील वापरू शकता."</string>
-    <string name="touchpad_back_gesture_success_title" msgid="7240576648330612171">"उत्तम कामगिरी!"</string>
+    <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"तुमच्या टचपॅडवर तीन बोटांनी डावीकडे किंवा उजवीकडे स्‍वाइप करा"</string>
+    <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"छान!"</string>
     <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"तुम्ही गो बॅक जेश्चर पूर्ण केले."</string>
     <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"होमवर जा"</string>
-    <string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"कधीही तुमच्या होम स्क्रीनवर जाण्यासाठी, तीन बोटांनी तुमच्या स्क्रीनच्या तळापासून स्वाइप करा."</string>
-    <string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"छान!"</string>
-    <string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"तुम्ही गो होम जेश्चर पूर्ण केले आहे."</string>
+    <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"तुमच्या टचपॅडवर तीन बोटांनी वर स्वाइप करा"</string>
+    <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"उत्तम कामगिरी!"</string>
+    <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"तुम्ही गो होम जेश्चर पूर्ण केले आहे"</string>
     <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"अलीकडील अ‍ॅप्स पहा"</string>
-    <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"तुमच्या टचपॅडवर तीन बोटांनी वरती आणि खाली स्वाइप करा."</string>
+    <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"तुमच्या टचपॅडवर तीन बोटांनी वर स्वाइप करून धरून ठेवा"</string>
     <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"उत्तम कामगिरी!"</string>
     <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"तुम्ही अलीकडील ॲप्स पाहण्याचे जेश्चर पूर्ण केले आहे."</string>
-    <string name="tutorial_action_key_title" msgid="2659466586996495447">"अ‍ॅक्शन की"</string>
-    <string name="tutorial_action_key_guidance" msgid="5718948664616999196">"तुमची ॲप्स अ‍ॅक्सेस करण्यासाठी, तुमच्या कीबोर्डवरील अ‍ॅक्शन की प्रेस करा."</string>
-    <string name="tutorial_action_key_success_title" msgid="466467860120112933">"अभिनंदन!"</string>
-    <string name="tutorial_action_key_success_body" msgid="7201991081652850430">"तुम्ही अ‍ॅक्शन की जेश्चर पूर्ण केले आहे.\n\nकृती + / हे तुमच्याकडे उपलब्ध असलेले सर्व शॉर्टकट दाखवते."</string>
+    <string name="tutorial_action_key_title" msgid="8172535792469008169">"सर्व अ‍ॅप्स पहा"</string>
+    <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"तुमच्या कीबोर्डवर अ‍ॅक्शन की प्रेस करा"</string>
+    <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"खूप छान!"</string>
+    <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"तुम्ही ॲप्स पाहण्याचे जेश्चर पूर्ण केले आहे"</string>
     <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"कीबोर्ड बॅकलाइट"</string>
     <string name="keyboard_backlight_value" msgid="7336398765584393538">"%2$d पैकी %1$d पातळी"</string>
     <string name="home_controls_dream_label" msgid="6567105701292324257">"होम कंट्रोल"</string>
@@ -1436,6 +1440,7 @@
     <string name="all_apps_edu_toast_content" msgid="8807496014667211562">"तुमची सर्व ॲप्स पाहण्यासाठी, तुमच्या कीबोर्डवरील अ‍ॅक्शन की प्रेस करा"</string>
     <string name="redacted_notification_single_line_title" msgid="212019960919261670">"रिडॅक्ट केलेले"</string>
     <string name="redacted_notification_single_line_text" msgid="8684166405005242945">"पाहण्यासाठी अनलॉक करा"</string>
+    <string name="contextual_education_dialog_title" msgid="4630392552837487324">"संदर्भीय शिक्षण"</string>
     <string name="back_edu_notification_title" msgid="5624780717751357278">"मागे जाण्यासाठी तुमचा टचपॅड वापरा"</string>
     <string name="back_edu_notification_content" msgid="2497557451540954068">"तीन बोटांनी डावीकडे किंवा उजवीकडे स्वाइप करा. आणखी जेश्चर जाणून घेण्यासाठी टॅप करा."</string>
     <string name="home_edu_notification_title" msgid="6097902076909654045">"होमवर जाण्यासाठी तुमचा टचपॅड वापरा"</string>
diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
index ed3a0bc..1160a1a 100644
--- a/packages/SystemUI/res/values-ms/strings.xml
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -440,7 +440,7 @@
     <string name="zen_mode_on" msgid="9085304934016242591">"Hidup"</string>
     <string name="zen_mode_on_with_details" msgid="7416143430557895497">"Pada • <xliff:g id="TRIGGER_DESCRIPTION">%1$s</xliff:g>"</string>
     <string name="zen_mode_off" msgid="1736604456618147306">"Mati"</string>
-    <string name="zen_mode_set_up" msgid="7457957033034460064">"Sediakan"</string>
+    <string name="zen_mode_set_up" msgid="8231201163894922821">"Tidak ditetapkan"</string>
     <string name="zen_mode_no_manual_invocation" msgid="1769975741344633672">"Urus dalam tetapan"</string>
     <string name="zen_mode_active_modes" msgid="1625850411578488856">"{count,plural, =0{Tiada mod yang aktif}=1{{mode} aktif}other{# mod aktif}}"</string>
     <string name="zen_priority_introduction" msgid="3159291973383796646">"Anda tidak akan diganggu oleh bunyi dan getaran, kecuali daripada penggera, peringatan, acara dan pemanggil yang anda tetapkan. Anda masih mendengar item lain yang anda pilih untuk dimainkan termasuk muzik, video dan permainan."</string>
@@ -573,8 +573,7 @@
     <string name="notification_section_header_conversations" msgid="821834744538345661">"Perbualan"</string>
     <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Kosongkan semua pemberitahuan senyap"</string>
     <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Pemberitahuan dijeda oleh Jangan Ganggu"</string>
-    <!-- no translation found for modes_suppressing_shade_text (6037581130837903239) -->
-    <skip />
+    <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{Tiada pemberitahuan}=1{Pemberitahuan dijeda oleh {mode}}=2{Pemberitahuan dijeda oleh {mode} dan satu lagi mod yang lain}other{Pemberitahuan dijeda oleh {mode} dan # mod yang lain}}"</string>
     <string name="media_projection_action_text" msgid="3634906766918186440">"Mulakan sekarang"</string>
     <string name="empty_shade_text" msgid="8935967157319717412">"Tiada pemberitahuan"</string>
     <string name="no_unseen_notif_text" msgid="395512586119868682">"Tiada pemberitahuan baharu"</string>
@@ -673,6 +672,10 @@
     <string name="stream_notification_unavailable" msgid="4313854556205836435">"Tidak tersedia kerana deringan diredam"</string>
     <string name="stream_alarm_unavailable" msgid="4059817189292197839">"Tidak tersedia kerana Jangan Ganggu dihidupkan"</string>
     <string name="stream_media_unavailable" msgid="6823020894438959853">"Tidak tersedia kerana Jangan Ganggu dihidupkan"</string>
+    <!-- no translation found for stream_unavailable_by_modes (3674139029490353683) -->
+    <skip />
+    <!-- no translation found for stream_unavailable_by_unknown (6908434629318171588) -->
+    <skip />
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Ketik untuk menyahredam."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Ketik untuk menetapkan pada getar. Perkhidmatan kebolehaksesan mungkin diredamkan."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Ketik untuk meredam. Perkhidmatan kebolehaksesan mungkin diredamkan."</string>
@@ -706,6 +709,7 @@
     <string name="show_demo_mode" msgid="3677956462273059726">"Tunjukkan mod tunjuk cara"</string>
     <string name="status_bar_ethernet" msgid="5690979758988647484">"Ethernet"</string>
     <string name="status_bar_alarm" msgid="87160847643623352">"Penggera"</string>
+    <string name="active_mode_content_description" msgid="1627555562186515927">"<xliff:g id="MODENAME">%1$s</xliff:g> dihidupkan"</string>
     <string name="wallet_title" msgid="5369767670735827105">"Wallet"</string>
     <string name="wallet_empty_state_label" msgid="7776761245237530394">"Buat persediaan untuk membuat pembelian yang lebih pantas dan selamat dengan telefon anda"</string>
     <string name="wallet_app_button_label" msgid="7123784239111190992">"Tunjukkan semua"</string>
@@ -1405,26 +1409,26 @@
     <string name="launch_touchpad_tutorial_notification_content" msgid="7931085031240753226">"Ketahui gerak isyarat pad sentuh"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_title" msgid="1940023776496198762">"Navigasi menggunakan papan kekunci dan pad sentuh anda"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Ketahui gerak isyarat pad sentuh, pintasan papan kekunci dan pelbagai lagi"</string>
-    <string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Gerak isyarat kembali"</string>
-    <string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Gerak isyarat pergi ke laman utama"</string>
+    <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"Kembali"</string>
+    <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Akses laman utama"</string>
     <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Lihat apl terbaharu"</string>
     <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Selesai"</string>
     <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Kembali"</string>
-    <string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"Untuk kembali, leret ke kiri atau ke kanan menggunakan tiga jari di mana-mana sahaja pada pad sentuh.\n\nAnda juga boleh menggunakan pintasan papan kekunci Action + ESC untuk kembali."</string>
-    <string name="touchpad_back_gesture_success_title" msgid="7240576648330612171">"Syabas!"</string>
+    <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"Leret ke kiri atau kanan menggunakan tiga jari pada pad sentuh anda"</string>
+    <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"Bagus!"</string>
     <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"Anda telah melengkapkan gerak isyarat undur."</string>
     <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"Akses laman utama"</string>
-    <string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"Untuk mengakses skrin utama anda pada bila-bila masa, leret ke atas menggunakan tiga jari daripada bahagian bawah skrin anda."</string>
-    <string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Bagus!"</string>
-    <string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Anda telah melengkapkan gerak isyarat akses laman utama."</string>
+    <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"Leret ke atas dengan tiga jari pada pad sentuh anda"</string>
+    <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"Bagus!"</string>
+    <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"Anda telah melengkapkan gerak isyarat akses laman utama"</string>
     <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"Lihat apl terbaharu"</string>
-    <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"Leret ke atas dan tahan menggunakan tiga jari pada pad sentuh anda."</string>
+    <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"Leret ke atas dan tahan menggunakan tiga jari pada pad sentuh anda"</string>
     <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Syabas!"</string>
     <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Anda melengkapkan gerak isyarat lihat apl terbaharu."</string>
-    <string name="tutorial_action_key_title" msgid="2659466586996495447">"Kekunci tindakan"</string>
-    <string name="tutorial_action_key_guidance" msgid="5718948664616999196">"Untuk mengakses semua apl anda, tekan kekunci tindakan pada papan kekunci anda."</string>
-    <string name="tutorial_action_key_success_title" msgid="466467860120112933">"Tahniah!"</string>
-    <string name="tutorial_action_key_success_body" msgid="7201991081652850430">"Anda telah melengkapkan gerak isyarat kekunci tindakan.\n\nTindakan + / menunjukkan semua pintasan anda yang tersedia."</string>
+    <string name="tutorial_action_key_title" msgid="8172535792469008169">"Lihat semua apl"</string>
+    <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Tekan kekunci tindakan pada papan kekunci anda"</string>
+    <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Syabas!"</string>
+    <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Anda telah melengkapkan gerak isyarat lihat semua apl"</string>
     <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Cahaya latar papan kekunci"</string>
     <string name="keyboard_backlight_value" msgid="7336398765584393538">"Tahap %1$d daripada %2$d"</string>
     <string name="home_controls_dream_label" msgid="6567105701292324257">"Kawalan Rumah"</string>
@@ -1436,6 +1440,7 @@
     <string name="all_apps_edu_toast_content" msgid="8807496014667211562">"Untuk melihat semua apl anda, tekan kekunci tindakan pada papan kekunci anda"</string>
     <string name="redacted_notification_single_line_title" msgid="212019960919261670">"Disunting"</string>
     <string name="redacted_notification_single_line_text" msgid="8684166405005242945">"Buka kunci untuk melihat"</string>
+    <string name="contextual_education_dialog_title" msgid="4630392552837487324">"Pendidikan kontekstual"</string>
     <string name="back_edu_notification_title" msgid="5624780717751357278">"Gunakan pad sentuh anda untuk kembali"</string>
     <string name="back_edu_notification_content" msgid="2497557451540954068">"Leret ke kiri atau ke kanan dengan tiga jari. Ketik dan ketahui lebih lanjut tentang gerak isyarat."</string>
     <string name="home_edu_notification_title" msgid="6097902076909654045">"Gunakan pad sentuh untuk mengakses laman utama"</string>
@@ -1444,8 +1449,8 @@
     <string name="overview_edu_notification_content" msgid="3578204677648432500">"Leret ke atas, tahan dengan tiga jari. Ketik untuk mengetahui lebih lanjut tentang gerak isyarat."</string>
     <string name="all_apps_edu_notification_title" msgid="372262997265569063">"Gunakan papan kekunci anda untuk melihat semua apl"</string>
     <string name="all_apps_edu_notification_content" msgid="3255070575694025585">"Tekan kekunci tindakan pada bila-bila masa. Ketik dan ketahui lebih lanjut tentang gerak isyarat."</string>
-    <string name="accessibility_deprecate_extra_dim_dialog_title" msgid="910988771011857460">"Kini ciri amat malap merupakan sebahagian daripada peluncur kecerahan"</string>
-    <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="4453123359258743230">"Kini anda boleh menjadikan skrin amat malap dengan merendahkan lebih lagi tahap kecerahan.\n\nMemandangkan ciri ini kini merupakan sebahagian daripada peluncur kecerahan, pintasan amat malap dialih keluar."</string>
+    <string name="accessibility_deprecate_extra_dim_dialog_title" msgid="910988771011857460">"Ciri amat malap kini bergabung dengan peluncur kecerahan"</string>
+    <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="4453123359258743230">"Skrin boleh dijadikan amat malap dengan menurunkan lagi tahap kecerahannya.\n\nOleh sebab ciri ini telah bergabung dengan peluncur kecerahan, pintasan amat malap dialih keluar."</string>
     <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="3947537827396916005">"Alih keluar pintasan amat malap"</string>
     <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="165474092660941104">"Pintasan amat malap dialih keluar"</string>
     <string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"Kesambungan"</string>
diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml
index ea10ec2..224247e 100644
--- a/packages/SystemUI/res/values-my/strings.xml
+++ b/packages/SystemUI/res/values-my/strings.xml
@@ -440,7 +440,7 @@
     <string name="zen_mode_on" msgid="9085304934016242591">"ဖွင့်"</string>
     <string name="zen_mode_on_with_details" msgid="7416143430557895497">"ဖွင့် • <xliff:g id="TRIGGER_DESCRIPTION">%1$s</xliff:g>"</string>
     <string name="zen_mode_off" msgid="1736604456618147306">"ပိတ်"</string>
-    <string name="zen_mode_set_up" msgid="7457957033034460064">"စနစ်ထည့်သွင်းရန်"</string>
+    <string name="zen_mode_set_up" msgid="8231201163894922821">"သတ်မှတ်မထားပါ"</string>
     <string name="zen_mode_no_manual_invocation" msgid="1769975741344633672">"ဆက်တင်များတွင် စီမံရန်"</string>
     <string name="zen_mode_active_modes" msgid="1625850411578488856">"{count,plural, =0{သုံးနေသော မုဒ်မရှိပါ}=1{{mode} ကို သုံးနေသည်}other{မုဒ် # ခု သုံးနေသည်}}"</string>
     <string name="zen_priority_introduction" msgid="3159291973383796646">"နှိုးစက်သံ၊ သတိပေးချက်အသံများ၊ ပွဲစဉ်သတိပေးသံများနှင့် သင်ခွင့်ပြုထားသူများထံမှ ဖုန်းခေါ်မှုများမှလွဲ၍ အခြားအသံများနှင့် တုန်ခါမှုများက သင့်ကို အနှောင့်အယှက်ပြုမည် မဟုတ်ပါ။ သို့သော်လည်း သီချင်း၊ ဗီဒီယိုနှင့် ဂိမ်းများအပါအဝင် သင်ကရွေးချယ်ဖွင့်ထားသည့် အရာတိုင်း၏ အသံကိုမူ ကြားနေရဆဲဖြစ်ပါလိမ့်မည်။"</string>
@@ -573,8 +573,7 @@
     <string name="notification_section_header_conversations" msgid="821834744538345661">"စကားဝိုင်းများ"</string>
     <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"အသံတိတ် အကြောင်းကြားချက်များအားလုံးကို ရှင်းလင်းရန်"</string>
     <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"အကြောင်းကြားချက်များကို \'မနှောင့်ယှက်ရ\' က ခေတ္တရပ်ထားသည်"</string>
-    <!-- no translation found for modes_suppressing_shade_text (6037581130837903239) -->
-    <skip />
+    <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{အကြောင်းကြားချက် မရှိပါ}=1{{mode} က ခဏရပ်ထားသော အကြောင်းကြားချက်များ}=2{{mode} နှင့် အခြားမုဒ်တစ်ခုက ခဏရပ်ထားသော အကြောင်းကြားချက်များ}other{{mode} နှင့် အခြားမုဒ် # ခုက ခဏရပ်ထားသော အကြောင်းကြားချက်များ}}"</string>
     <string name="media_projection_action_text" msgid="3634906766918186440">"ယခု စတင်ပါ"</string>
     <string name="empty_shade_text" msgid="8935967157319717412">"အကြောင်းကြားချက် မရှိပါ"</string>
     <string name="no_unseen_notif_text" msgid="395512586119868682">"အကြောင်းကြားချက်သစ် မရှိပါ"</string>
@@ -673,6 +672,10 @@
     <string name="stream_notification_unavailable" msgid="4313854556205836435">"ဖုန်းမြည်သံပိတ်ထားသဖြင့် မရနိုင်ပါ"</string>
     <string name="stream_alarm_unavailable" msgid="4059817189292197839">"‘မနှောင့်ယှက်ရ’ ဖွင့်ထားသောကြောင့် မရနိုင်ပါ"</string>
     <string name="stream_media_unavailable" msgid="6823020894438959853">"‘မနှောင့်ယှက်ရ’ ဖွင့်ထားသောကြောင့် မရနိုင်ပါ"</string>
+    <!-- no translation found for stream_unavailable_by_modes (3674139029490353683) -->
+    <skip />
+    <!-- no translation found for stream_unavailable_by_unknown (6908434629318171588) -->
+    <skip />
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s။ အသံပြန်ဖွင့်ရန် တို့ပါ။"</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s။ တုန်ခါမှုကို သတ်မှတ်ရန် တို့ပါ။ အများသုံးနိုင်မှု ဝန်ဆောင်မှုများကို အသံပိတ်ထားနိုင်ပါသည်။"</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s။ အသံပိတ်ရန် တို့ပါ။ အများသုံးနိုင်မှု ဝန်ဆောင်မှုများကို အသံပိတ်ထားနိုင်ပါသည်။"</string>
@@ -706,6 +709,7 @@
     <string name="show_demo_mode" msgid="3677956462273059726">"သရုပ်ပြမုဒ် ပြရန်"</string>
     <string name="status_bar_ethernet" msgid="5690979758988647484">"အီသာနက်"</string>
     <string name="status_bar_alarm" msgid="87160847643623352">"နှိုးစက်"</string>
+    <string name="active_mode_content_description" msgid="1627555562186515927">"<xliff:g id="MODENAME">%1$s</xliff:g> ဖွင့်ထားသည်"</string>
     <string name="wallet_title" msgid="5369767670735827105">"Wallet"</string>
     <string name="wallet_empty_state_label" msgid="7776761245237530394">"သင့်ဖုန်းဖြင့် ပိုမိုမြန်ဆန်၊ ပိုမိုစိတ်ချရသော ဝယ်ယူမှုများ ပြုလုပ်ရန် စတင်သတ်မှတ်ပါ"</string>
     <string name="wallet_app_button_label" msgid="7123784239111190992">"အားလုံးပြရန်"</string>
@@ -1405,26 +1409,26 @@
     <string name="launch_touchpad_tutorial_notification_content" msgid="7931085031240753226">"တာ့ချ်ပက်လက်ဟန်များကို လေ့လာပါ"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_title" msgid="1940023776496198762">"သင်၏ ကီးဘုတ်နှင့် တာ့ချ်ပက်တို့ကိုသုံး၍ လမ်းညွှန်ခြင်း"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"တာ့ချ်ပက်လက်ဟန်များ၊ လက်ကွက်ဖြတ်လမ်းများ စသည်တို့ကို လေ့လာပါ"</string>
-    <string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"နောက်သို့ လက်ဟန်"</string>
-    <string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"ပင်မစာမျက်နှာ လက်ဟန်"</string>
+    <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"နောက်သို့"</string>
+    <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"ပင်မစာမျက်နှာသို့ သွားရန်"</string>
     <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"မကြာသေးမီကအက်ပ်များကို ကြည့်ရန်"</string>
     <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"ပြီးပြီ"</string>
     <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"ပြန်သွားရန်"</string>
-    <string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"နောက်ပြန်သွားရန် တာ့ချ်ပက်ပေါ်ရှိ မည်သည့်နေရာ၌မဆို လက်သုံးချောင်းဖြင့် ဘယ် (သို့) ညာသို့ ပွတ်ဆွဲပါ။\n\n၎င်းအတွက် လက်ကွက်ဖြတ်လမ်း Action + ESC ကိုလည်း သုံးနိုင်သည်။"</string>
-    <string name="touchpad_back_gesture_success_title" msgid="7240576648330612171">"တော်ပါပေသည်။"</string>
+    <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"သင့်တာ့ချ်ပက်တွင် လက်သုံးချောင်းဖြင့် ဘယ် (သို့) ညာသို့ ပွတ်ဆွဲပါ"</string>
+    <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"ကောင်းပါသည်။"</string>
     <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"နောက်သို့လက်ဟန် အပြီးသတ်လိုက်ပါပြီ"</string>
     <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"ပင်မစာမျက်နှာသို့ သွားရန်"</string>
-    <string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"ပင်မစာမျက်နှာသို့ အချိန်မရွေးသွားရန် စခရင်အောက်ခြေမှ အပေါ်သို့ လက်သုံးချောင်းဖြင့် ပွတ်ဆွဲပါ။"</string>
-    <string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"ကောင်းသည်။"</string>
-    <string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"ပင်မစာမျက်နှာသို့သွားသည့် လက်ဟန် အပြီးသတ်လိုက်ပါပြီ။"</string>
+    <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"တာ့ချ်ပက်ပေါ်တွင် လက်သုံးချောင်းဖြင့် အပေါ်သို့ ပွတ်ဆွဲပါ"</string>
+    <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"တော်ပါပေသည်။"</string>
+    <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"ပင်မစာမျက်နှာသို့သွားသည့် လက်ဟန် အပြီးသတ်လိုက်ပါပြီ"</string>
     <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"မကြာသေးမီကအက်ပ်များကို ကြည့်ခြင်း"</string>
-    <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"သင့်တာ့ချ်ပက်တွင် လက်သုံးချောင်းဖြင့် အပေါ်သို့ပွတ်ဆွဲပြီး ဖိထားပါ။"</string>
+    <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"သင့်တာ့ချ်ပက်တွင် လက်သုံးချောင်းဖြင့် အပေါ်သို့ပွတ်ဆွဲပြီး ဖိထားပါ"</string>
     <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"တော်ပါပေသည်။"</string>
     <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"မကြာသေးမီကအက်ပ်များကို ကြည့်ခြင်းလက်ဟန် သင်ခန်းစာပြီးပါပြီ။"</string>
-    <string name="tutorial_action_key_title" msgid="2659466586996495447">"လုပ်ဆောင်ချက်ကီး"</string>
-    <string name="tutorial_action_key_guidance" msgid="5718948664616999196">"သင့်အက်ပ်များသုံးရန် ကီးဘုတ်ပေါ်ရှိ လုပ်ဆောင်ချက်ကီးကို နှိပ်ပါ။"</string>
-    <string name="tutorial_action_key_success_title" msgid="466467860120112933">"ဂုဏ်ယူပါသည်။"</string>
-    <string name="tutorial_action_key_success_body" msgid="7201991081652850430">"လုပ်ဆောင်ချက်ကီး လက်ဟန် အပြီးသတ်လိုက်ပါပြီ။\n\nလုပ်ဆောင်ချက် + / သည် ရရှိနိုင်သော ဖြတ်လမ်းအားလုံးကို ပြသည်။"</string>
+    <string name="tutorial_action_key_title" msgid="8172535792469008169">"အက်ပ်အားလုံးကို ကြည့်ရန်"</string>
+    <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"ကီးဘုတ်တွင် လုပ်ဆောင်ချက်ကီး နှိပ်ပါ"</string>
+    <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"အလွန်ကောင်းပါသည်။"</string>
+    <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"အက်ပ်အားလုံးကို ကြည့်ခြင်းလက်ဟန် သင်ခန်းစာပြီးပါပြီ"</string>
     <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"ကီးဘုတ်နောက်မီး"</string>
     <string name="keyboard_backlight_value" msgid="7336398765584393538">"အဆင့် %2$d အနက် %1$d"</string>
     <string name="home_controls_dream_label" msgid="6567105701292324257">"အိမ်ထိန်းချုပ်မှုများ"</string>
@@ -1436,6 +1440,7 @@
     <string name="all_apps_edu_toast_content" msgid="8807496014667211562">"သင့်အက်ပ်အားလုံးကြည့်ရန် ကီးဘုတ်ပေါ်ရှိ လုပ်ဆောင်ချက်ကီးကို နှိပ်ပါ"</string>
     <string name="redacted_notification_single_line_title" msgid="212019960919261670">"အစားထိုးထားသည်"</string>
     <string name="redacted_notification_single_line_text" msgid="8684166405005242945">"ကြည့်ရန် ဖွင့်ပါ"</string>
+    <string name="contextual_education_dialog_title" msgid="4630392552837487324">"အကြောင်းအရာအလိုက် ပညာရေး"</string>
     <string name="back_edu_notification_title" msgid="5624780717751357278">"နောက်ပြန်သွားရန် သင့်တာ့ချ်ပက်ကို သုံးပါ"</string>
     <string name="back_edu_notification_content" msgid="2497557451540954068">"လက်သုံးချောင်းဖြင့် ဘယ် (သို့) ညာသို့ ပွတ်ဆွဲပါ။ လက်ဟန်များ ပိုမိုလေ့လာရန် တို့ပါ။"</string>
     <string name="home_edu_notification_title" msgid="6097902076909654045">"ပင်မစာမျက်နှာသို့ သွားရန် သင့်တာ့ချ်ပက်ကို သုံးပါ"</string>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index 6ce048e4..6d65c6c 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -440,7 +440,7 @@
     <string name="zen_mode_on" msgid="9085304934016242591">"På"</string>
     <string name="zen_mode_on_with_details" msgid="7416143430557895497">"På • <xliff:g id="TRIGGER_DESCRIPTION">%1$s</xliff:g>"</string>
     <string name="zen_mode_off" msgid="1736604456618147306">"Av"</string>
-    <string name="zen_mode_set_up" msgid="7457957033034460064">"Konfigurer"</string>
+    <string name="zen_mode_set_up" msgid="8231201163894922821">"Ikke angitt"</string>
     <string name="zen_mode_no_manual_invocation" msgid="1769975741344633672">"Administrer i innstillingene"</string>
     <string name="zen_mode_active_modes" msgid="1625850411578488856">"{count,plural, =0{Ingen aktive moduser}=1{{mode} er aktiv}other{# moduser er aktive}}"</string>
     <string name="zen_priority_introduction" msgid="3159291973383796646">"Du blir ikke forstyrret av lyder og vibrasjoner, med unntak av alarmer, påminnelser, aktiviteter og oppringere du angir. Du kan fremdeles høre alt du velger å spille av, for eksempel musikk, videoer og spill."</string>
@@ -573,8 +573,7 @@
     <string name="notification_section_header_conversations" msgid="821834744538345661">"Samtaler"</string>
     <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Fjern alle lydløse varsler"</string>
     <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Varsler er satt på pause av «Ikke forstyrr»"</string>
-    <!-- no translation found for modes_suppressing_shade_text (6037581130837903239) -->
-    <skip />
+    <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{Ingen varsler}=1{Varsler er satt på pause av {mode}}=2{Varsler er satt på pause av {mode} og én modus til}other{Varsler er satt på pause av {mode} og # moduser til}}"</string>
     <string name="media_projection_action_text" msgid="3634906766918186440">"Start nå"</string>
     <string name="empty_shade_text" msgid="8935967157319717412">"Ingen varsler"</string>
     <string name="no_unseen_notif_text" msgid="395512586119868682">"Ingen nye varsler"</string>
@@ -673,6 +672,10 @@
     <string name="stream_notification_unavailable" msgid="4313854556205836435">"Utilgjengelig fordi ringelyden er kuttet"</string>
     <string name="stream_alarm_unavailable" msgid="4059817189292197839">"Utilgjengelig fordi «Ikke forstyrr» er på"</string>
     <string name="stream_media_unavailable" msgid="6823020894438959853">"Utilgjengelig fordi «Ikke forstyrr» er på"</string>
+    <!-- no translation found for stream_unavailable_by_modes (3674139029490353683) -->
+    <skip />
+    <!-- no translation found for stream_unavailable_by_unknown (6908434629318171588) -->
+    <skip />
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Trykk for å slå på lyden."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Trykk for å angi vibrasjon. Lyden kan bli slått av for tilgjengelighetstjenestene."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Trykk for å slå av lyden. Lyden kan bli slått av for tilgjengelighetstjenestene."</string>
@@ -706,6 +709,7 @@
     <string name="show_demo_mode" msgid="3677956462273059726">"Vis demo-modus"</string>
     <string name="status_bar_ethernet" msgid="5690979758988647484">"Ethernet"</string>
     <string name="status_bar_alarm" msgid="87160847643623352">"Alarm"</string>
+    <string name="active_mode_content_description" msgid="1627555562186515927">"<xliff:g id="MODENAME">%1$s</xliff:g> er på"</string>
     <string name="wallet_title" msgid="5369767670735827105">"Wallet"</string>
     <string name="wallet_empty_state_label" msgid="7776761245237530394">"Legg til en betalingsmåte for å gjennomføre kjøp raskere og sikrere med telefonen"</string>
     <string name="wallet_app_button_label" msgid="7123784239111190992">"Vis alle"</string>
@@ -1405,26 +1409,26 @@
     <string name="launch_touchpad_tutorial_notification_content" msgid="7931085031240753226">"Lær deg styreflatebevegelser"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_title" msgid="1940023776496198762">"Naviger med tastaturet og styreflaten"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Lær deg styreflatebevegelser, hurtigtaster med mer"</string>
-    <string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Tilbakebevegelse"</string>
-    <string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Startskjermbevegelse"</string>
+    <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"Gå tilbake"</string>
+    <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Gå til startsiden"</string>
     <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Se nylige apper"</string>
     <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Ferdig"</string>
     <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Gå tilbake"</string>
-    <string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"For å gå tilbake, sveip mot høyre eller venstre med tre fingre hvor som helst på styreflaten.\n\nDu kan også gjøre dette med hurtigtasten Action + Esc."</string>
-    <string name="touchpad_back_gesture_success_title" msgid="7240576648330612171">"Bra jobbet!"</string>
+    <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"Sveip til venstre eller høyre med tre fingre på styreflaten"</string>
+    <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"Bra!"</string>
     <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"Du har fullført bevegelsen for å gå tilbake."</string>
     <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"Gå til startsiden"</string>
-    <string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"For å gå til startskjermen, sveip opp med tre fingre fra bunnen av skjermen når som helst."</string>
-    <string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Bra!"</string>
-    <string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Du har fullført bevegelsen for å gå til startskjermen."</string>
+    <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"Sveip opp med tre fingre på styreflaten"</string>
+    <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"Bra jobbet!"</string>
+    <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"Du har fullført bevegelsen for å gå til startskjermen"</string>
     <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"Se nylige apper"</string>
-    <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"Sveip opp og hold med tre fingre på styreflaten."</string>
+    <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"Sveip opp og hold med tre fingre på styreflaten"</string>
     <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Bra jobbet!"</string>
     <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Du har fullført bevegelsen for å se nylige apper."</string>
-    <string name="tutorial_action_key_title" msgid="2659466586996495447">"Handlingstast"</string>
-    <string name="tutorial_action_key_guidance" msgid="5718948664616999196">"For å åpne appene dine, trykk på handlingstasten på tastaturet."</string>
-    <string name="tutorial_action_key_success_title" msgid="466467860120112933">"Gratulerer!"</string>
-    <string name="tutorial_action_key_success_body" msgid="7201991081652850430">"Du har fullført bevegelsen for handlingstasten.\n\nHandling + / viser alle tilgjengelige snarveier."</string>
+    <string name="tutorial_action_key_title" msgid="8172535792469008169">"Se alle apper"</string>
+    <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Trykk på handlingstasten på tastaturet"</string>
+    <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Bra!"</string>
+    <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Du har fullført bevegelsen for å se alle apper"</string>
     <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Bakgrunnslys for tastatur"</string>
     <string name="keyboard_backlight_value" msgid="7336398765584393538">"Nivå %1$d av %2$d"</string>
     <string name="home_controls_dream_label" msgid="6567105701292324257">"Hjemkontroller"</string>
@@ -1436,6 +1440,7 @@
     <string name="all_apps_edu_toast_content" msgid="8807496014667211562">"For å se alle appene dine, trykk på handlingstasten på tastaturet"</string>
     <string name="redacted_notification_single_line_title" msgid="212019960919261670">"Fjernet"</string>
     <string name="redacted_notification_single_line_text" msgid="8684166405005242945">"Lås opp for å se"</string>
+    <string name="contextual_education_dialog_title" msgid="4630392552837487324">"Kontekstuell opplæring"</string>
     <string name="back_edu_notification_title" msgid="5624780717751357278">"Bruk styreflaten for å gå tilbake"</string>
     <string name="back_edu_notification_content" msgid="2497557451540954068">"Sveip til venstre eller høyre med tre fingre. Trykk for å lære flere bevegelser."</string>
     <string name="home_edu_notification_title" msgid="6097902076909654045">"Bruk styreflaten for å gå til startsiden"</string>
@@ -1450,7 +1455,7 @@
     <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="165474092660941104">"Snarveiene for ekstra dimming er fjernet"</string>
     <string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"Tilkobling"</string>
     <string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"Tilgjengelighet"</string>
-    <string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"Systemverktøy"</string>
+    <string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"Verktøy"</string>
     <string name="qs_edit_mode_category_privacy" msgid="6577774443194551775">"Personvern"</string>
     <string name="qs_edit_mode_category_providedByApps" msgid="8346112074897919019">"Levert av apper"</string>
     <string name="qs_edit_mode_category_display" msgid="4749511439121053942">"Skjerm"</string>
diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml
index 01419b4..a55c53a 100644
--- a/packages/SystemUI/res/values-ne/strings.xml
+++ b/packages/SystemUI/res/values-ne/strings.xml
@@ -440,7 +440,7 @@
     <string name="zen_mode_on" msgid="9085304934016242591">"अन छ"</string>
     <string name="zen_mode_on_with_details" msgid="7416143430557895497">"अन छ • <xliff:g id="TRIGGER_DESCRIPTION">%1$s</xliff:g>"</string>
     <string name="zen_mode_off" msgid="1736604456618147306">"अफ छ"</string>
-    <string name="zen_mode_set_up" msgid="7457957033034460064">"सेटअप गर्नुहोस्"</string>
+    <string name="zen_mode_set_up" msgid="8231201163894922821">"सेट गरिएको छैन"</string>
     <string name="zen_mode_no_manual_invocation" msgid="1769975741344633672">"सेटिङमा गई व्यवस्थापन गर्नुहोस्"</string>
     <string name="zen_mode_active_modes" msgid="1625850411578488856">"{count,plural, =0{कुनै पनि सक्रिय छैन}=1{{mode} सक्रिय छ}other{# मोड सक्रिय छन्}}"</string>
     <string name="zen_priority_introduction" msgid="3159291973383796646">"तपाईंलाई अलार्म, रिमाइन्डर, कार्यक्रम र तपाईंले निर्दिष्ट गर्नुभएका कलरहरू बाहेकका ध्वनि र कम्पनहरूले बाधा पुऱ्याउने छैनन्। तपाईंले अझै सङ्गीत, भिडियो र खेलहरू लगायत आफूले प्ले गर्न छनौट गरेका जुनसुकै कुरा सुन्न सक्नुहुनेछ।"</string>
@@ -573,8 +573,7 @@
     <string name="notification_section_header_conversations" msgid="821834744538345661">"वार्तालापहरू"</string>
     <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"सबै मौन सूचनाहरू हटाउनुहोस्"</string>
     <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"बाधा नपुऱ्याउनुहोस् नामक मोडमार्फत पज पारिएका सूचनाहरू"</string>
-    <!-- no translation found for modes_suppressing_shade_text (6037581130837903239) -->
-    <skip />
+    <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{कुनै पनि नोटिफिकेसन छैन}=1{{mode} ले गर्दा नोटिफिकेसनहरू पज गरिएका छन्}=2{{mode} र अन्य एक मोडले गर्दा नोटिफिकेसनहरू पज गरिएका छन्}other{{mode} र अन्य # वटा मोडले गर्दा नोटिफिकेसनहरू पज गरिएका छन्}}"</string>
     <string name="media_projection_action_text" msgid="3634906766918186440">"अहिले न"</string>
     <string name="empty_shade_text" msgid="8935967157319717412">"कुनै सूचनाहरू छैनन्"</string>
     <string name="no_unseen_notif_text" msgid="395512586119868682">"कुनै पनि नयाँ सूचना छैन"</string>
@@ -673,6 +672,10 @@
     <string name="stream_notification_unavailable" msgid="4313854556205836435">"डिभाइस म्युट गरिएकाले यो सुविधा उपलब्ध छैन"</string>
     <string name="stream_alarm_unavailable" msgid="4059817189292197839">"Do Not Disturb अन भएकाले भोल्युम बढाउन मिल्दैन"</string>
     <string name="stream_media_unavailable" msgid="6823020894438959853">"Do Not Disturb अन भएकाले भोल्युम बढाउन मिल्दैन"</string>
+    <!-- no translation found for stream_unavailable_by_modes (3674139029490353683) -->
+    <skip />
+    <!-- no translation found for stream_unavailable_by_unknown (6908434629318171588) -->
+    <skip />
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s। अनम्यूट गर्नाका लागि ट्याप गर्नुहोस्।"</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s। कम्पनमा सेट गर्नाका लागि ट्याप गर्नुहोस्। पहुँच सम्बन्धी सेवाहरू म्यूट हुन सक्छन्।"</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s। म्यूट गर्नाका लागि ट्याप गर्नुहोस्। पहुँच सम्बन्धी सेवाहरू म्यूट हुन सक्छन्।"</string>
@@ -706,6 +709,7 @@
     <string name="show_demo_mode" msgid="3677956462273059726">"डेमो मोड देखाउनुहोस्"</string>
     <string name="status_bar_ethernet" msgid="5690979758988647484">"इथरनेट"</string>
     <string name="status_bar_alarm" msgid="87160847643623352">"अलार्म"</string>
+    <string name="active_mode_content_description" msgid="1627555562186515927">"<xliff:g id="MODENAME">%1$s</xliff:g> अन छ"</string>
     <string name="wallet_title" msgid="5369767670735827105">"Wallet"</string>
     <string name="wallet_empty_state_label" msgid="7776761245237530394">"फोनमार्फत अझ छिटो र थप सुरक्षित तरिकाले खरिद गर्न भुक्तानी विधि सेटअप गर्नुहोस्"</string>
     <string name="wallet_app_button_label" msgid="7123784239111190992">"सबै देखाउनुहोस्"</string>
@@ -1405,26 +1409,26 @@
     <string name="launch_touchpad_tutorial_notification_content" msgid="7931085031240753226">"टचप्याड जेस्चर प्रयोग गर्न सिक्नुहोस्"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_title" msgid="1940023776496198762">"किबोर्ड र टचप्याड प्रयोग गरी नेभिगेट गर्नुहोस्"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"टचप्याड जेस्चर, किबोर्डका सर्टकट र अन्य कुरा प्रयोग गर्न सिक्नुहोस्"</string>
-    <string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"ब्याक जेस्चर"</string>
-    <string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"होम जेस्चर"</string>
+    <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"पछाडि जानुहोस्"</string>
+    <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"होम स्क्रिनमा जानुहोस्"</string>
     <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"हालसालै चलाइएका एपहरू हेर्नुहोस्"</string>
     <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"सम्पन्न भयो"</string>
     <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"पछाडि जानुहोस्"</string>
-    <string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"पछाडि जान तीन वटा औँलाले टचप्याडमा कतै छोएर बायाँ वा दायाँतिर स्वाइप गर्नुहोस्।\n\nतपाईं यसका लागि किबोर्डको सर्टकट \"Action + ESC\" पनि प्रयोग गर्न सक्नुहुन्छ।"</string>
-    <string name="touchpad_back_gesture_success_title" msgid="7240576648330612171">"अद्भुत!"</string>
+    <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"तीन वटा औँला प्रयोग गरी टचप्याडमा बायाँ वा दायाँतिर स्वाइप गर्नुहोस्"</string>
+    <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"राम्रो!"</string>
     <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"तपाईंले \'पछाडि जानुहोस्\' नामक इसारा प्रयोग गर्ने तरिका सिक्नुभयो।"</string>
     <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"होमपेजमा जानुहोस्"</string>
-    <string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"जुनसुकै बेला आफ्नो होम स्क्रिनमा जान स्क्रिनको फेदबाट तीन वटा औँलाले माथितिर स्वाइप गर्नुहोस्।"</string>
-    <string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"राम्रो!"</string>
-    <string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"तपाईंले \"होम स्क्रिनमा जानुहोस्\" नामक जेस्चर प्रयोग गर्ने तरिका सिक्नुभयो।"</string>
+    <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"टचप्याडमा तीन वटा औँलाले माथितिर स्वाइप गर्नुहोस्"</string>
+    <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"अद्भुत!"</string>
+    <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"तपाईंले \"होम स्क्रिनमा जानुहोस्\" नामक जेस्चर प्रयोग गर्ने तरिका सिक्नुभयो"</string>
     <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"हालसालै चलाइएका एपहरू हेर्नुहोस्"</string>
-    <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"तीन वटा औँला प्रयोग गरी टचप्याडमा माथितिर स्वाइप गर्नुहोस् र होल्ड गर्नुहोस्।"</string>
+    <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"तीन वटा औँला प्रयोग गरी टचप्याडमा माथितिर स्वाइप गर्नुहोस् र होल्ड गर्नुहोस्"</string>
     <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"अद्भुत!"</string>
     <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"तपाईंले हालसालै चलाइएका एपहरू हेर्ने जेस्चर पूरा गर्नुभएको छ।"</string>
-    <string name="tutorial_action_key_title" msgid="2659466586996495447">"एक्सन की"</string>
-    <string name="tutorial_action_key_guidance" msgid="5718948664616999196">"आफ्ना एपहरू एक्सेस गर्न आफ्नो किबोर्डमा भएको एक्सन की थिच्नुहोस्।"</string>
-    <string name="tutorial_action_key_success_title" msgid="466467860120112933">"बधाई छ!"</string>
-    <string name="tutorial_action_key_success_body" msgid="7201991081652850430">"तपाईंले एक्सन की थिचेर गरिने जेस्चर प्रयोग गर्ने तरिका सिक्नुभयो।\n\nएक्सन + / थिच्नुभयो भने उपलब्ध सबै सर्टकटहरू देखिन्छन्।"</string>
+    <string name="tutorial_action_key_title" msgid="8172535792469008169">"सबै एपहरू हेर्नुहोस्"</string>
+    <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"आफ्नो किबोर्डमा भएको एक्सन की थिच्नुहोस्"</string>
+    <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"स्याबास!"</string>
+    <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"तपाईंले \"सबै एपहरू हेर्नुहोस्\" नामक जेस्चर प्रयोग गर्ने तरिका सिक्नुभयो"</string>
     <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"किबोर्ड ब्याकलाइट"</string>
     <string name="keyboard_backlight_value" msgid="7336398765584393538">"%2$d मध्ये %1$d औँ स्तर"</string>
     <string name="home_controls_dream_label" msgid="6567105701292324257">"होम कन्ट्रोलहरू"</string>
@@ -1436,6 +1440,7 @@
     <string name="all_apps_edu_toast_content" msgid="8807496014667211562">"आफ्ना सबै एपहरू हेर्न आफ्नो किबोर्डमा भएको एक्सन की थिच्नुहोस्"</string>
     <string name="redacted_notification_single_line_title" msgid="212019960919261670">"जानकारी लुकाउन सम्पादन गरिएको"</string>
     <string name="redacted_notification_single_line_text" msgid="8684166405005242945">"हेर्नका लागि अनलक गर्नुहोस्"</string>
+    <string name="contextual_education_dialog_title" msgid="4630392552837487324">"सान्दर्भिक शिक्षा"</string>
     <string name="back_edu_notification_title" msgid="5624780717751357278">"पछाडि जान आफ्नो टचप्याड प्रयोग गर्नुहोस्"</string>
     <string name="back_edu_notification_content" msgid="2497557451540954068">"तिन वटा औँला प्रयोग गरी बायाँ वा दायाँतिर स्वाइप गर्नुहोस्। थप जेस्चर प्रयोग गर्ने तरिका सिक्न ट्याप गर्नुहोस्।"</string>
     <string name="home_edu_notification_title" msgid="6097902076909654045">"होममा जान आफ्नो टचप्याड प्रयोग गर्नुहोस्"</string>
diff --git a/packages/SystemUI/res/values-night/styles.xml b/packages/SystemUI/res/values-night/styles.xml
index 7bd4ca8..17ba2e5 100644
--- a/packages/SystemUI/res/values-night/styles.xml
+++ b/packages/SystemUI/res/values-night/styles.xml
@@ -63,10 +63,4 @@
     <style name="ShortcutHelperTheme" parent="@style/ShortcutHelperThemeCommon">
         <item name="android:windowLightNavigationBar">false</item>
     </style>
-
-    <style name="ContextualEduDialog" parent="@android:style/Theme.DeviceDefault.Dialog.NoActionBar">
-        <!-- To make the dialog wrap to content when the education text is short -->
-        <item name="windowMinWidthMajor">0%</item>
-        <item name="windowMinWidthMinor">0%</item>
-    </style>
 </resources>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index 325e361..e5bc5be 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -440,7 +440,7 @@
     <string name="zen_mode_on" msgid="9085304934016242591">"Aan"</string>
     <string name="zen_mode_on_with_details" msgid="7416143430557895497">"Aan • <xliff:g id="TRIGGER_DESCRIPTION">%1$s</xliff:g>"</string>
     <string name="zen_mode_off" msgid="1736604456618147306">"Uit"</string>
-    <string name="zen_mode_set_up" msgid="7457957033034460064">"Instellen"</string>
+    <string name="zen_mode_set_up" msgid="8231201163894922821">"Niet ingesteld"</string>
     <string name="zen_mode_no_manual_invocation" msgid="1769975741344633672">"Beheren via instellingen"</string>
     <string name="zen_mode_active_modes" msgid="1625850411578488856">"{count,plural, =0{Geen actieve modi}=1{{mode} is actief}other{# modi zijn actief}}"</string>
     <string name="zen_priority_introduction" msgid="3159291973383796646">"Je wordt niet gestoord door geluiden en trillingen, behalve bij wekkers, herinneringen, afspraken en specifieke bellers die je selecteert. Je kunt nog steeds alles horen wat je wilt afspelen, waaronder muziek, video\'s en games."</string>
@@ -573,8 +573,7 @@
     <string name="notification_section_header_conversations" msgid="821834744538345661">"Gesprekken"</string>
     <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Alle stille meldingen wissen"</string>
     <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Meldingen onderbroken door \'Niet storen\'"</string>
-    <!-- no translation found for modes_suppressing_shade_text (6037581130837903239) -->
-    <skip />
+    <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{Geen meldingen}=1{Meldingen onderbroken door {mode}}=2{Meldingen onderbroken door {mode} en 1 andere modus}other{Meldingen onderbroken door {mode} en # andere modi}}"</string>
     <string name="media_projection_action_text" msgid="3634906766918186440">"Nu starten"</string>
     <string name="empty_shade_text" msgid="8935967157319717412">"Geen meldingen"</string>
     <string name="no_unseen_notif_text" msgid="395512586119868682">"Geen nieuwe meldingen"</string>
@@ -673,6 +672,10 @@
     <string name="stream_notification_unavailable" msgid="4313854556205836435">"Niet beschikbaar, belgeluid staat uit"</string>
     <string name="stream_alarm_unavailable" msgid="4059817189292197839">"Niet beschikbaar omdat Niet storen aanstaat"</string>
     <string name="stream_media_unavailable" msgid="6823020894438959853">"Niet beschikbaar omdat Niet storen aanstaat"</string>
+    <!-- no translation found for stream_unavailable_by_modes (3674139029490353683) -->
+    <skip />
+    <!-- no translation found for stream_unavailable_by_unknown (6908434629318171588) -->
+    <skip />
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Tik om dempen op te heffen."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Tik om in te stellen op trillen. Het geluid van toegankelijkheidsservices kan hierdoor uitgaan."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Tik om te dempen. Het geluid van toegankelijkheidsservices kan hierdoor uitgaan."</string>
@@ -706,6 +709,7 @@
     <string name="show_demo_mode" msgid="3677956462273059726">"Demomodus tonen"</string>
     <string name="status_bar_ethernet" msgid="5690979758988647484">"Ethernet"</string>
     <string name="status_bar_alarm" msgid="87160847643623352">"Wekker"</string>
+    <string name="active_mode_content_description" msgid="1627555562186515927">"<xliff:g id="MODENAME">%1$s</xliff:g> staat aan"</string>
     <string name="wallet_title" msgid="5369767670735827105">"Portemonnee"</string>
     <string name="wallet_empty_state_label" msgid="7776761245237530394">"Zorg dat je sneller en beter beveiligd aankopen kunt doen met je telefoon"</string>
     <string name="wallet_app_button_label" msgid="7123784239111190992">"Alles tonen"</string>
@@ -1405,26 +1409,26 @@
     <string name="launch_touchpad_tutorial_notification_content" msgid="7931085031240753226">"Leer touchpadgebaren die je kunt gebruiken"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_title" msgid="1940023776496198762">"Navigeren met je toetsenbord en touchpad"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Leer meer over onder andere touchpadgebaren en sneltoetsen"</string>
-    <string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Gebaar voor terug"</string>
-    <string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Gebaar voor startscherm"</string>
+    <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"Terug"</string>
+    <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Naar startscherm"</string>
     <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Recente apps bekijken"</string>
     <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Klaar"</string>
     <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Terug"</string>
-    <string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"Als je wilt teruggaan, swipe je met 3 vingers naar links of rechts op de touchpad.\n\nJe kunt hiervoor ook de sneltoets Actie + ESC gebruiken."</string>
-    <string name="touchpad_back_gesture_success_title" msgid="7240576648330612171">"Goed bezig!"</string>
+    <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"Swipe met 3 vingers naar links of rechts op de touchpad"</string>
+    <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"Goed zo!"</string>
     <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"Je weet nu hoe je het gebaar voor terug maakt."</string>
     <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"Naar startscherm"</string>
-    <string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"Swipe met 3 vingers omhoog vanaf de onderkant van het scherm om naar het startscherm te gaan."</string>
-    <string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Mooi zo!"</string>
-    <string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Je weet nu hoe je het gebaar Naar startscherm maakt."</string>
+    <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"Swipe met 3 vingers omhoog op de touchpad"</string>
+    <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"Goed werk!"</string>
+    <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"Je weet nu hoe je het gebaar Naar startscherm maakt"</string>
     <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"Recente apps bekijken"</string>
-    <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"Swipe met 3 vingers omhoog en houd vast op je touchpad."</string>
+    <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"Swipe met 3 vingers omhoog en houd vast op de touchpad"</string>
     <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Goed werk!"</string>
     <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Je weet nu hoe je het gebaar Recente apps bekijken maakt."</string>
-    <string name="tutorial_action_key_title" msgid="2659466586996495447">"Actietoets"</string>
-    <string name="tutorial_action_key_guidance" msgid="5718948664616999196">"Als je toegang tot je apps wilt krijgen, druk je op de actietoets op je toetsenbord."</string>
-    <string name="tutorial_action_key_success_title" msgid="466467860120112933">"Gefeliciteerd!"</string>
-    <string name="tutorial_action_key_success_body" msgid="7201991081652850430">"Je hebt het gebaar voor de actietoets uitgevoerd.\n\nActie + / toont alle beschikbare sneltoetsen."</string>
+    <string name="tutorial_action_key_title" msgid="8172535792469008169">"Alle apps bekijken"</string>
+    <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Druk op de actietoets op het toetsenbord"</string>
+    <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Goed gedaan!"</string>
+    <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Je weet nu hoe je het gebaar Alle apps bekijken maakt"</string>
     <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Achtergrondverlichting van toetsenbord"</string>
     <string name="keyboard_backlight_value" msgid="7336398765584393538">"Niveau %1$d van %2$d"</string>
     <string name="home_controls_dream_label" msgid="6567105701292324257">"Bediening voor in huis"</string>
@@ -1436,6 +1440,7 @@
     <string name="all_apps_edu_toast_content" msgid="8807496014667211562">"Als je alle apps wilt bekijken, druk je op de actietoets op je toetsenbord"</string>
     <string name="redacted_notification_single_line_title" msgid="212019960919261670">"Verborgen"</string>
     <string name="redacted_notification_single_line_text" msgid="8684166405005242945">"Ontgrendelen om te bekijken"</string>
+    <string name="contextual_education_dialog_title" msgid="4630392552837487324">"Contextuele educatie"</string>
     <string name="back_edu_notification_title" msgid="5624780717751357278">"Je touchpad gebruiken om terug te gaan"</string>
     <string name="back_edu_notification_content" msgid="2497557451540954068">"Swipe met 3 vingers naar links of rechts. Tik voor meer gebaren."</string>
     <string name="home_edu_notification_title" msgid="6097902076909654045">"Je touchpad gebruiken om naar het startscherm te gaan"</string>
diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml
index e034999..cf7a58d 100644
--- a/packages/SystemUI/res/values-or/strings.xml
+++ b/packages/SystemUI/res/values-or/strings.xml
@@ -440,7 +440,7 @@
     <string name="zen_mode_on" msgid="9085304934016242591">"ଚାଲୁ ଅଛି"</string>
     <string name="zen_mode_on_with_details" msgid="7416143430557895497">"ଚାଲୁ ଅଛି • <xliff:g id="TRIGGER_DESCRIPTION">%1$s</xliff:g>"</string>
     <string name="zen_mode_off" msgid="1736604456618147306">"ବନ୍ଦ ଅଛି"</string>
-    <string name="zen_mode_set_up" msgid="7457957033034460064">"ସେଟ ଅପ କରନ୍ତୁ"</string>
+    <string name="zen_mode_set_up" msgid="8231201163894922821">"ସେଟ କରାଯାଇନାହିଁ"</string>
     <string name="zen_mode_no_manual_invocation" msgid="1769975741344633672">"ସେଟିଂସରେ ପରିଚାଳନା କରନ୍ତୁ"</string>
     <string name="zen_mode_active_modes" msgid="1625850411578488856">"{count,plural, =0{କୌଣସି ସକ୍ରିୟ ମୋଡ ନାହିଁ}=1{{mode} ସକ୍ରିୟ ଅଛି}other{# ମୋଡ ସକ୍ରିୟ ଅଛି}}"</string>
     <string name="zen_priority_introduction" msgid="3159291973383796646">"ଆଲାର୍ମ, ରିମାଇଣ୍ଡର୍‌, ଇଭେଣ୍ଟ ଏବଂ ଆପଣ ନିର୍ଦ୍ଦିଷ୍ଟ କରିଥିବା କଲର୍‌ଙ୍କ ବ୍ୟତୀତ ଆପଣଙ୍କ ଧ୍ୟାନ ଅନ୍ୟ କୌଣସି ଧ୍ୱନୀ ଏବଂ ଭାଇବ୍ରେଶନ୍‌ରେ ଆକର୍ଷଣ କରାଯିବନାହିଁ। ମ୍ୟୁଜିକ୍‍, ଭିଡିଓ ଏବଂ ଗେମ୍‌ ସମେତ ନିଜେ ଚଲାଇବାକୁ ବାଛିଥିବା ଅନ୍ୟ ସବୁକିଛି ଆପଣ ଶୁଣିପାରିବେ।"</string>
@@ -573,8 +573,7 @@
     <string name="notification_section_header_conversations" msgid="821834744538345661">"ବାର୍ତ୍ତାଳାପଗୁଡ଼ିକ"</string>
     <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"ସମସ୍ତ ନୀରବ ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକ ଖାଲି କରନ୍ତୁ"</string>
     <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"\"ବିରକ୍ତ କରନ୍ତୁ ନାହିଁ\" ବିକଳ୍ପ ଦ୍ୱାରା ବିଜ୍ଞପ୍ତି ପଜ୍‍ ହୋଇଛି"</string>
-    <!-- no translation found for modes_suppressing_shade_text (6037581130837903239) -->
-    <skip />
+    <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{କୌଣସି ବିଜ୍ଞପ୍ତି ନାହିଁ}=1{{mode} ଦ୍ୱାରା ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକୁ ବିରତ କରାଯାଇଛି}=2{{mode} ଏବଂ ଅନ୍ୟ ଏକ ମୋଡ ଦ୍ୱାରା ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକୁ ବିରତ କରାଯାଇଛି}other{{mode} ଏବଂ ଅନ୍ୟ # ମୋଡ ଦ୍ୱାରା ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକୁ ବିରତ କରାଯାଇଛି}}"</string>
     <string name="media_projection_action_text" msgid="3634906766918186440">"ବର୍ତ୍ତମାନ ଆରମ୍ଭ କରନ୍ତୁ"</string>
     <string name="empty_shade_text" msgid="8935967157319717412">"କୌଣସି ବିଜ୍ଞପ୍ତି ନାହିଁ"</string>
     <string name="no_unseen_notif_text" msgid="395512586119868682">"କୌଣସି ନୂଆ ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକ ନାହିଁ"</string>
@@ -673,6 +672,10 @@
     <string name="stream_notification_unavailable" msgid="4313854556205836435">"ରିଂକୁ ମ୍ୟୁଟ କରାଯାଇଥିବା ଯୋଗୁଁ ଉପଲବ୍ଧ ନାହିଁ"</string>
     <string name="stream_alarm_unavailable" msgid="4059817189292197839">"\'ବିରକ୍ତ କରନ୍ତୁ ନାହିଁ\' ଚାଲୁ ଥିବା ଯୋଗୁଁ ଉପଲବ୍ଧ ନାହିଁ"</string>
     <string name="stream_media_unavailable" msgid="6823020894438959853">"\'ବିରକ୍ତ କରନ୍ତୁ ନାହିଁ\' ଚାଲୁ ଥିବା ଯୋଗୁଁ ଉପଲବ୍ଧ ନାହିଁ"</string>
+    <!-- no translation found for stream_unavailable_by_modes (3674139029490353683) -->
+    <skip />
+    <!-- no translation found for stream_unavailable_by_unknown (6908434629318171588) -->
+    <skip />
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s। ଅନମ୍ୟୁଟ୍‍ କରିବା ପାଇଁ ଟାପ୍‍ କରନ୍ତୁ।"</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s। ଭାଇବ୍ରେଟ୍‍ ସେଟ୍‍ କରିବାକୁ ଟାପ୍‍ କରନ୍ତୁ। ଆକ୍ସେସିବିଲିଟୀ ସର୍ଭିସ୍‌ ମ୍ୟୁଟ୍‍ କରାଯାଇପାରେ।"</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s। ମ୍ୟୁଟ୍‍ କରିବାକୁ ଟାପ୍‍ କରନ୍ତୁ। ଆକ୍ସେସିବିଲିଟୀ ସର୍ଭିସ୍‌ ମ୍ୟୁଟ୍‍ କରାଯାଇପାରେ।"</string>
@@ -706,6 +709,7 @@
     <string name="show_demo_mode" msgid="3677956462273059726">"ଡେମୋ ମୋଡ୍‍ ଦେଖାନ୍ତୁ"</string>
     <string name="status_bar_ethernet" msgid="5690979758988647484">"ଇଥରନେଟ୍‌"</string>
     <string name="status_bar_alarm" msgid="87160847643623352">"ଆଲାରାମ"</string>
+    <string name="active_mode_content_description" msgid="1627555562186515927">"<xliff:g id="MODENAME">%1$s</xliff:g> ଚାଲୁ ଅଛି"</string>
     <string name="wallet_title" msgid="5369767670735827105">"ୱାଲେଟ୍"</string>
     <string name="wallet_empty_state_label" msgid="7776761245237530394">"ଆପଣଙ୍କ ଫୋନ୍ ମାଧ୍ୟମରେ ଆହୁରି ଶୀଘ୍ର, ଅଧିକ ସୁରକ୍ଷିତ କ୍ରୟ କରିବା ପାଇଁ ସେଟ୍ ଅପ୍ କରନ୍ତୁ"</string>
     <string name="wallet_app_button_label" msgid="7123784239111190992">"ସବୁ ଦେଖାନ୍ତୁ"</string>
@@ -1405,26 +1409,26 @@
     <string name="launch_touchpad_tutorial_notification_content" msgid="7931085031240753226">"ଟଚପେଡର ଜେଶ୍ଚରଗୁଡ଼ିକ ବିଷୟରେ ଜାଣନ୍ତୁ"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_title" msgid="1940023776496198762">"ଆପଣଙ୍କ କୀବୋର୍ଡ ଏବଂ ଟଚପେଡ ବ୍ୟବହାର କରି ନାଭିଗେଟ କରନ୍ତୁ"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"ଟଚପେଡ ଜେଶ୍ଚର, କୀବୋର୍ଡ ସର୍ଟକଟ ଏବଂ ଆହୁରି ଅନେକ କିଛି ବିଷୟରେ ଜାଣନ୍ତୁ"</string>
-    <string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"ବେକ ଜେଶ୍ଚର"</string>
-    <string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"ହୋମ ଜେଶ୍ଚର"</string>
+    <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"ପଛକୁ ଫେରନ୍ତୁ"</string>
+    <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"ହୋମକୁ ଯାଆନ୍ତୁ"</string>
     <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"ବର୍ତ୍ତମାନର ଆପ୍ସ ଭ୍ୟୁ କରନ୍ତୁ"</string>
     <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"ହୋଇଗଲା"</string>
     <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"ପଛକୁ ଫେରନ୍ତୁ"</string>
-    <string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"ପଛକୁ ଫେରିବା ପାଇଁ ଯେ କୌଣସି ସ୍ଥାନରେ ତିନି ଆଙ୍ଗୁଠି ବ୍ୟବହାର କରି ବାମ କିମ୍ବା ଡାହାଣକୁ ସ୍ୱାଇପ କରନ୍ତୁ।\n\nଏଥିପାଇଁ ଆପଣ କୀବୋର୍ଡ ସର୍ଟକଟ ଆକ୍ସନ + ESC ମଧ୍ୟ ବ୍ୟବହାର କରିପାରିବେ।"</string>
-    <string name="touchpad_back_gesture_success_title" msgid="7240576648330612171">"ବଢ଼ିଆ କାମ!"</string>
+    <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"ଆପଣଙ୍କ ଟଚପେଡରେ ତିନୋଟି ଆଙ୍ଗୁଠି ବ୍ୟବହାର କରି ବାମ କିମ୍ବା ଡାହାଣକୁ ସ୍ୱାଇପ କରନ୍ତୁ"</string>
+    <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"ବଢ଼ିଆ!"</string>
     <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"ଆପଣ \'ପଛକୁ ଫେରନ୍ତୁ\' ଜେଶ୍ଚର ସମ୍ପୂର୍ଣ୍ଣ କରିଛନ୍ତି।"</string>
     <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"ହୋମକୁ ଯାଆନ୍ତୁ"</string>
-    <string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"ଯେ କୌଣସି ସମୟରେ ଆପଣଙ୍କ ହୋମ ସ୍କ୍ରିନକୁ ଯିବା ପାଇଁ ଆପଣଙ୍କ ସ୍କିନର ତଳୁ ତିନୋଟି ଆଙ୍ଗୁଠିରେ ଉପରକୁ ସ୍ୱାଇପ କରନ୍ତୁ।"</string>
-    <string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"ବଢ଼ିଆ!"</string>
-    <string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"ଆପଣ \'ହୋମକୁ ଯାଆନ୍ତୁ\' ଜେଶ୍ଚର ସମ୍ପୂର୍ଣ୍ଣ କରିଛନ୍ତି।"</string>
+    <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"ଆପଣଙ୍କ ଟଚପେଡରେ ତିନୋଟି ଆଙ୍ଗୁଠିରେ ଉପରକୁ ସ୍ୱାଇପ କରନ୍ତୁ"</string>
+    <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"ବଢ଼ିଆ କାମ!"</string>
+    <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"ଆପଣ \'ହୋମକୁ ଯାଆନ୍ତୁ\' ଜେଶ୍ଚର ସମ୍ପୂର୍ଣ୍ଣ କରିଛନ୍ତି"</string>
     <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"ବର୍ତ୍ତମାନର ଆପ୍ସ ଭ୍ୟୁ କରନ୍ତୁ"</string>
-    <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"ଆପଣଙ୍କ ଟଚପେଡରେ ତିନୋଟି ଆଙ୍ଗୁଠିକୁ ବ୍ୟବହାର କରି ଉପରକୁ ସ୍ୱାଇପ କରି ଧରି ରଖନ୍ତୁ।"</string>
+    <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"ଆପଣଙ୍କ ଟଚପେଡରେ ତିନୋଟି ଆଙ୍ଗୁଠିକୁ ବ୍ୟବହାର କରି ଉପରକୁ ସ୍ୱାଇପ କରି ଧରି ରଖନ୍ତୁ"</string>
     <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"ବଢ଼ିଆ କାମ!"</string>
     <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"ଆପଣ ବର୍ତ୍ତମାନର ଆପ୍ସ ଜେଶ୍ଚରକୁ ଭ୍ୟୁ କରିବା ସମ୍ପୂର୍ଣ୍ଣ କରିଛନ୍ତି।"</string>
-    <string name="tutorial_action_key_title" msgid="2659466586996495447">"ଆକ୍ସନ କୀ"</string>
-    <string name="tutorial_action_key_guidance" msgid="5718948664616999196">"ଆପଣଙ୍କ ଆପ୍ସ ଆକ୍ସେସ କରିବା ପାଇଁ ଆପଣଙ୍କର କୀବୋର୍ଡରେ ଆକ୍ସନ କୀ\'କୁ ଦବାନ୍ତୁ।"</string>
-    <string name="tutorial_action_key_success_title" msgid="466467860120112933">"ଅଭିନନ୍ଦନ!"</string>
-    <string name="tutorial_action_key_success_body" msgid="7201991081652850430">"ଆପଣ ଆକ୍ସନ କୀ ଜେଶ୍ଚରକୁ ସମ୍ପୂର୍ଣ୍ଣ କରିଛନ୍ତି।\n\nଆକ୍ସନ + / ଆପଣଙ୍କ ପାଖରେ ଉପଲବ୍ଧ ଥିବା ସମସ୍ତ ସଟକର୍ଟକୁ ଦେଖାଇଥାଏ।"</string>
+    <string name="tutorial_action_key_title" msgid="8172535792469008169">"ସମସ୍ତ ଆପ ଭ୍ୟୁ କରନ୍ତୁ"</string>
+    <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"ଆପଣଙ୍କର କୀବୋର୍ଡରେ ଆକ୍ସନ କୀ\'କୁ ଦବାନ୍ତୁ"</string>
+    <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"ବହୁତ ବଢ଼ିଆ!"</string>
+    <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"ଆପଣ ସମସ୍ତ ଆପ୍ସ ଜେଶ୍ଚରକୁ ଭ୍ୟୁ କରିବା ସମ୍ପୂର୍ଣ୍ଣ କରିଛନ୍ତି"</string>
     <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"କୀବୋର୍ଡ ବେକଲାଇଟ"</string>
     <string name="keyboard_backlight_value" msgid="7336398765584393538">"%2$dରୁ %1$d ନମ୍ବର ଲେଭେଲ"</string>
     <string name="home_controls_dream_label" msgid="6567105701292324257">"ହୋମ କଣ୍ଟ୍ରୋଲ୍ସ"</string>
@@ -1436,6 +1440,7 @@
     <string name="all_apps_edu_toast_content" msgid="8807496014667211562">"ଆପଣଙ୍କ ସମସ୍ତ ଆପ୍ସ ଭ୍ୟୁ କରିବା ପାଇଁ ଆପଣଙ୍କ କୀବୋର୍ଡରେ ଆକ୍ସନ କୀ\'କୁ ଦବାନ୍ତୁ"</string>
     <string name="redacted_notification_single_line_title" msgid="212019960919261670">"ଲୁଚା ଯାଇଥିବା"</string>
     <string name="redacted_notification_single_line_text" msgid="8684166405005242945">"ଭ୍ୟୁ କରିବାକୁ ଅନଲକ କରନ୍ତୁ"</string>
+    <string name="contextual_education_dialog_title" msgid="4630392552837487324">"ପ୍ରାସଙ୍ଗିକ ଶିକ୍ଷା"</string>
     <string name="back_edu_notification_title" msgid="5624780717751357278">"ପଛକୁ ଫେରିବା ପାଇଁ ଆପଣଙ୍କ ଟଚପେଡକୁ ବ୍ୟବହାର କରନ୍ତୁ"</string>
     <string name="back_edu_notification_content" msgid="2497557451540954068">"ତିନୋଟି ଆଙ୍ଗୁଠିରେ ବାମ ବା ଡାହାଣକୁ ସ୍ୱାଇପ କରନ୍ତୁ। ଜେଶ୍ଚରଗୁଡ଼ିକ ବିଷୟରେ ଅଧିକ ଜାଣିବାକୁ ଟାପ କରନ୍ତୁ।"</string>
     <string name="home_edu_notification_title" msgid="6097902076909654045">"ହୋମକୁ ଯିବା ପାଇଁ ଆପଣଙ୍କ ଟଚପେଡ ବ୍ୟବହାର କରନ୍ତୁ"</string>
diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml
index 9659930..43691a4b 100644
--- a/packages/SystemUI/res/values-pa/strings.xml
+++ b/packages/SystemUI/res/values-pa/strings.xml
@@ -440,7 +440,7 @@
     <string name="zen_mode_on" msgid="9085304934016242591">"ਚਾਲੂ"</string>
     <string name="zen_mode_on_with_details" msgid="7416143430557895497">"<xliff:g id="TRIGGER_DESCRIPTION">%1$s</xliff:g> • \'ਤੇ"</string>
     <string name="zen_mode_off" msgid="1736604456618147306">"ਬੰਦ"</string>
-    <string name="zen_mode_set_up" msgid="7457957033034460064">"ਸੈੱਟਅੱਪ ਕਰੋ"</string>
+    <string name="zen_mode_set_up" msgid="8231201163894922821">"ਸੈੱਟ ਨਹੀਂ ਹੈ"</string>
     <string name="zen_mode_no_manual_invocation" msgid="1769975741344633672">"ਸੈਟਿੰਗਾਂ ਵਿੱਚ ਪ੍ਰਬੰਧਨ ਕਰੋ"</string>
     <string name="zen_mode_active_modes" msgid="1625850411578488856">"{count,plural, =0{ਕੋਈ ਕਿਰਿਆਸ਼ੀਲ ਮੋਡ ਨਹੀਂ ਹੈ}=1{{mode} ਕਿਰਿਆਸ਼ੀਲ ਹੈ}other{# ਮੋਡ ਕਿਰਿਆਸ਼ੀਲ ਹਨ}}"</string>
     <string name="zen_priority_introduction" msgid="3159291973383796646">"ਧੁਨੀਆਂ ਅਤੇ ਥਰਥਰਾਹਟਾਂ ਤੁਹਾਨੂੰ ਪਰੇਸ਼ਾਨ ਨਹੀਂ ਕਰਨਗੀਆਂ, ਸਿਵਾਏ ਅਲਾਰਮਾਂ, ਯਾਦ-ਦਹਾਨੀਆਂ, ਵਰਤਾਰਿਆਂ, ਅਤੇ ਤੁਹਾਡੇ ਵੱਲੋਂ ਨਿਰਧਾਰਤ ਕੀਤੇ ਕਾਲਰਾਂ ਦੀ ਸੂਰਤ ਵਿੱਚ। ਤੁਸੀਂ ਅਜੇ ਵੀ ਸੰਗੀਤ, ਵੀਡੀਓ ਅਤੇ ਗੇਮਾਂ ਸਮੇਤ ਆਪਣੀ ਚੋਣ ਅਨੁਸਾਰ ਕੁਝ ਵੀ ਸੁਣ ਸਕਦੇ ਹੋ।"</string>
@@ -573,8 +573,7 @@
     <string name="notification_section_header_conversations" msgid="821834744538345661">"ਗੱਲਾਂਬਾਤਾਂ"</string>
     <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"ਸਾਰੀਆਂ ਸ਼ਾਂਤ ਸੂਚਨਾਵਾਂ ਕਲੀਅਰ ਕਰੋ"</string>
     <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"\'ਪਰੇਸ਼ਾਨ ਨਾ ਕਰੋ\' ਵੱਲੋਂ ਸੂਚਨਾਵਾਂ ਨੂੰ ਰੋਕਿਆ ਗਿਆ"</string>
-    <!-- no translation found for modes_suppressing_shade_text (6037581130837903239) -->
-    <skip />
+    <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{ਕੋਈ ਸੂਚਨਾ ਨਹੀਂ ਹੈ}=1{{mode} ਵੱਲੋਂ ਸੂਚਨਾਵਾਂ ਨੂੰ ਬੰਦ ਕੀਤਾ ਗਿਆ}=2{{mode} ਅਤੇ ਇੱਕ ਹੋਰ ਮੋਡ ਵੱਲੋਂ ਸੂਚਨਾਵਾਂ ਨੂੰ ਬੰਦ ਕੀਤਾ ਗਿਆ}other{{mode} ਅਤੇ # ਹੋਰ ਮੋਡਾਂ ਵੱਲੋਂ ਸੂਚਨਾਵਾਂ ਨੂੰ ਬੰਦ ਕੀਤਾ ਗਿਆ}}"</string>
     <string name="media_projection_action_text" msgid="3634906766918186440">"ਹੁਣੇ ਸ਼ੁਰੂ ਕਰੋ"</string>
     <string name="empty_shade_text" msgid="8935967157319717412">"ਕੋਈ ਸੂਚਨਾ ਨਹੀਂ"</string>
     <string name="no_unseen_notif_text" msgid="395512586119868682">"ਕੋਈ ਨਵੀਂ ਸੂਚਨਾ ਨਹੀਂ ਹੈ"</string>
@@ -673,6 +672,10 @@
     <string name="stream_notification_unavailable" msgid="4313854556205836435">"ਉਪਲਬਧ ਨਹੀਂ ਹੈ ਕਿਉਂਕਿ ਘੰਟੀ ਮਿਊਟ ਕੀਤੀ ਹੋਈ ਹੈ"</string>
     <string name="stream_alarm_unavailable" msgid="4059817189292197839">"ਉਪਲਬਧ ਨਹੀਂ ਹੈ ਕਿਉਂਕਿ ਪਰੇਸ਼ਾਨ ਨਾ ਕਰੋ ਵਿਸ਼ੇਸ਼ਤਾ ਚਾਲੂ ਹੈ"</string>
     <string name="stream_media_unavailable" msgid="6823020894438959853">"ਉਪਲਬਧ ਨਹੀਂ ਹੈ ਕਿਉਂਕਿ ਪਰੇਸ਼ਾਨ ਨਾ ਕਰੋ ਵਿਸ਼ੇਸ਼ਤਾ ਚਾਲੂ ਹੈ"</string>
+    <!-- no translation found for stream_unavailable_by_modes (3674139029490353683) -->
+    <skip />
+    <!-- no translation found for stream_unavailable_by_unknown (6908434629318171588) -->
+    <skip />
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s। ਅਣਮਿਊਟ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ।"</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s। ਥਰਥਰਾਹਟ ਸੈੱਟ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ। ਪਹੁੰਚਯੋਗਤਾ ਸੇਵਾਵਾਂ ਮਿਊਟ ਹੋ ਸਕਦੀਆਂ ਹਨ।"</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s। ਮਿਊਟ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ। ਪਹੁੰਚਯੋਗਤਾ ਸੇਵਾਵਾਂ ਮਿਊਟ ਹੋ ਸਕਦੀਆਂ ਹਨ।"</string>
@@ -706,6 +709,7 @@
     <string name="show_demo_mode" msgid="3677956462273059726">"ਡੈਮੋ ਮੋਡ ਦੇਖੋ"</string>
     <string name="status_bar_ethernet" msgid="5690979758988647484">"ਈਥਰਨੈਟ"</string>
     <string name="status_bar_alarm" msgid="87160847643623352">"ਅਲਾਰਮ"</string>
+    <string name="active_mode_content_description" msgid="1627555562186515927">"<xliff:g id="MODENAME">%1$s</xliff:g> ਚਾਲੂ ਹੈ"</string>
     <string name="wallet_title" msgid="5369767670735827105">"Wallet"</string>
     <string name="wallet_empty_state_label" msgid="7776761245237530394">"ਆਪਣੇ ਫ਼ੋਨ ਨਾਲ ਜ਼ਿਆਦਾ ਤੇਜ਼ ਅਤੇ ਜ਼ਿਆਦਾ ਸੁਰੱਖਿਅਤ ਖਰੀਦਾਂ ਕਰਨ ਲਈ ਸੈੱਟਅੱਪ ਕਰੋ"</string>
     <string name="wallet_app_button_label" msgid="7123784239111190992">"ਸਭ ਦਿਖਾਓ"</string>
@@ -1405,26 +1409,26 @@
     <string name="launch_touchpad_tutorial_notification_content" msgid="7931085031240753226">"ਟੱਚਪੈਡ ਇਸ਼ਾਰਿਆਂ ਬਾਰੇ ਜਾਣੋ"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_title" msgid="1940023776496198762">"ਆਪਣੇ ਕੀ-ਬੋਰਡ ਅਤੇ ਟੱਚਪੈਡ ਦੀ ਵਰਤੋਂ ਕਰ ਕੇ ਨੈਵੀਗੇਟ ਕਰੋ"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"ਟੱਚਪੈਡ ਇਸ਼ਾਰੇ, ਕੀ-ਬੋਰਡ ਸ਼ਾਰਟਕੱਟ ਅਤੇ ਹੋਰ ਬਹੁਤ ਕੁਝ ਬਾਰੇ ਜਾਣੋ"</string>
-    <string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"ਪਿੱਛੇ ਜਾਣ ਦਾ ਇਸ਼ਾਰਾ"</string>
-    <string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"ਹੋਮ \'ਤੇ ਜਾਣ ਦਾ ਇਸ਼ਾਰਾ"</string>
+    <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"ਵਾਪਸ ਜਾਓ"</string>
+    <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"ਹੋਮ \'ਤੇ ਜਾਓ"</string>
     <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"ਹਾਲੀਆ ਐਪਾਂ ਦੇਖੋ"</string>
     <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"ਹੋ ਗਿਆ"</string>
     <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"ਵਾਪਸ ਜਾਓ"</string>
-    <string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"ਵਾਪਸ ਜਾਣ ਲਈ, ਟੱਚਪੈਡ \'ਤੇ ਕਿਤੇ ਵੀ ਤਿੰਨ ਉਂਗਲਾਂ ਦੀ ਵਰਤੋਂ ਕਰ ਕੇ ਖੱਬੇ ਜਾਂ ਸੱਜੇ ਪਾਸੇ ਵੱਲ ਸਵਾਈਪ ਕਰੋ।\n\nਤੁਸੀਂ ਇਸ ਲਈ ਕੀ-ਬੋਰਡ ਸ਼ਾਰਟਕੱਟ Action + ESC ਦੀ ਵਰਤੋਂ ਵੀ ਕਰ ਸਕਦੇ ਹੋ।"</string>
-    <string name="touchpad_back_gesture_success_title" msgid="7240576648330612171">"ਬਹੁਤ ਵਧੀਆ!"</string>
+    <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"ਆਪਣੇ ਟੱਚਪੈਡ \'ਤੇ ਤਿੰਨ ਉਂਗਲਾਂ ਦੀ ਵਰਤੋਂ ਕਰ ਕੇ ਖੱਬੇ ਜਾਂ ਸੱਜੇ ਪਾਸੇ ਵੱਲ ਸਵਾਈਪ ਕਰੋ"</string>
+    <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"ਵਧੀਆ!"</string>
     <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"ਤੁਸੀਂ \'ਵਾਪਸ ਜਾਓ\' ਦਾ ਇਸ਼ਾਰਾ ਪੂਰਾ ਕੀਤਾ।"</string>
     <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"ਹੋਮ \'ਤੇ ਜਾਓ"</string>
-    <string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"ਕਿਸੇ ਵੀ ਸਮੇਂ ਆਪਣੀ ਹੋਮ ਸਕ੍ਰੀਨ \'ਤੇ ਜਾਣ ਲਈ, ਤਿੰਨ ਉਂਗਲਾਂ ਨਾਲ ਆਪਣੀ ਸਕ੍ਰੀਨ ਦੇ ਹੇਠਾਂ ਤੋਂ ਉੱਪਰ ਵੱਲ ਸਵਾਈਪ ਕਰੋ।"</string>
-    <string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"ਵਧੀਆ!"</string>
-    <string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"ਤੁਸੀਂ \'ਹੋਮ \'ਤੇ ਜਾਓ\' ਦਾ ਇਸ਼ਾਰਾ ਪੂਰਾ ਕੀਤਾ।"</string>
+    <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"ਆਪਣੇ ਟੱਚਪੈਡ \'ਤੇ ਤਿੰਨ ਉਂਗਲਾਂ ਨਾਲ ਉੱਪਰ ਵੱਲ ਸਵਾਈਪ ਕਰੋ"</string>
+    <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"ਬਹੁਤ ਵਧੀਆ!"</string>
+    <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"ਤੁਸੀਂ \'ਹੋਮ \'ਤੇ ਜਾਓ\' ਦਾ ਇਸ਼ਾਰਾ ਪੂਰਾ ਕੀਤਾ"</string>
     <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"ਹਾਲੀਆ ਐਪਾਂ ਦੇਖੋ"</string>
-    <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"ਆਪਣੇ ਟੱਚਪੈਡ \'ਤੇ ਤਿੰਨ ਉਂਗਲਾਂ ਦੀ ਵਰਤੋਂ ਕਰ ਕੇ ਉੱਪਰ ਵੱਲ ਸਵਾਈਪ ਕਰ ਕੇ ਦਬਾਈ ਰੱਖੋ।"</string>
+    <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"ਆਪਣੇ ਟੱਚਪੈਡ \'ਤੇ ਤਿੰਨ ਉਂਗਲਾਂ ਦੀ ਵਰਤੋਂ ਕਰ ਕੇ ਉੱਪਰ ਵੱਲ ਸਵਾਈਪ ਕਰ ਕੇ ਦਬਾਈ ਰੱਖੋ"</string>
     <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"ਬਹੁਤ ਵਧੀਆ!"</string>
     <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"ਤੁਸੀਂ \'ਹਾਲੀਆ ਐਪਾਂ ਦੇਖੋ\' ਦਾ ਇਸ਼ਾਰਾ ਪੂਰਾ ਕੀਤਾ ਹੈ।"</string>
-    <string name="tutorial_action_key_title" msgid="2659466586996495447">"ਕਾਰਵਾਈ ਕੁੰਜੀ"</string>
-    <string name="tutorial_action_key_guidance" msgid="5718948664616999196">"ਆਪਣੀਆਂ ਐਪਾਂ ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਲਈ, ਆਪਣੇ ਕੀ-ਬੋਰਡ \'ਤੇ ਕਾਰਵਾਈ ਕੁੰਜੀ ਨੂੰ ਦਬਾਓ।"</string>
-    <string name="tutorial_action_key_success_title" msgid="466467860120112933">"ਵਧਾਈਆਂ!"</string>
-    <string name="tutorial_action_key_success_body" msgid="7201991081652850430">"ਤੁਸੀਂ \'ਕਾਰਵਾਈ ਕੁੰਜੀ\' ਦਾ ਇਸ਼ਾਰਾ ਪੂਰਾ ਕੀਤਾ।\n\nਕਾਰਵਾਈ ਬਟਨ ਅਤੇ / ਨੂੰ ਇਕੱਠੇ ਦਬਾਉਣ \'ਤੇ, ਤੁਹਾਡੇ ਕੋਲ ਉਪਲਬਧ ਸਾਰੇ ਸ਼ਾਰਟਕੱਟ ਦਿਖਦੇ ਹਨ।"</string>
+    <string name="tutorial_action_key_title" msgid="8172535792469008169">"ਸਾਰੀਆਂ ਐਪਾਂ ਦੇਖੋ"</string>
+    <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"ਆਪਣੇ ਕੀ-ਬੋਰਡ \'ਤੇ ਕਾਰਵਾਈ ਕੁੰਜੀ ਨੂੰ ਦਬਾਓ"</string>
+    <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"ਬਹੁਤ ਵਧੀਆ!"</string>
+    <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"ਤੁਸੀਂ \'ਸਾਰੀਆਂ ਐਪਾਂ ਦੇਖੋ\' ਦਾ ਇਸ਼ਾਰਾ ਪੂਰਾ ਕੀਤਾ ਹੈ"</string>
     <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"ਕੀ-ਬੋਰਡ ਬੈਕਲਾਈਟ"</string>
     <string name="keyboard_backlight_value" msgid="7336398765584393538">"%2$d ਵਿੱਚੋਂ %1$d ਪੱਧਰ"</string>
     <string name="home_controls_dream_label" msgid="6567105701292324257">"ਹੋਮ ਕੰਟਰੋਲ"</string>
@@ -1436,6 +1440,7 @@
     <string name="all_apps_edu_toast_content" msgid="8807496014667211562">"ਆਪਣੀਆਂ ਸਾਰੀਆਂ ਐਪਾਂ ਨੂੰ ਦੇਖਣ ਲਈ, ਆਪਣੇ ਕੀ-ਬੋਰਡ \'ਤੇ ਕਾਰਵਾਈ ਕੁੰਜੀ ਨੂੰ ਦਬਾਓ"</string>
     <string name="redacted_notification_single_line_title" msgid="212019960919261670">"ਅਸਪਸ਼ਟ ਬਣਾਇਆ ਗਿਆ"</string>
     <string name="redacted_notification_single_line_text" msgid="8684166405005242945">"ਦੇਖਣ ਲਈ ਅਣਲਾਕ ਕਰੋ"</string>
+    <string name="contextual_education_dialog_title" msgid="4630392552837487324">"ਸੰਦਰਭੀ ਸਿੱਖਿਆ"</string>
     <string name="back_edu_notification_title" msgid="5624780717751357278">"ਪਿੱਛੇ ਜਾਣ ਲਈ ਆਪਣੇ ਟੱਚਪੈਡ ਦੀ ਵਰਤੋਂ ਕਰੋ"</string>
     <string name="back_edu_notification_content" msgid="2497557451540954068">"ਤਿੰਨ ਉਂਗਲਾਂ ਦੀ ਵਰਤੋਂ ਕਰ ਕੇ ਖੱਬੇ ਜਾਂ ਸੱਜੇ ਪਾਸੇ ਵੱਲ ਸਵਾਈਪ ਕਰੋ। ਹੋਰ ਇਸ਼ਾਰਿਆਂ ਨੂੰ ਜਾਣਨ ਲਈ ਟੈਪ ਕਰੋ।"</string>
     <string name="home_edu_notification_title" msgid="6097902076909654045">"ਹੋਮ \'ਤੇ ਜਾਣ ਲਈ ਆਪਣੇ ਟੱਚਪੈਡ ਦੀ ਵਰਤੋਂ ਕਰੋ"</string>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index 9c97423..3e1e2d1 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -440,7 +440,7 @@
     <string name="zen_mode_on" msgid="9085304934016242591">"Wł."</string>
     <string name="zen_mode_on_with_details" msgid="7416143430557895497">"Włączone • <xliff:g id="TRIGGER_DESCRIPTION">%1$s</xliff:g>"</string>
     <string name="zen_mode_off" msgid="1736604456618147306">"Wył."</string>
-    <string name="zen_mode_set_up" msgid="7457957033034460064">"Skonfiguruj"</string>
+    <string name="zen_mode_set_up" msgid="8231201163894922821">"Nie ustawiono"</string>
     <string name="zen_mode_no_manual_invocation" msgid="1769975741344633672">"Zarządzaj w ustawieniach"</string>
     <string name="zen_mode_active_modes" msgid="1625850411578488856">"{count,plural, =0{Brak aktywnych trybów}=1{Tryb {mode} jest aktywny}few{# tryby są aktywne}many{# trybów jest aktywnych}other{# trybu jest aktywne}}"</string>
     <string name="zen_priority_introduction" msgid="3159291973383796646">"Nie będą Cię niepokoić żadne dźwięki ani wibracje z wyjątkiem alarmów, przypomnień, wydarzeń i połączeń od wybranych osób. Będziesz słyszeć wszystkie odtwarzane treści, takie jak muzyka, filmy czy gry."</string>
@@ -573,8 +573,7 @@
     <string name="notification_section_header_conversations" msgid="821834744538345661">"Rozmowy"</string>
     <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Usuń wszystkie ciche powiadomienia"</string>
     <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Powiadomienia wstrzymane przez tryb Nie przeszkadzać"</string>
-    <!-- no translation found for modes_suppressing_shade_text (6037581130837903239) -->
-    <skip />
+    <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{Brak powiadomień}=1{Powiadomienia są wstrzymane przez tryb {mode}}=2{Powiadomienia są wstrzymane przez tryb {mode} i 1 inny tryb}few{Powiadomienia są wstrzymane przez tryb {mode} i # inne tryby}many{Powiadomienia są wstrzymane przez tryb {mode} i # innych trybów}other{Powiadomienia są wstrzymane przez tryb {mode} i # innego trybu}}"</string>
     <string name="media_projection_action_text" msgid="3634906766918186440">"Rozpocznij teraz"</string>
     <string name="empty_shade_text" msgid="8935967157319717412">"Brak powiadomień"</string>
     <string name="no_unseen_notif_text" msgid="395512586119868682">"Brak nowych powiadomień"</string>
@@ -673,6 +672,10 @@
     <string name="stream_notification_unavailable" msgid="4313854556205836435">"Niedostępne, bo dzwonek jest wyciszony"</string>
     <string name="stream_alarm_unavailable" msgid="4059817189292197839">"Niedostępne, włączone jest „Nie przeszkadzać”"</string>
     <string name="stream_media_unavailable" msgid="6823020894438959853">"Niedostępne, włączone jest „Nie przeszkadzać”"</string>
+    <!-- no translation found for stream_unavailable_by_modes (3674139029490353683) -->
+    <skip />
+    <!-- no translation found for stream_unavailable_by_unknown (6908434629318171588) -->
+    <skip />
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Kliknij, by wyłączyć wyciszenie."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Kliknij, by włączyć wibracje. Ułatwienia dostępu mogą być wyciszone."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Kliknij, by wyciszyć. Ułatwienia dostępu mogą być wyciszone."</string>
@@ -706,6 +709,7 @@
     <string name="show_demo_mode" msgid="3677956462273059726">"Pokaż tryb demonstracyjny"</string>
     <string name="status_bar_ethernet" msgid="5690979758988647484">"Ethernet"</string>
     <string name="status_bar_alarm" msgid="87160847643623352">"Alarm"</string>
+    <string name="active_mode_content_description" msgid="1627555562186515927">"Aplikacja <xliff:g id="MODENAME">%1$s</xliff:g> jest włączona"</string>
     <string name="wallet_title" msgid="5369767670735827105">"Portfel"</string>
     <string name="wallet_empty_state_label" msgid="7776761245237530394">"Skonfiguruj formę płatności, aby szybciej i bezpieczniej płacić telefonem za zakupy"</string>
     <string name="wallet_app_button_label" msgid="7123784239111190992">"Pokaż wszystko"</string>
@@ -1405,26 +1409,26 @@
     <string name="launch_touchpad_tutorial_notification_content" msgid="7931085031240753226">"Poznaj gesty na touchpada"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_title" msgid="1940023776496198762">"Nawiguj za pomocą klawiatury i touchpada"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Poznaj gesty na touchpada, skróty klawiszowe i inne funkcje"</string>
-    <string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Gest przejścia wstecz"</string>
-    <string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Gest przejścia na ekran główny"</string>
+    <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"Wróć"</string>
+    <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Otwórz stronę główną"</string>
     <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Wyświetlanie ostatnich aplikacji"</string>
     <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Gotowe"</string>
     <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Wróć"</string>
-    <string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"Aby przejść wstecz, przesuń 3 palcami w lewo lub w prawo w dowolnym miejscu touchpada.\n\nMożesz też użyć do tego skrótu klawiszowego Action + ESC."</string>
-    <string name="touchpad_back_gesture_success_title" msgid="7240576648330612171">"Brawo!"</string>
+    <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"Przesuń 3 palcami w prawo lub w lewo na touchpadzie"</string>
+    <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"Super!"</string>
     <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"Gest przejścia wstecz został opanowany."</string>
     <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"Otwórz stronę główną"</string>
-    <string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"Aby w dowolnym momencie wyświetlić ekran główny, przesuń od dołu ekranu w górę 3 palcami."</string>
-    <string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Super!"</string>
-    <string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Gest przechodzenia na ekran główny został opanowany."</string>
+    <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"Przesuń 3 palcami w górę na touchpadzie"</string>
+    <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"Dobra robota!"</string>
+    <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"Gest przechodzenia na ekran główny został opanowany"</string>
     <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"Wyświetlanie ostatnich aplikacji"</string>
-    <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"Przesuń w górę za pomocą 3 palców na touchpadzie i przytrzymaj."</string>
+    <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"Przesuń w górę za pomocą 3 palców na touchpadzie i przytrzymaj"</string>
     <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Brawo!"</string>
     <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Znasz już gest wyświetlania ostatnio używanych aplikacji."</string>
-    <string name="tutorial_action_key_title" msgid="2659466586996495447">"Klawisz działania"</string>
-    <string name="tutorial_action_key_guidance" msgid="5718948664616999196">"Aby uzyskać dostęp do aplikacji, naciśnij klawisz działania na klawiaturze."</string>
-    <string name="tutorial_action_key_success_title" msgid="466467860120112933">"Gratulacje!"</string>
-    <string name="tutorial_action_key_success_body" msgid="7201991081652850430">"Gest klawisza działania został opanowany.\n\nKlawisz działania + / pokazuje wszystkie dostępne skróty."</string>
+    <string name="tutorial_action_key_title" msgid="8172535792469008169">"Wyświetl wszystkie aplikacje"</string>
+    <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Naciśnij klawisz działania na klawiaturze"</string>
+    <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Brawo!"</string>
+    <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Znasz już gest wyświetlania wszystkich aplikacji"</string>
     <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Podświetlenie klawiatury"</string>
     <string name="keyboard_backlight_value" msgid="7336398765584393538">"Poziom %1$d z %2$d"</string>
     <string name="home_controls_dream_label" msgid="6567105701292324257">"Sterowanie domem"</string>
@@ -1436,6 +1440,7 @@
     <string name="all_apps_edu_toast_content" msgid="8807496014667211562">"Aby wyświetlić wszystkie swoje aplikacje, naciśnij klawisz działania na klawiaturze"</string>
     <string name="redacted_notification_single_line_title" msgid="212019960919261670">"Usunięto"</string>
     <string name="redacted_notification_single_line_text" msgid="8684166405005242945">"Odblokuj, aby zobaczyć"</string>
+    <string name="contextual_education_dialog_title" msgid="4630392552837487324">"Edukacja kontekstowa"</string>
     <string name="back_edu_notification_title" msgid="5624780717751357278">"Przechodzenie wstecz za pomocą touchpada"</string>
     <string name="back_edu_notification_content" msgid="2497557451540954068">"Przesuń w prawo lub lewo za pomocą 3 palców. Kliknij, aby poznać więcej gestów."</string>
     <string name="home_edu_notification_title" msgid="6097902076909654045">"Przechodzenie do ekranu głównego za pomocą touchpada"</string>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index 399523e..c34f2f7 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -440,7 +440,7 @@
     <string name="zen_mode_on" msgid="9085304934016242591">"Ativado"</string>
     <string name="zen_mode_on_with_details" msgid="7416143430557895497">"Ativado • <xliff:g id="TRIGGER_DESCRIPTION">%1$s</xliff:g>"</string>
     <string name="zen_mode_off" msgid="1736604456618147306">"Desativado"</string>
-    <string name="zen_mode_set_up" msgid="7457957033034460064">"Configurar"</string>
+    <string name="zen_mode_set_up" msgid="8231201163894922821">"Não definido"</string>
     <string name="zen_mode_no_manual_invocation" msgid="1769975741344633672">"Gerenciar nas configurações"</string>
     <string name="zen_mode_active_modes" msgid="1625850411578488856">"{count,plural, =0{Nenhum modo ativo}=1{{mode} está ativo}one{# modo está ativo}many{# de modos estão ativos}other{# modos estão ativos}}"</string>
     <string name="zen_priority_introduction" msgid="3159291973383796646">"Você não será perturbado por sons e vibrações, exceto alarmes, lembretes, eventos e chamadas de pessoas especificadas. No entanto, você ouvirá tudo o que decidir reproduzir, como músicas, vídeos e jogos."</string>
@@ -573,8 +573,7 @@
     <string name="notification_section_header_conversations" msgid="821834744538345661">"Conversas"</string>
     <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Apagar todas as notificações silenciosas"</string>
     <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Notificações pausadas pelo modo \"Não perturbe\""</string>
-    <!-- no translation found for modes_suppressing_shade_text (6037581130837903239) -->
-    <skip />
+    <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{Sem notificações}=1{Notificações pausadas pelo modo {mode}}=2{Notificações pausadas por {mode} e mais um modo}one{Notificações pausadas por {mode} e mais # modo}many{Notificações pausadas por {mode} e mais # de modos}other{Notificações pausadas por {mode} e mais # modos}}"</string>
     <string name="media_projection_action_text" msgid="3634906766918186440">"Iniciar agora"</string>
     <string name="empty_shade_text" msgid="8935967157319717412">"Sem notificações"</string>
     <string name="no_unseen_notif_text" msgid="395512586119868682">"Nenhuma notificação nova"</string>
@@ -673,6 +672,10 @@
     <string name="stream_notification_unavailable" msgid="4313854556205836435">"Indisponível com o toque silenciado"</string>
     <string name="stream_alarm_unavailable" msgid="4059817189292197839">"Indisponível com o Não perturbe ativado"</string>
     <string name="stream_media_unavailable" msgid="6823020894438959853">"Indisponível com o Não perturbe ativado"</string>
+    <!-- no translation found for stream_unavailable_by_modes (3674139029490353683) -->
+    <skip />
+    <!-- no translation found for stream_unavailable_by_unknown (6908434629318171588) -->
+    <skip />
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Toque para ativar o som."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Toque para configurar para vibrar. É possível que os serviços de acessibilidade sejam silenciados."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Toque para silenciar. É possível que os serviços de acessibilidade sejam silenciados."</string>
@@ -706,6 +709,7 @@
     <string name="show_demo_mode" msgid="3677956462273059726">"Mostrar modo de demonstração"</string>
     <string name="status_bar_ethernet" msgid="5690979758988647484">"Ethernet"</string>
     <string name="status_bar_alarm" msgid="87160847643623352">"Alarme"</string>
+    <string name="active_mode_content_description" msgid="1627555562186515927">"O modo <xliff:g id="MODENAME">%1$s</xliff:g> está ativado"</string>
     <string name="wallet_title" msgid="5369767670735827105">"Carteira"</string>
     <string name="wallet_empty_state_label" msgid="7776761245237530394">"Prepare tudo para fazer compras mais rápidas e seguras com seu smartphone"</string>
     <string name="wallet_app_button_label" msgid="7123784239111190992">"Mostrar tudo"</string>
@@ -1405,26 +1409,26 @@
     <string name="launch_touchpad_tutorial_notification_content" msgid="7931085031240753226">"Aprenda gestos do touchpad"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_title" msgid="1940023776496198762">"Navegue usando o teclado e o touchpad"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Aprenda gestos do touchpad, atalhos do teclado e muito mais"</string>
-    <string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Gesto de volta"</string>
-    <string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Gesto de início"</string>
+    <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"Voltar"</string>
+    <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Ir para a página inicial"</string>
     <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Ver os apps recentes"</string>
     <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Concluído"</string>
     <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Voltar"</string>
-    <string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"Para voltar, deslize para a esquerda ou direita usando 3 dedos em qualquer lugar do touchpad.\n\nVocê também pode usar o atalho de teclado Ação + ESC."</string>
-    <string name="touchpad_back_gesture_success_title" msgid="7240576648330612171">"Muito bem!"</string>
+    <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"Deslize para a esquerda ou direita com 3 dedos no touchpad"</string>
+    <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"Legal!"</string>
     <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"Você concluiu o gesto para voltar."</string>
     <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"Ir para a página inicial"</string>
-    <string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"Para acessar sua tela inicial a qualquer momento, deslize de baixo para cima na tela com três dedos."</string>
-    <string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Legal!"</string>
-    <string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Você concluiu o gesto para acessar a tela inicial."</string>
+    <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"Deslize para cima com 3 dedos no touchpad"</string>
+    <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"Muito bem!"</string>
+    <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"Você concluiu o gesto para acessar a tela inicial"</string>
     <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"Ver os apps recentes"</string>
-    <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"Deslize para cima e pressione com 3 dedos no touchpad."</string>
+    <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"Deslize para cima e pressione com 3 dedos no touchpad"</string>
     <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Muito bem!"</string>
     <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Você concluiu o gesto para ver os apps recentes."</string>
-    <string name="tutorial_action_key_title" msgid="2659466586996495447">"Tecla de ação"</string>
-    <string name="tutorial_action_key_guidance" msgid="5718948664616999196">"Para acessar os apps, pressione a tecla de ação no teclado."</string>
-    <string name="tutorial_action_key_success_title" msgid="466467860120112933">"Parabéns!"</string>
-    <string name="tutorial_action_key_success_body" msgid="7201991081652850430">"Você concluiu o gesto da tecla de ação.\n\nA tecla de ação + / mostra todos os atalhos disponíveis."</string>
+    <string name="tutorial_action_key_title" msgid="8172535792469008169">"Ver todos os apps"</string>
+    <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Pressione a tecla de ação no teclado"</string>
+    <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Muito bem!"</string>
+    <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Você concluiu o gesto para ver todos os apps"</string>
     <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Luz de fundo do teclado"</string>
     <string name="keyboard_backlight_value" msgid="7336398765584393538">"Nível %1$d de %2$d"</string>
     <string name="home_controls_dream_label" msgid="6567105701292324257">"Automação residencial"</string>
@@ -1436,8 +1440,7 @@
     <string name="all_apps_edu_toast_content" msgid="8807496014667211562">"Para ver todos os apps, pressione a tecla de ação no teclado"</string>
     <string name="redacted_notification_single_line_title" msgid="212019960919261670">"Encoberto"</string>
     <string name="redacted_notification_single_line_text" msgid="8684166405005242945">"Desbloquear para visualizar"</string>
-    <!-- no translation found for contextual_education_dialog_title (4630392552837487324) -->
-    <skip />
+    <string name="contextual_education_dialog_title" msgid="4630392552837487324">"Educação contextual"</string>
     <string name="back_edu_notification_title" msgid="5624780717751357278">"Use o touchpad para voltar"</string>
     <string name="back_edu_notification_content" msgid="2497557451540954068">"Deslize para a esquerda ou direita usando três dedos. Toque para aprender outros gestos."</string>
     <string name="home_edu_notification_title" msgid="6097902076909654045">"Use o touchpad para acessar a tela inicial"</string>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index e87564d..04d3ec5 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -440,7 +440,7 @@
     <string name="zen_mode_on" msgid="9085304934016242591">"Ativado"</string>
     <string name="zen_mode_on_with_details" msgid="7416143430557895497">"Ativado • <xliff:g id="TRIGGER_DESCRIPTION">%1$s</xliff:g>"</string>
     <string name="zen_mode_off" msgid="1736604456618147306">"Desativado"</string>
-    <string name="zen_mode_set_up" msgid="7457957033034460064">"Configurar"</string>
+    <string name="zen_mode_set_up" msgid="8231201163894922821">"Não definido"</string>
     <string name="zen_mode_no_manual_invocation" msgid="1769975741344633672">"Gerir nas definições"</string>
     <string name="zen_mode_active_modes" msgid="1625850411578488856">"{count,plural, =0{Nenhum modo ativo}=1{{mode} está ativo}many{# modos estão ativos}other{# modos estão ativos}}"</string>
     <string name="zen_priority_introduction" msgid="3159291973383796646">"Não é incomodado por sons e vibrações, exceto de alarmes, lembretes, eventos e autores de chamadas que especificar. Continua a ouvir tudo o que optar por reproduzir, incluindo música, vídeos e jogos."</string>
@@ -573,8 +573,7 @@
     <string name="notification_section_header_conversations" msgid="821834744538345661">"Conversas"</string>
     <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Limpar todas as notificações silenciosas"</string>
     <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Notificações colocadas em pausa pelo modo Não incomodar."</string>
-    <!-- no translation found for modes_suppressing_shade_text (6037581130837903239) -->
-    <skip />
+    <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{Sem notificações}=1{Notificações pausadas pelo modo {mode}}=2{Notificações pausadas pelo modo {mode} e mais um modo}many{Notificações pausadas pelo modo {mode} e mais # modos}other{Notificações pausadas pelo modo {mode} e mais # modos}}"</string>
     <string name="media_projection_action_text" msgid="3634906766918186440">"Começar agora"</string>
     <string name="empty_shade_text" msgid="8935967157319717412">"Sem notificações"</string>
     <string name="no_unseen_notif_text" msgid="395512586119868682">"Não existem novas notificações"</string>
@@ -673,6 +672,10 @@
     <string name="stream_notification_unavailable" msgid="4313854556205836435">"Indisponível com toque desativado"</string>
     <string name="stream_alarm_unavailable" msgid="4059817189292197839">"Indisponível porque Não incomodar está ativado"</string>
     <string name="stream_media_unavailable" msgid="6823020894438959853">"Indisponível com Não incomodar ativado"</string>
+    <!-- no translation found for stream_unavailable_by_modes (3674139029490353683) -->
+    <skip />
+    <!-- no translation found for stream_unavailable_by_unknown (6908434629318171588) -->
+    <skip />
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Toque para reativar o som."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Toque para ativar a vibração. Os serviços de acessibilidade podem ser silenciados."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Toque para desativar o som. Os serviços de acessibilidade podem ser silenciados."</string>
@@ -706,6 +709,7 @@
     <string name="show_demo_mode" msgid="3677956462273059726">"Mostrar modo de demonstração"</string>
     <string name="status_bar_ethernet" msgid="5690979758988647484">"Ethernet"</string>
     <string name="status_bar_alarm" msgid="87160847643623352">"Alarme"</string>
+    <string name="active_mode_content_description" msgid="1627555562186515927">"O modo <xliff:g id="MODENAME">%1$s</xliff:g> está ativado"</string>
     <string name="wallet_title" msgid="5369767670735827105">"Carteira"</string>
     <string name="wallet_empty_state_label" msgid="7776761245237530394">"Configure para efetuar pagamentos mais rápidos e seguros com o seu telemóvel"</string>
     <string name="wallet_app_button_label" msgid="7123784239111190992">"Mostrar tudo"</string>
@@ -1405,26 +1409,26 @@
     <string name="launch_touchpad_tutorial_notification_content" msgid="7931085031240753226">"Aprenda gestos do touchpad"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_title" msgid="1940023776496198762">"Navegue com o teclado e o touchpad"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Aprenda gestos do touchpad, atalhos de teclado e muito mais"</string>
-    <string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Gesto para retroceder"</string>
-    <string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Gesto para aceder ao ecrã principal"</string>
+    <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"Voltar"</string>
+    <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Aceder ao ecrã principal"</string>
     <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Ver apps recentes"</string>
     <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Concluir"</string>
     <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Voltar"</string>
-    <string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"Para retroceder, deslize rapidamente para a esquerda ou direita com 3 dedos em qualquer parte do touchpad.\n\nPara o fazer, também pode usar o atalho de teclado Ação + ESC."</string>
-    <string name="touchpad_back_gesture_success_title" msgid="7240576648330612171">"Muito bem!"</string>
+    <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"Deslize rapidamente para a esquerda ou direita com 3 dedos no touchpad"</string>
+    <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"Boa!"</string>
     <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"Concluiu o gesto para retroceder."</string>
     <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"Aceder ao ecrã principal"</string>
-    <string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"Para aceder ao ecrã principal em qualquer altura, deslize rapidamente com 3 dedos de baixo para cima no ecrã."</string>
-    <string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Boa!"</string>
-    <string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Concluiu o gesto para aceder ao ecrã principal."</string>
+    <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"Deslize para cima com 3 dedos no touchpad"</string>
+    <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"É assim mesmo!"</string>
+    <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"Concluiu o gesto para aceder ao ecrã principal"</string>
     <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"Ver apps recentes"</string>
-    <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"Deslize rapidamente para cima e mantenha premido com 3 dedos no touchpad."</string>
+    <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"Deslize rapidamente para cima e mantenha premido com 3 dedos no touchpad"</string>
     <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Muito bem!"</string>
     <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Concluiu o gesto para ver as apps recentes."</string>
-    <string name="tutorial_action_key_title" msgid="2659466586996495447">"Tecla de ação"</string>
-    <string name="tutorial_action_key_guidance" msgid="5718948664616999196">"Para aceder às suas apps, prima a tecla de ação no teclado."</string>
-    <string name="tutorial_action_key_success_title" msgid="466467860120112933">"Parabéns!"</string>
-    <string name="tutorial_action_key_success_body" msgid="7201991081652850430">"Concluiu o gesto da tecla de ação.\n\nA ação + / mostra todos os atalhos que tem disponíveis."</string>
+    <string name="tutorial_action_key_title" msgid="8172535792469008169">"Ver todas as apps"</string>
+    <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Prima a tecla de ação no teclado"</string>
+    <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Muito bem!"</string>
+    <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Concluiu o gesto para ver todas as apps"</string>
     <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Luz do teclado"</string>
     <string name="keyboard_backlight_value" msgid="7336398765584393538">"Nível %1$d de %2$d"</string>
     <string name="home_controls_dream_label" msgid="6567105701292324257">"Controlos domésticos"</string>
@@ -1436,6 +1440,7 @@
     <string name="all_apps_edu_toast_content" msgid="8807496014667211562">"Para ver todas as suas apps, prima a tecla de ação no teclado"</string>
     <string name="redacted_notification_single_line_title" msgid="212019960919261670">"Revisto"</string>
     <string name="redacted_notification_single_line_text" msgid="8684166405005242945">"Desbloqueie para ver"</string>
+    <string name="contextual_education_dialog_title" msgid="4630392552837487324">"Educação contextual"</string>
     <string name="back_edu_notification_title" msgid="5624780717751357278">"Use o touchpad para retroceder"</string>
     <string name="back_edu_notification_content" msgid="2497557451540954068">"Deslize rapidamente para a esquerda ou direita com 3 dedos. Toque para aprender mais gestos."</string>
     <string name="home_edu_notification_title" msgid="6097902076909654045">"Use o touchpad para aceder ao ecrã principal"</string>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index 5c9679d..c34f2f7 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -440,7 +440,7 @@
     <string name="zen_mode_on" msgid="9085304934016242591">"Ativado"</string>
     <string name="zen_mode_on_with_details" msgid="7416143430557895497">"Ativado • <xliff:g id="TRIGGER_DESCRIPTION">%1$s</xliff:g>"</string>
     <string name="zen_mode_off" msgid="1736604456618147306">"Desativado"</string>
-    <string name="zen_mode_set_up" msgid="7457957033034460064">"Configurar"</string>
+    <string name="zen_mode_set_up" msgid="8231201163894922821">"Não definido"</string>
     <string name="zen_mode_no_manual_invocation" msgid="1769975741344633672">"Gerenciar nas configurações"</string>
     <string name="zen_mode_active_modes" msgid="1625850411578488856">"{count,plural, =0{Nenhum modo ativo}=1{{mode} está ativo}one{# modo está ativo}many{# de modos estão ativos}other{# modos estão ativos}}"</string>
     <string name="zen_priority_introduction" msgid="3159291973383796646">"Você não será perturbado por sons e vibrações, exceto alarmes, lembretes, eventos e chamadas de pessoas especificadas. No entanto, você ouvirá tudo o que decidir reproduzir, como músicas, vídeos e jogos."</string>
@@ -573,8 +573,7 @@
     <string name="notification_section_header_conversations" msgid="821834744538345661">"Conversas"</string>
     <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Apagar todas as notificações silenciosas"</string>
     <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Notificações pausadas pelo modo \"Não perturbe\""</string>
-    <!-- no translation found for modes_suppressing_shade_text (6037581130837903239) -->
-    <skip />
+    <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{Sem notificações}=1{Notificações pausadas pelo modo {mode}}=2{Notificações pausadas por {mode} e mais um modo}one{Notificações pausadas por {mode} e mais # modo}many{Notificações pausadas por {mode} e mais # de modos}other{Notificações pausadas por {mode} e mais # modos}}"</string>
     <string name="media_projection_action_text" msgid="3634906766918186440">"Iniciar agora"</string>
     <string name="empty_shade_text" msgid="8935967157319717412">"Sem notificações"</string>
     <string name="no_unseen_notif_text" msgid="395512586119868682">"Nenhuma notificação nova"</string>
@@ -673,6 +672,10 @@
     <string name="stream_notification_unavailable" msgid="4313854556205836435">"Indisponível com o toque silenciado"</string>
     <string name="stream_alarm_unavailable" msgid="4059817189292197839">"Indisponível com o Não perturbe ativado"</string>
     <string name="stream_media_unavailable" msgid="6823020894438959853">"Indisponível com o Não perturbe ativado"</string>
+    <!-- no translation found for stream_unavailable_by_modes (3674139029490353683) -->
+    <skip />
+    <!-- no translation found for stream_unavailable_by_unknown (6908434629318171588) -->
+    <skip />
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Toque para ativar o som."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Toque para configurar para vibrar. É possível que os serviços de acessibilidade sejam silenciados."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Toque para silenciar. É possível que os serviços de acessibilidade sejam silenciados."</string>
@@ -706,6 +709,7 @@
     <string name="show_demo_mode" msgid="3677956462273059726">"Mostrar modo de demonstração"</string>
     <string name="status_bar_ethernet" msgid="5690979758988647484">"Ethernet"</string>
     <string name="status_bar_alarm" msgid="87160847643623352">"Alarme"</string>
+    <string name="active_mode_content_description" msgid="1627555562186515927">"O modo <xliff:g id="MODENAME">%1$s</xliff:g> está ativado"</string>
     <string name="wallet_title" msgid="5369767670735827105">"Carteira"</string>
     <string name="wallet_empty_state_label" msgid="7776761245237530394">"Prepare tudo para fazer compras mais rápidas e seguras com seu smartphone"</string>
     <string name="wallet_app_button_label" msgid="7123784239111190992">"Mostrar tudo"</string>
@@ -1405,26 +1409,26 @@
     <string name="launch_touchpad_tutorial_notification_content" msgid="7931085031240753226">"Aprenda gestos do touchpad"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_title" msgid="1940023776496198762">"Navegue usando o teclado e o touchpad"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Aprenda gestos do touchpad, atalhos do teclado e muito mais"</string>
-    <string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Gesto de volta"</string>
-    <string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Gesto de início"</string>
+    <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"Voltar"</string>
+    <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Ir para a página inicial"</string>
     <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Ver os apps recentes"</string>
     <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Concluído"</string>
     <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Voltar"</string>
-    <string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"Para voltar, deslize para a esquerda ou direita usando 3 dedos em qualquer lugar do touchpad.\n\nVocê também pode usar o atalho de teclado Ação + ESC."</string>
-    <string name="touchpad_back_gesture_success_title" msgid="7240576648330612171">"Muito bem!"</string>
+    <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"Deslize para a esquerda ou direita com 3 dedos no touchpad"</string>
+    <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"Legal!"</string>
     <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"Você concluiu o gesto para voltar."</string>
     <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"Ir para a página inicial"</string>
-    <string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"Para acessar sua tela inicial a qualquer momento, deslize de baixo para cima na tela com três dedos."</string>
-    <string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Legal!"</string>
-    <string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Você concluiu o gesto para acessar a tela inicial."</string>
+    <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"Deslize para cima com 3 dedos no touchpad"</string>
+    <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"Muito bem!"</string>
+    <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"Você concluiu o gesto para acessar a tela inicial"</string>
     <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"Ver os apps recentes"</string>
-    <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"Deslize para cima e pressione com 3 dedos no touchpad."</string>
+    <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"Deslize para cima e pressione com 3 dedos no touchpad"</string>
     <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Muito bem!"</string>
     <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Você concluiu o gesto para ver os apps recentes."</string>
-    <string name="tutorial_action_key_title" msgid="2659466586996495447">"Tecla de ação"</string>
-    <string name="tutorial_action_key_guidance" msgid="5718948664616999196">"Para acessar os apps, pressione a tecla de ação no teclado."</string>
-    <string name="tutorial_action_key_success_title" msgid="466467860120112933">"Parabéns!"</string>
-    <string name="tutorial_action_key_success_body" msgid="7201991081652850430">"Você concluiu o gesto da tecla de ação.\n\nA tecla de ação + / mostra todos os atalhos disponíveis."</string>
+    <string name="tutorial_action_key_title" msgid="8172535792469008169">"Ver todos os apps"</string>
+    <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Pressione a tecla de ação no teclado"</string>
+    <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Muito bem!"</string>
+    <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Você concluiu o gesto para ver todos os apps"</string>
     <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Luz de fundo do teclado"</string>
     <string name="keyboard_backlight_value" msgid="7336398765584393538">"Nível %1$d de %2$d"</string>
     <string name="home_controls_dream_label" msgid="6567105701292324257">"Automação residencial"</string>
@@ -1436,6 +1440,7 @@
     <string name="all_apps_edu_toast_content" msgid="8807496014667211562">"Para ver todos os apps, pressione a tecla de ação no teclado"</string>
     <string name="redacted_notification_single_line_title" msgid="212019960919261670">"Encoberto"</string>
     <string name="redacted_notification_single_line_text" msgid="8684166405005242945">"Desbloquear para visualizar"</string>
+    <string name="contextual_education_dialog_title" msgid="4630392552837487324">"Educação contextual"</string>
     <string name="back_edu_notification_title" msgid="5624780717751357278">"Use o touchpad para voltar"</string>
     <string name="back_edu_notification_content" msgid="2497557451540954068">"Deslize para a esquerda ou direita usando três dedos. Toque para aprender outros gestos."</string>
     <string name="home_edu_notification_title" msgid="6097902076909654045">"Use o touchpad para acessar a tela inicial"</string>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index 8c76491..ba28026 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -440,7 +440,7 @@
     <string name="zen_mode_on" msgid="9085304934016242591">"Activat"</string>
     <string name="zen_mode_on_with_details" msgid="7416143430557895497">"Activat • <xliff:g id="TRIGGER_DESCRIPTION">%1$s</xliff:g>"</string>
     <string name="zen_mode_off" msgid="1736604456618147306">"Dezactivat"</string>
-    <string name="zen_mode_set_up" msgid="7457957033034460064">"Configurează"</string>
+    <string name="zen_mode_set_up" msgid="8231201163894922821">"Nesetat"</string>
     <string name="zen_mode_no_manual_invocation" msgid="1769975741344633672">"Gestionează în setări"</string>
     <string name="zen_mode_active_modes" msgid="1625850411578488856">"{count,plural, =0{Niciun mod activ}=1{{mode} este activ}few{# moduri sunt active}other{# de moduri sunt active}}"</string>
     <string name="zen_priority_introduction" msgid="3159291973383796646">"Se vor anunța prin sunete și vibrații numai alarmele, mementourile, evenimentele și apelanții specificați de tine. Totuși, vei auzi tot ce alegi să redai, inclusiv muzică, videoclipuri și jocuri."</string>
@@ -573,8 +573,7 @@
     <string name="notification_section_header_conversations" msgid="821834744538345661">"Conversații"</string>
     <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Șterge toate notificările silențioase"</string>
     <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Notificări întrerupte prin „Nu deranja”"</string>
-    <!-- no translation found for modes_suppressing_shade_text (6037581130837903239) -->
-    <skip />
+    <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{Nicio notificare}=1{Notificările au fost întrerupte de {mode}}=2{Notificările au fost întrerupte de {mode} și de un alt mod}few{Notificările au fost întrerupte de {mode} și de alte # moduri}other{Notificările au fost întrerupte de {mode} și de alte # de moduri}}"</string>
     <string name="media_projection_action_text" msgid="3634906766918186440">"Începe acum"</string>
     <string name="empty_shade_text" msgid="8935967157319717412">"Nicio notificare"</string>
     <string name="no_unseen_notif_text" msgid="395512586119868682">"Nicio notificare nouă"</string>
@@ -673,6 +672,10 @@
     <string name="stream_notification_unavailable" msgid="4313854556205836435">"Indisponibil; soneria este dezactivată"</string>
     <string name="stream_alarm_unavailable" msgid="4059817189292197839">"Indisponibil; funcția Nu deranja e activată"</string>
     <string name="stream_media_unavailable" msgid="6823020894438959853">"Indisponibil; funcția Nu deranja e activată"</string>
+    <!-- no translation found for stream_unavailable_by_modes (3674139029490353683) -->
+    <skip />
+    <!-- no translation found for stream_unavailable_by_unknown (6908434629318171588) -->
+    <skip />
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Atinge pentru a activa sunetul."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Atinge pentru a seta vibrarea. Sunetul se poate dezactiva pentru serviciile de accesibilitate."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Atinge pentru a dezactiva sunetul. Sunetul se poate dezactiva pentru serviciile de accesibilitate."</string>
@@ -706,6 +709,7 @@
     <string name="show_demo_mode" msgid="3677956462273059726">"Afișează modul demonstrativ"</string>
     <string name="status_bar_ethernet" msgid="5690979758988647484">"Ethernet"</string>
     <string name="status_bar_alarm" msgid="87160847643623352">"Alarmă"</string>
+    <string name="active_mode_content_description" msgid="1627555562186515927">"<xliff:g id="MODENAME">%1$s</xliff:g> este activ"</string>
     <string name="wallet_title" msgid="5369767670735827105">"Portofel"</string>
     <string name="wallet_empty_state_label" msgid="7776761245237530394">"Configurează pentru a face achiziții mai rapide și mai sigure cu telefonul"</string>
     <string name="wallet_app_button_label" msgid="7123784239111190992">"Afișează-le pe toate"</string>
@@ -1405,26 +1409,26 @@
     <string name="launch_touchpad_tutorial_notification_content" msgid="7931085031240753226">"Învață gesturi pentru touchpad"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_title" msgid="1940023776496198762">"Navighează folosind tastatura și touchpadul"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Învață gesturi pentru touchpad, comenzi rapide de la tastatură și altele"</string>
-    <string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Gestul Înapoi"</string>
-    <string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Gestul Ecran de pornire"</string>
+    <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"Înapoi"</string>
+    <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Înapoi la pagina de pornire"</string>
     <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Vezi aplicațiile recente"</string>
     <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Gata"</string>
     <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Înapoi"</string>
-    <string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"Pentru a reveni, glisează spre stânga sau spre dreapta cu trei degete oriunde pe touchpad.\n\nPoți folosi și comanda rapidă de la tastatură Action + ESC pentru aceasta."</string>
-    <string name="touchpad_back_gesture_success_title" msgid="7240576648330612171">"Excelent!"</string>
+    <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"Glisează la stânga sau la dreapta cu trei degete pe touchpad"</string>
+    <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"Bravo!"</string>
     <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"Ai finalizat gestul Înapoi."</string>
     <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"Înapoi la pagina de pornire"</string>
-    <string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"Pentru a accesa oricând ecranul de pornire, glisează în sus cu trei degete din partea de jos a ecranului"</string>
-    <string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Bravo!"</string>
-    <string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Ai finalizat gestul „accesează ecranul de pornire”."</string>
+    <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"Glisează în sus cu trei degete oriunde pe touchpad"</string>
+    <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"Excelent!"</string>
+    <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"Ai finalizat gestul „accesează ecranul de pornire”"</string>
     <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"Vezi aplicațiile recente"</string>
-    <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"Glisează în sus și ține apăsat cu trei degete pe touchpad."</string>
+    <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"Glisează în sus și ține apăsat cu trei degete pe touchpad"</string>
     <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Excelent!"</string>
     <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Ai finalizat gestul pentru afișarea aplicațiilor recente."</string>
-    <string name="tutorial_action_key_title" msgid="2659466586996495447">"Tasta de acțiuni"</string>
-    <string name="tutorial_action_key_guidance" msgid="5718948664616999196">"Pentru a accesa aplicațiile, apasă tasta de acțiuni de pe tastatură."</string>
-    <string name="tutorial_action_key_success_title" msgid="466467860120112933">"Felicitări!"</string>
-    <string name="tutorial_action_key_success_body" msgid="7201991081652850430">"Ai finalizat gestul cu tasta de acțiuni.\n\nAcțiune + / afișează toate comenzile rapide disponibile."</string>
+    <string name="tutorial_action_key_title" msgid="8172535792469008169">"Vezi toate aplicațiile"</string>
+    <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Apasă tasta de acțiuni de pe tastatură"</string>
+    <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Felicitări!"</string>
+    <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Ai finalizat gestul pentru afișarea tuturor aplicațiilor"</string>
     <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Iluminarea din spate a tastaturii"</string>
     <string name="keyboard_backlight_value" msgid="7336398765584393538">"Nivelul %1$d din %2$d"</string>
     <string name="home_controls_dream_label" msgid="6567105701292324257">"Comenzi pentru locuință"</string>
@@ -1436,6 +1440,7 @@
     <string name="all_apps_edu_toast_content" msgid="8807496014667211562">"Ca să vezi toate aplicațiile, apasă tasta de acțiuni de pe tastatură"</string>
     <string name="redacted_notification_single_line_title" msgid="212019960919261670">"Ascunsă"</string>
     <string name="redacted_notification_single_line_text" msgid="8684166405005242945">"Deblochează pentru a afișa"</string>
+    <string name="contextual_education_dialog_title" msgid="4630392552837487324">"Educație contextuală"</string>
     <string name="back_edu_notification_title" msgid="5624780717751357278">"Folosește-ți touchpadul ca să revii"</string>
     <string name="back_edu_notification_content" msgid="2497557451540954068">"Glisează la stânga sau la dreapta cu trei degete. Atinge ca să înveți mai multe gesturi."</string>
     <string name="home_edu_notification_title" msgid="6097902076909654045">"Folosește-ți touchpadul ca să accesezi pagina de pornire"</string>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index c5b6479..bd5a5a1 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -440,7 +440,7 @@
     <string name="zen_mode_on" msgid="9085304934016242591">"Включено"</string>
     <string name="zen_mode_on_with_details" msgid="7416143430557895497">"Вкл. • <xliff:g id="TRIGGER_DESCRIPTION">%1$s</xliff:g>"</string>
     <string name="zen_mode_off" msgid="1736604456618147306">"Отключено"</string>
-    <string name="zen_mode_set_up" msgid="7457957033034460064">"Настроить"</string>
+    <string name="zen_mode_set_up" msgid="8231201163894922821">"Не задано"</string>
     <string name="zen_mode_no_manual_invocation" msgid="1769975741344633672">"Открыть настройки"</string>
     <string name="zen_mode_active_modes" msgid="1625850411578488856">"{count,plural, =0{Включено 0 режимов}=1{Включен режим \"{mode}\"}one{Включен # режим}few{Включено # режима}many{Включено # режимов}other{Включено # режима}}"</string>
     <string name="zen_priority_introduction" msgid="3159291973383796646">"Вас не будут отвлекать звуки и вибрация, за исключением сигналов будильника, напоминаний, уведомлений о мероприятиях и звонков от помеченных контактов. Вы по-прежнему будете слышать включенную вами музыку, видео, игры и т. д."</string>
@@ -573,8 +573,7 @@
     <string name="notification_section_header_conversations" msgid="821834744538345661">"Разговоры"</string>
     <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Отклонить все беззвучные уведомления"</string>
     <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"В режиме \"Не беспокоить\" уведомления заблокированы"</string>
-    <!-- no translation found for modes_suppressing_shade_text (6037581130837903239) -->
-    <skip />
+    <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{Уведомлений нет}=1{Режим \"{mode}\" приостанавливает уведомления}=2{Режим \"{mode}\" и ещё один режим приостанавливают уведомления}one{Режим \"{mode}\" и ещё # режим приостанавливают уведомления}few{Режим \"{mode}\" и ещё # режима приостанавливают уведомления}many{Режим \"{mode}\" и ещё # режимов приостанавливают уведомления}other{Режим \"{mode}\" и ещё # режима приостанавливают уведомления}}"</string>
     <string name="media_projection_action_text" msgid="3634906766918186440">"Начать"</string>
     <string name="empty_shade_text" msgid="8935967157319717412">"Нет уведомлений."</string>
     <string name="no_unseen_notif_text" msgid="395512586119868682">"Новых уведомлений нет"</string>
@@ -673,6 +672,10 @@
     <string name="stream_notification_unavailable" msgid="4313854556205836435">"Недоступно в беззвучном режиме"</string>
     <string name="stream_alarm_unavailable" msgid="4059817189292197839">"Недоступно при включенном режиме \"Не беспокоить\"."</string>
     <string name="stream_media_unavailable" msgid="6823020894438959853">"Недоступно при включенном режиме \"Не беспокоить\"."</string>
+    <!-- no translation found for stream_unavailable_by_modes (3674139029490353683) -->
+    <skip />
+    <!-- no translation found for stream_unavailable_by_unknown (6908434629318171588) -->
+    <skip />
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Нажмите, чтобы включить звук."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Нажмите, чтобы включить вибрацию. Специальные возможности могут прекратить работу."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Нажмите, чтобы выключить звук. Специальные возможности могут прекратить работу."</string>
@@ -706,6 +709,7 @@
     <string name="show_demo_mode" msgid="3677956462273059726">"Перейти в демонстрационный режим"</string>
     <string name="status_bar_ethernet" msgid="5690979758988647484">"Ethernet"</string>
     <string name="status_bar_alarm" msgid="87160847643623352">"Будильник"</string>
+    <string name="active_mode_content_description" msgid="1627555562186515927">"<xliff:g id="MODENAME">%1$s</xliff:g>: включено"</string>
     <string name="wallet_title" msgid="5369767670735827105">"Кошелек"</string>
     <string name="wallet_empty_state_label" msgid="7776761245237530394">"Расплачивайтесь через телефон быстро и безопасно."</string>
     <string name="wallet_app_button_label" msgid="7123784239111190992">"Показать все"</string>
@@ -1405,26 +1409,26 @@
     <string name="launch_touchpad_tutorial_notification_content" msgid="7931085031240753226">"Узнайте о жестах на сенсорной панели."</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_title" msgid="1940023776496198762">"Навигация с помощью клавиатуры и сенсорной панели"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Узнайте о жестах на сенсорной панели, сочетаниях клавиш и многом другом."</string>
-    <string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Жест \"назад\""</string>
-    <string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Жест \"на главный экран\""</string>
+    <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"Назад"</string>
+    <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"На главную"</string>
     <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Жест \"Просмотр недавних приложений\""</string>
     <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Готово"</string>
     <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Назад"</string>
-    <string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"Чтобы вернуться назад, проведите по сенсорной панели тремя пальцами влево или вправо.\n\nВы также можете нажать клавишу действия + Esc."</string>
-    <string name="touchpad_back_gesture_success_title" msgid="7240576648330612171">"Отлично!"</string>
+    <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"Проведите тремя пальцами влево или вправо по сенсорной панели."</string>
+    <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"Отлично!"</string>
     <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"Вы выполнили жест для перехода назад."</string>
     <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"На главный экран"</string>
-    <string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"Чтобы перейти на главный экран, проведите снизу вверх тремя пальцами."</string>
-    <string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Неплохо!"</string>
-    <string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Вы выполнили жест для перехода на главный экран."</string>
+    <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"Проведите тремя пальцами вверх по сенсорной панели."</string>
+    <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"Отличная работа!"</string>
+    <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"Вы выполнили жест для перехода на главный экран."</string>
     <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"Просмотр недавних приложений"</string>
-    <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"Проведите вверх по сенсорной панели тремя пальцами и удерживайте."</string>
+    <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"Проведите вверх по сенсорной панели тремя пальцами и удерживайте."</string>
     <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Отлично!"</string>
     <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Вы выполнили жест для просмотра недавних приложений."</string>
-    <string name="tutorial_action_key_title" msgid="2659466586996495447">"Клавиша действия"</string>
-    <string name="tutorial_action_key_guidance" msgid="5718948664616999196">"Чтобы перейти к приложениям, нажмите клавишу действия на клавиатуре."</string>
-    <string name="tutorial_action_key_success_title" msgid="466467860120112933">"Готово!"</string>
-    <string name="tutorial_action_key_success_body" msgid="7201991081652850430">"Вы выполнили жест с клавишей действия.\n\nЧтобы посмотреть доступные сочетания, нажмите клавишу действия и \"/\"."</string>
+    <string name="tutorial_action_key_title" msgid="8172535792469008169">"Все приложения"</string>
+    <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Нажмите клавишу действия на клавиатуре."</string>
+    <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Блестяще!"</string>
+    <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Вы выполнили жест для просмотра всех приложений."</string>
     <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Подсветка клавиатуры"</string>
     <string name="keyboard_backlight_value" msgid="7336398765584393538">"Уровень %1$d из %2$d"</string>
     <string name="home_controls_dream_label" msgid="6567105701292324257">"Управление домом"</string>
@@ -1436,6 +1440,7 @@
     <string name="all_apps_edu_toast_content" msgid="8807496014667211562">"Чтобы открыть список всех своих приложений, нажмите клавишу действия."</string>
     <string name="redacted_notification_single_line_title" msgid="212019960919261670">"Скрыто"</string>
     <string name="redacted_notification_single_line_text" msgid="8684166405005242945">"Разблокируйте экран, чтобы посмотреть."</string>
+    <string name="contextual_education_dialog_title" msgid="4630392552837487324">"Контекстные подсказки"</string>
     <string name="back_edu_notification_title" msgid="5624780717751357278">"Используйте сенсорную панель, чтобы возвращаться назад"</string>
     <string name="back_edu_notification_content" msgid="2497557451540954068">"Для этого проведите тремя пальцами влево или вправо. Нажмите, чтобы посмотреть другие жесты."</string>
     <string name="home_edu_notification_title" msgid="6097902076909654045">"Используйте сенсорную панель, чтобы переходить на главный экран"</string>
diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml
index ff0c28d..6d2b0be 100644
--- a/packages/SystemUI/res/values-si/strings.xml
+++ b/packages/SystemUI/res/values-si/strings.xml
@@ -440,7 +440,7 @@
     <string name="zen_mode_on" msgid="9085304934016242591">"ක්‍රියාත්මකයි"</string>
     <string name="zen_mode_on_with_details" msgid="7416143430557895497">"ක්‍රියාත්මකයි • <xliff:g id="TRIGGER_DESCRIPTION">%1$s</xliff:g>"</string>
     <string name="zen_mode_off" msgid="1736604456618147306">"ක්‍රියාවිරහිතයි"</string>
-    <string name="zen_mode_set_up" msgid="7457957033034460064">"පිහිටුවන්න"</string>
+    <string name="zen_mode_set_up" msgid="8231201163894922821">"සකසා නැත"</string>
     <string name="zen_mode_no_manual_invocation" msgid="1769975741344633672">"සැකසීම් තුළ කළමනාකරණය කරන්න"</string>
     <string name="zen_mode_active_modes" msgid="1625850411578488856">"{count,plural, =0{සක්‍රිය ප්‍රකාර නොමැත}=1{{mode} සක්‍රියයි}one{ප්‍රකාර #ක් සක්‍රියයි}other{ප්‍රකාර #ක් සක්‍රියයි}}"</string>
     <string name="zen_priority_introduction" msgid="3159291973383796646">"එලාම සිහිකැඳවීම්, සිදුවීම්, සහ ඔබ සඳහන් කළ අමතන්නන් හැර, ශබ්ද සහ කම්පනවලින් ඔබට බාධා නොවනු ඇත. සංගීතය, වීඩියෝ, සහ ක්‍රීඩා ඇතුළු ඔබ වාදනය කිරීමට තෝරන ලද සියලු දේ ඔබට තවම ඇසෙනු ඇත."</string>
@@ -573,8 +573,7 @@
     <string name="notification_section_header_conversations" msgid="821834744538345661">"සංවාද"</string>
     <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"සියලු නිහඬ දැනුම්දීම් හිස් කරන්න"</string>
     <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"බාධා නොකරන්න මගින් විරාම කරන ලද දැනුම්දීම්"</string>
-    <!-- no translation found for modes_suppressing_shade_text (6037581130837903239) -->
-    <skip />
+    <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{දැනුම්දීම් නැත}=1{{mode} මගින් දැනුම්දීම් විරාම කරන ලදි}=2{{mode} සහ තව එක ප්‍රකාරයක් මගින් දැනුම්දීම් විරාම කරන ලදි}one{{mode} සහ තව ප්‍රකාර #ක් මගින් දැනුම්දීම් විරාම කරන ලදි}other{{mode} සහ තව ප්‍රකාර #ක් මගින් දැනුම්දීම් විරාම කරන ලදි}}"</string>
     <string name="media_projection_action_text" msgid="3634906766918186440">"දැන් අරඹන්න"</string>
     <string name="empty_shade_text" msgid="8935967157319717412">"දැනුම්දීම් නැත"</string>
     <string name="no_unseen_notif_text" msgid="395512586119868682">"නව දැනුම්දීම් නැත"</string>
@@ -673,6 +672,10 @@
     <string name="stream_notification_unavailable" msgid="4313854556205836435">"නාදය නිහඬ කර ඇති නිසා නොලැබේ"</string>
     <string name="stream_alarm_unavailable" msgid="4059817189292197839">"බාධා නොකරන්න ක්‍රියාත්මකව ඇති බැවින් ලද නොහැක"</string>
     <string name="stream_media_unavailable" msgid="6823020894438959853">"බාධා නොකරන්න ක්‍රියාත්මකව ඇති බැවින් ලද නොහැක"</string>
+    <!-- no translation found for stream_unavailable_by_modes (3674139029490353683) -->
+    <skip />
+    <!-- no translation found for stream_unavailable_by_unknown (6908434629318171588) -->
+    <skip />
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. නිහඬ කිරීම ඉවත් කිරීමට තට්ටු කරන්න."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. කම්පනය කිරීමට තට්ටු කරන්න. ප්‍රවේශ්‍යතා සේවා නිහඬ කළ හැකිය."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. නිහඬ කිරීමට තට්ටු කරන්න. ප්‍රවේශ්‍යතා සේවා නිහඬ කළ හැකිය."</string>
@@ -706,6 +709,7 @@
     <string name="show_demo_mode" msgid="3677956462273059726">"ආදර්ශන ප්‍රකාරය පෙන්වන්න"</string>
     <string name="status_bar_ethernet" msgid="5690979758988647484">"Ethernet"</string>
     <string name="status_bar_alarm" msgid="87160847643623352">"එලාමය"</string>
+    <string name="active_mode_content_description" msgid="1627555562186515927">"<xliff:g id="MODENAME">%1$s</xliff:g> ක්‍රියාත්මකයි"</string>
     <string name="wallet_title" msgid="5369767670735827105">"Wallet"</string>
     <string name="wallet_empty_state_label" msgid="7776761245237530394">"ඔබගේ දුරකථනය සමඟ වඩා වේගවත්, වඩා සුරක්ෂිත මිලදී ගැනීම් සිදු කිරීමට සූදානම් වන්න"</string>
     <string name="wallet_app_button_label" msgid="7123784239111190992">"සියල්ල පෙන්වන්න"</string>
@@ -1405,26 +1409,26 @@
     <string name="launch_touchpad_tutorial_notification_content" msgid="7931085031240753226">"ස්පර්ශක පුවරු අභිනයන් ඉගෙන ගන්න"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_title" msgid="1940023776496198762">"ඔබේ යතුරු පුවරුව සහ ස්පර්ශ පෑඩ් භාවිතයෙන් සංචාලනය කරන්න"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"ස්පර්ශ පෑඩ් අභිනයන්, යතුරුපුවරු කෙටිමං සහ තවත් දේ ඉගෙන ගන්න"</string>
-    <string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"ආපසු අභිනය"</string>
-    <string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"නිවෙස් අභිනය"</string>
+    <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"ආපසු යන්න"</string>
+    <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"මුල් පිටුවට යන්න"</string>
     <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"මෑත යෙදුම් බලන්න"</string>
     <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"නිමයි"</string>
     <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"ආපස්සට යන්න"</string>
-    <string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"ආපසු යාමට, ස්පර්ශ පුවරුවවේ ඕනෑම තැනක ඇඟිලි තුනක් භාවිතයෙන් වමට හෝ දකුණට ස්වයිප් කරන්න.\n\nඔබට මේ සඳහා යතුරු පුවරු කෙටිමං ක්‍රියාව + ESC ද භාවිත කළ හැක."</string>
-    <string name="touchpad_back_gesture_success_title" msgid="7240576648330612171">"අනර්ඝ වැඩක්!"</string>
+    <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"ඔබේ ස්පර්ශ පුවරුව මත ඇඟිලි තුනක් භාවිතයෙන් වමට හෝ දකුණට ස්වයිප් කරන්න"</string>
+    <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"කදිමයි!"</string>
     <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"ඔබ ආපසු යාමේ ඉංගිතය සම්පූර්ණ කරන ලදි."</string>
     <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"මුල් පිටුවට යන්න"</string>
-    <string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"ඕනෑම වේලාවක ඔබේ මුල් තිරයට යාමට, ඔබේ තිරයේ පහළ සිට ඇඟිලි තුනකින් ඉහළට ස්වයිප් කරන්න."</string>
-    <string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"කදිමයි!"</string>
-    <string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"ඔබ මුල් පිටුවට යාමේ ඉංගිතය සම්පූර්ණ කළා."</string>
+    <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"ඔබේ ස්පර්ශ පුවරුවේ ඇඟිලි තුනකින් ඉහළට ස්වයිප් කරන්න"</string>
+    <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"අනර්ඝ වැඩක්!"</string>
+    <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"ඔබ මුල් පිටුවට යාමේ ඉංගිතය සම්පූර්ණ කරන ලදි"</string>
     <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"මෑත යෙදුම් බලන්න"</string>
-    <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"ඉහළට ස්වයිප් කර ඔබේ ස්පර්ශ පුවරුව මත ඇඟිලි තුනක් භාවිතා කර සිටින්න."</string>
+    <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"ඉහළට ස්වයිප් කර ඔබේ ස්පර්ශ පුවරුව මත ඇඟිලි තුනක් භාවිත කර රඳවාගෙන සිටින්න"</string>
     <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"අනර්ඝ වැඩක්!"</string>
     <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"ඔබ මෑත යෙදුම් ඉංගිත බැලීම සම්පූර්ණ කර ඇත."</string>
-    <string name="tutorial_action_key_title" msgid="2659466586996495447">"ක්‍රියා යතුර"</string>
-    <string name="tutorial_action_key_guidance" msgid="5718948664616999196">"ඔබේ යෙදුම් වෙත ප්‍රවේශ වීමට, ඔබේ යතුරු පුවරුවෙහි ක්‍රියා යතුර ඔබන්න."</string>
-    <string name="tutorial_action_key_success_title" msgid="466467860120112933">"සුබ පැතුම්!"</string>
-    <string name="tutorial_action_key_success_body" msgid="7201991081652850430">"ඔබ ක්‍රියා යතුරු අභිනය සම්පූර්ණ කළා.\n\nක්‍රියාව + / ඔබට ලබා ගත හැකි සියලු කෙටිමං පෙන්වයි."</string>
+    <string name="tutorial_action_key_title" msgid="8172535792469008169">"සියලු යෙදුම් බලන්න"</string>
+    <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"ඔබේ යතුරු පුවරුවේ ක්‍රියාකාරී යතුර ඔබන්න"</string>
+    <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"හොඳින් කළා!"</string>
+    <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"ඔබ සියලු යෙදුම් ඉංගිත බැලීම සම්පූර්ණ කර ඇත"</string>
     <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"යතුරු පුවරු පසු ආලෝකය"</string>
     <string name="keyboard_backlight_value" msgid="7336398765584393538">"%2$dන් %1$d වැනි මට්ටම"</string>
     <string name="home_controls_dream_label" msgid="6567105701292324257">"නිවෙස් පාලන"</string>
@@ -1436,6 +1440,7 @@
     <string name="all_apps_edu_toast_content" msgid="8807496014667211562">"ඔබේ සියලුම යෙදුම් බැලීමට, ඔබේ යතුරුපුවරුවේ ක්‍රියාකාරී යතුර ඔබන්න"</string>
     <string name="redacted_notification_single_line_title" msgid="212019960919261670">"නැවත සකස් කරන ලද"</string>
     <string name="redacted_notification_single_line_text" msgid="8684166405005242945">"බැලීමට අගුළු හරින්න"</string>
+    <string name="contextual_education_dialog_title" msgid="4630392552837487324">"සන්දර්භීය අධ්‍යාපනය"</string>
     <string name="back_edu_notification_title" msgid="5624780717751357278">"ආපසු යාමට ඔබේ ස්පර්ශ පුවරුව භාවිත කරන්න"</string>
     <string name="back_edu_notification_content" msgid="2497557451540954068">"ඇඟිලි තුනක් භාවිතයෙන් වමට හෝ දකුණට ස්වයිප් කරන්න. තව ඉංගිත දැන ගැනීමට තට්ටු කරන්න."</string>
     <string name="home_edu_notification_title" msgid="6097902076909654045">"මුල් පිටුවට යාමට ඔබේ ස්පර්ශ පුවරුව භාවිත කරන්න"</string>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index 16af11a..223070c 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -440,7 +440,7 @@
     <string name="zen_mode_on" msgid="9085304934016242591">"Zapnuté"</string>
     <string name="zen_mode_on_with_details" msgid="7416143430557895497">"Zapnuté • <xliff:g id="TRIGGER_DESCRIPTION">%1$s</xliff:g>"</string>
     <string name="zen_mode_off" msgid="1736604456618147306">"Vypnuté"</string>
-    <string name="zen_mode_set_up" msgid="7457957033034460064">"Nastaviť"</string>
+    <string name="zen_mode_set_up" msgid="8231201163894922821">"Nenastavené"</string>
     <string name="zen_mode_no_manual_invocation" msgid="1769975741344633672">"Správa v nastaveniach"</string>
     <string name="zen_mode_active_modes" msgid="1625850411578488856">"{count,plural, =0{Žiadne aktívne režimy}=1{{mode} je aktívny}few{# režimy sú aktívne}many{# modes are active}other{# režimov je aktívnych}}"</string>
     <string name="zen_priority_introduction" msgid="3159291973383796646">"Nebudú vás vyrušovať zvuky ani vibrácie, iba budíky, pripomenutia, udalosti a volajúci, ktorých určíte. Budete naďalej počuť všetko, čo sa rozhodnete prehrať, ako napríklad hudbu, videá a hry."</string>
@@ -573,8 +573,7 @@
     <string name="notification_section_header_conversations" msgid="821834744538345661">"Konverzácie"</string>
     <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Vymazať všetky tiché upozornenia"</string>
     <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Upozornenia sú pozastavené režimom bez vyrušení"</string>
-    <!-- no translation found for modes_suppressing_shade_text (6037581130837903239) -->
-    <skip />
+    <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{Žiadne upozornenia}=1{Upozornenia boli pozastavené režimom {mode}}=2{Upozornenia boli pozastavené režimom {mode} a jedným ďalším}few{Upozornenia boli pozastavené režimom {mode} a # ďalšími}many{Notifications paused by {mode} and # other modes}other{Upozornenia boli pozastavené režimom {mode} a # ďalšími}}"</string>
     <string name="media_projection_action_text" msgid="3634906766918186440">"Spustiť"</string>
     <string name="empty_shade_text" msgid="8935967157319717412">"Žiadne upozornenia"</string>
     <string name="no_unseen_notif_text" msgid="395512586119868682">"Žiadne nové upozornenia"</string>
@@ -673,6 +672,10 @@
     <string name="stream_notification_unavailable" msgid="4313854556205836435">"Nedostupné, pretože je vypnuté zvonenie"</string>
     <string name="stream_alarm_unavailable" msgid="4059817189292197839">"Nedostupné, pretože je zapnutý režim bez vyrušení"</string>
     <string name="stream_media_unavailable" msgid="6823020894438959853">"Nedostupné, zapnutý režim bez vyrušení"</string>
+    <!-- no translation found for stream_unavailable_by_modes (3674139029490353683) -->
+    <skip />
+    <!-- no translation found for stream_unavailable_by_unknown (6908434629318171588) -->
+    <skip />
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Klepnutím zapnite zvuk."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Klepnutím aktivujte režim vibrovania. Služby dostupnosti je možné stlmiť."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Klepnutím vypnite zvuk. Služby dostupnosti je možné stlmiť."</string>
@@ -706,6 +709,7 @@
     <string name="show_demo_mode" msgid="3677956462273059726">"Zobraziť režim ukážky"</string>
     <string name="status_bar_ethernet" msgid="5690979758988647484">"Ethernet"</string>
     <string name="status_bar_alarm" msgid="87160847643623352">"Budík"</string>
+    <string name="active_mode_content_description" msgid="1627555562186515927">"Režim <xliff:g id="MODENAME">%1$s</xliff:g> je zapnutý"</string>
     <string name="wallet_title" msgid="5369767670735827105">"Peňaženka"</string>
     <string name="wallet_empty_state_label" msgid="7776761245237530394">"Nastavte si všetko potrebné na rýchlejšie a bezpečnejšie nákupy telefónom"</string>
     <string name="wallet_app_button_label" msgid="7123784239111190992">"Zobraziť všetko"</string>
@@ -1405,26 +1409,26 @@
     <string name="launch_touchpad_tutorial_notification_content" msgid="7931085031240753226">"Naučte sa gestá touchpadu"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_title" msgid="1940023776496198762">"Prechádzajte pomocou klávesnice a touchpadu"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Naučte sa gestá touchpadu, klávesové skratky a ďalšie funkcie"</string>
-    <string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Gesto prechodu späť"</string>
-    <string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Gesto prechodu domov"</string>
+    <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"Prejsť späť"</string>
+    <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Prejsť na plochu"</string>
     <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Zobrazenie nedávnych aplikácií"</string>
     <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Hotovo"</string>
     <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Prejsť späť"</string>
-    <string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"Ak chcete prejsť späť, potiahnite kdekoľvek na touchpade troma prstami doľava alebo doprava.\n\nMôžete použiť aj klávesovú skratku, teda akčný kláves + ESC."</string>
-    <string name="touchpad_back_gesture_success_title" msgid="7240576648330612171">"Skvelé!"</string>
+    <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"Potiahnite troma prstami na touchpade doľava alebo doprava"</string>
+    <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"Výborne!"</string>
     <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"Dokončili ste gesto na prechod späť."</string>
     <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"Prechod na plochu"</string>
-    <string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"Na plochu môžete kedykoľvek prejsť potiahnutím troma prstami zdola obrazovky."</string>
-    <string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Výborne!"</string>
-    <string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Dokončili ste gesto na prechod na plochu."</string>
+    <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"Potiahnite troma prstami na touchpade nahor"</string>
+    <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"Skvelé!"</string>
+    <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"Dokončili ste gesto na prechod na plochu"</string>
     <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"Zobrazenie nedávnych aplikácií"</string>
-    <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"Potiahnite troma prstami na touchpade nahor a pridržte ich."</string>
+    <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"Potiahnite troma prstami na touchpade nahor a pridržte"</string>
     <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Skvelé!"</string>
     <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Dokončili ste gesto na zobrazenie nedávnych aplikácií."</string>
-    <string name="tutorial_action_key_title" msgid="2659466586996495447">"Akčný kláves"</string>
-    <string name="tutorial_action_key_guidance" msgid="5718948664616999196">"Ak chcete získať prístup k aplikáciám, stlačte na klávesnici akčný kláves."</string>
-    <string name="tutorial_action_key_success_title" msgid="466467860120112933">"Blahoželáme!"</string>
-    <string name="tutorial_action_key_success_body" msgid="7201991081652850430">"Dokončili ste gesto akčného klávesa.\n\nStlačením kombinácie akčný kláves + / zobrazíte všetky skratky, ktoré máte k dispozícii"</string>
+    <string name="tutorial_action_key_title" msgid="8172535792469008169">"Zobrazenie všetkých aplikácií"</string>
+    <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Stlačte na klávesnici akčný kláves"</string>
+    <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Výborne!"</string>
+    <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Dokončili ste gesto na zobrazenie všetkých aplikácií"</string>
     <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Podsvietenie klávesnice"</string>
     <string name="keyboard_backlight_value" msgid="7336398765584393538">"%1$d. úroveň z %2$d"</string>
     <string name="home_controls_dream_label" msgid="6567105701292324257">"Ovládanie domácnosti"</string>
@@ -1436,6 +1440,7 @@
     <string name="all_apps_edu_toast_content" msgid="8807496014667211562">"Ak si chcete zobraziť všetky aplikácie, stlačte na klávesnici akčný kláves"</string>
     <string name="redacted_notification_single_line_title" msgid="212019960919261670">"Zamaskované"</string>
     <string name="redacted_notification_single_line_text" msgid="8684166405005242945">"Zobrazíte odomknutím"</string>
+    <string name="contextual_education_dialog_title" msgid="4630392552837487324">"Kontextová náuka"</string>
     <string name="back_edu_notification_title" msgid="5624780717751357278">"Prechádzajte späť pomocou touchpadu"</string>
     <string name="back_edu_notification_content" msgid="2497557451540954068">"Potiahnite troma prstami doľava alebo doprava. Viac o gestách sa dozviete klepnutím."</string>
     <string name="home_edu_notification_title" msgid="6097902076909654045">"Vráťte sa na plochu pomocou touchpadu"</string>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index e664810..d44e70c 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -440,7 +440,7 @@
     <string name="zen_mode_on" msgid="9085304934016242591">"Vklopljeno"</string>
     <string name="zen_mode_on_with_details" msgid="7416143430557895497">"Vklopljeno • <xliff:g id="TRIGGER_DESCRIPTION">%1$s</xliff:g>"</string>
     <string name="zen_mode_off" msgid="1736604456618147306">"Izklopljeno"</string>
-    <string name="zen_mode_set_up" msgid="7457957033034460064">"Nastavitev"</string>
+    <string name="zen_mode_set_up" msgid="8231201163894922821">"Ni nastavljeno"</string>
     <string name="zen_mode_no_manual_invocation" msgid="1769975741344633672">"Upravljanje v nastavitvah"</string>
     <string name="zen_mode_active_modes" msgid="1625850411578488856">"{count,plural, =0{Ni aktivnih načinov}=1{Način {mode} je aktiven}one{# način je aktiven}two{# načina sta aktivna}few{# načini so aktivni}other{# načinov je aktivnih}}"</string>
     <string name="zen_priority_introduction" msgid="3159291973383796646">"Ne bodo vas motili zvoki ali vibriranje, razen v primeru alarmov, opomnikov, dogodkov in klicateljev, ki jih določite. Še vedno pa boste slišali vse, kar se boste odločili predvajati, vključno z glasbo, videoposnetki in igrami."</string>
@@ -573,8 +573,7 @@
     <string name="notification_section_header_conversations" msgid="821834744538345661">"Pogovori"</string>
     <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Brisanje vseh tihih obvestil"</string>
     <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Prikazovanje obvestil je začasno zaustavljeno z načinom »ne moti«"</string>
-    <!-- no translation found for modes_suppressing_shade_text (6037581130837903239) -->
-    <skip />
+    <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{Ni obvestil}=1{Prikazovanje obvestil je začasno zaustavljeno z načinom {mode}}=2{Prikazovanje obvestil je začasno zaustavljeno z načinom {mode} in še enim drugim načinom}one{Prikazovanje obvestil je začasno zaustavljeno z načinom {mode} in še # drugim načinom}two{Prikazovanje obvestil je začasno zaustavljeno z načinom {mode} in še # drugima načinoma}few{Prikazovanje obvestil je začasno zaustavljeno z načinom {mode} in še # drugimi načini}other{Prikazovanje obvestil je začasno zaustavljeno z načinom {mode} in še # drugimi načini}}"</string>
     <string name="media_projection_action_text" msgid="3634906766918186440">"Začni zdaj"</string>
     <string name="empty_shade_text" msgid="8935967157319717412">"Ni obvestil"</string>
     <string name="no_unseen_notif_text" msgid="395512586119868682">"Ni novih obvestil"</string>
@@ -673,6 +672,10 @@
     <string name="stream_notification_unavailable" msgid="4313854556205836435">"Ni na voljo, ker je zvonjenje izklopljeno"</string>
     <string name="stream_alarm_unavailable" msgid="4059817189292197839">"Ni na voljo, ker je vklopljen način »Ne moti«"</string>
     <string name="stream_media_unavailable" msgid="6823020894438959853">"Ni na voljo, ker je vklopljen način »Ne moti«"</string>
+    <!-- no translation found for stream_unavailable_by_modes (3674139029490353683) -->
+    <skip />
+    <!-- no translation found for stream_unavailable_by_unknown (6908434629318171588) -->
+    <skip />
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Dotaknite se, če želite vklopiti zvok."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Dotaknite se, če želite nastaviti vibriranje. V storitvah za dostopnost bo morda izklopljen zvok."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Dotaknite se, če želite izklopiti zvok. V storitvah za dostopnost bo morda izklopljen zvok."</string>
@@ -706,6 +709,7 @@
     <string name="show_demo_mode" msgid="3677956462273059726">"Prikaz predstavitvenega načina"</string>
     <string name="status_bar_ethernet" msgid="5690979758988647484">"Ethernet"</string>
     <string name="status_bar_alarm" msgid="87160847643623352">"Alarm"</string>
+    <string name="active_mode_content_description" msgid="1627555562186515927">"<xliff:g id="MODENAME">%1$s</xliff:g>: Vklopljeno"</string>
     <string name="wallet_title" msgid="5369767670735827105">"Denarnica"</string>
     <string name="wallet_empty_state_label" msgid="7776761245237530394">"Nastavite možnost hitrejšega in varnejšega plačevanja s telefonom."</string>
     <string name="wallet_app_button_label" msgid="7123784239111190992">"Prikaži vse"</string>
@@ -1405,26 +1409,26 @@
     <string name="launch_touchpad_tutorial_notification_content" msgid="7931085031240753226">"Učenje potez na sledilni ploščici"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_title" msgid="1940023776496198762">"Krmarjenje s tipkovnico in sledilno ploščico"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Učenje potez na sledilni ploščici, bližnjičnih tipk in drugega"</string>
-    <string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Poteza za pomik nazaj"</string>
-    <string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Poteza za začetni zaslon"</string>
+    <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"Nazaj"</string>
+    <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Pojdi na začetni zaslon"</string>
     <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Ogled nedavnih aplikacij"</string>
     <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Končano"</string>
     <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Nazaj"</string>
-    <string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"Za pomik nazaj povlecite levo ali desno s tremi prsti kjer koli na sledilni ploščici.\n\nUporabite lahko tudi bližnjični tipki Action + ESC."</string>
-    <string name="touchpad_back_gesture_success_title" msgid="7240576648330612171">"Odlično!"</string>
+    <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"Na sledilni ploščici s tremi prsti povlecite levo ali desno"</string>
+    <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"Odlično!"</string>
     <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"Izvedli ste potezo za pomik nazaj."</string>
     <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"Pomik na začetni zaslon"</string>
-    <string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"Za pomik na začetni zaslon lahko kadar koli s tremi prsti povlečete navzgor z dna zaslona."</string>
-    <string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Odlično!"</string>
-    <string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Izvedli ste potezo za pomik na začetni zaslon."</string>
+    <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"Na sledilni ploščici s tremi prsti povlecite navzgor"</string>
+    <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"Odlično!"</string>
+    <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"Izvedli ste potezo za pomik na začetni zaslon"</string>
     <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"Ogled nedavnih aplikacij"</string>
-    <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"Na sledilni ploščici s tremi prsti povlecite navzgor in pridržite."</string>
+    <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"Na sledilni ploščici s tremi prsti povlecite navzgor in pridržite"</string>
     <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Odlično!"</string>
     <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Izvedli ste potezo za ogled nedavnih aplikacij."</string>
-    <string name="tutorial_action_key_title" msgid="2659466586996495447">"Tipka za dejanja"</string>
-    <string name="tutorial_action_key_guidance" msgid="5718948664616999196">"Za dostop do aplikacij pritisnite tipko za dejanja na tipkovnici."</string>
-    <string name="tutorial_action_key_success_title" msgid="466467860120112933">"Čestitamo!"</string>
-    <string name="tutorial_action_key_success_body" msgid="7201991081652850430">"Izvedli ste potezo za tipko za dejanja.\n\nČe hkrati pritisnete tipko za dejanja in poševnico naprej »/«, bodo prikazane vse razpoložljive bližnjice."</string>
+    <string name="tutorial_action_key_title" msgid="8172535792469008169">"Ogled vseh aplikacij"</string>
+    <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Pritisnite tipko za dejanja na tipkovnici"</string>
+    <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Odlično!"</string>
+    <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Izvedli ste potezo za ogled vseh aplikacij"</string>
     <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Osvetlitev tipkovnice"</string>
     <string name="keyboard_backlight_value" msgid="7336398765584393538">"Stopnja %1$d od %2$d"</string>
     <string name="home_controls_dream_label" msgid="6567105701292324257">"Kontrolniki za dom"</string>
@@ -1436,6 +1440,7 @@
     <string name="all_apps_edu_toast_content" msgid="8807496014667211562">"Za ogled vseh aplikacij pritisnite tipko za dejanja na tipkovnici"</string>
     <string name="redacted_notification_single_line_title" msgid="212019960919261670">"Zakrito"</string>
     <string name="redacted_notification_single_line_text" msgid="8684166405005242945">"Odklenite za ogled"</string>
+    <string name="contextual_education_dialog_title" msgid="4630392552837487324">"Kontekstualno izobraževanje"</string>
     <string name="back_edu_notification_title" msgid="5624780717751357278">"Uporaba sledilne ploščice za pomik nazaj"</string>
     <string name="back_edu_notification_content" msgid="2497557451540954068">"S tremi prsti povlecite levo ali desno. Dotaknite se, če želite spoznati več potez."</string>
     <string name="home_edu_notification_title" msgid="6097902076909654045">"Uporaba sledilne ploščice za pomik na začetni zaslon"</string>
diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml
index e70629f..8787a60 100644
--- a/packages/SystemUI/res/values-sq/strings.xml
+++ b/packages/SystemUI/res/values-sq/strings.xml
@@ -440,7 +440,8 @@
     <string name="zen_mode_on" msgid="9085304934016242591">"Aktiv"</string>
     <string name="zen_mode_on_with_details" msgid="7416143430557895497">"Aktiv • <xliff:g id="TRIGGER_DESCRIPTION">%1$s</xliff:g>"</string>
     <string name="zen_mode_off" msgid="1736604456618147306">"Joaktiv"</string>
-    <string name="zen_mode_set_up" msgid="7457957033034460064">"Konfiguro"</string>
+    <!-- no translation found for zen_mode_set_up (8231201163894922821) -->
+    <skip />
     <string name="zen_mode_no_manual_invocation" msgid="1769975741344633672">"Menaxho te cilësimet"</string>
     <string name="zen_mode_active_modes" msgid="1625850411578488856">"{count,plural, =0{Nuk ka modalitete aktive}=1{\"{mode}\" është aktiv}other{# modalitete janë aktive}}"</string>
     <string name="zen_priority_introduction" msgid="3159291973383796646">"Nuk do të shqetësohesh nga tingujt dhe dridhjet, përveç alarmeve, alarmeve rikujtuese, ngjarjeve dhe telefonuesve që specifikon. Do të vazhdosh të dëgjosh çdo gjë që zgjedh të luash duke përfshirë muzikën, videot dhe lojërat."</string>
@@ -573,8 +574,7 @@
     <string name="notification_section_header_conversations" msgid="821834744538345661">"Bisedat"</string>
     <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Pastro të gjitha njoftimet në heshtje"</string>
     <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Njoftimet janë vendosur në pauzë nga modaliteti \"Mos shqetëso\""</string>
-    <!-- no translation found for modes_suppressing_shade_text (6037581130837903239) -->
-    <skip />
+    <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{Asnjë njoftim}=1{Njoftimet u vendosën në pauzë nga {mode}}=2{Njoftimet u vendosën në pauzë nga {mode} dhe një modalitet tjetër}other{Njoftimet u vendosën në pauzë nga {mode} dhe # modalitete të tjera}}"</string>
     <string name="media_projection_action_text" msgid="3634906766918186440">"Fillo tani"</string>
     <string name="empty_shade_text" msgid="8935967157319717412">"Asnjë njoftim"</string>
     <string name="no_unseen_notif_text" msgid="395512586119868682">"Nuk ka njoftime të reja"</string>
@@ -673,6 +673,10 @@
     <string name="stream_notification_unavailable" msgid="4313854556205836435">"Nuk ofrohet; ziles i është hequr zëri"</string>
     <string name="stream_alarm_unavailable" msgid="4059817189292197839">"Nuk ofrohet; \"Mos shqetëso\" është aktiv"</string>
     <string name="stream_media_unavailable" msgid="6823020894438959853">"Nuk ofrohet; \"Mos shqetëso\" është aktiv"</string>
+    <!-- no translation found for stream_unavailable_by_modes (3674139029490353683) -->
+    <skip />
+    <!-- no translation found for stream_unavailable_by_unknown (6908434629318171588) -->
+    <skip />
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Trokit për të aktivizuar."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Trokit për ta caktuar te dridhja. Shërbimet e qasshmërisë mund të çaktivizohen."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Trokit për të çaktivizuar. Shërbimet e qasshmërisë mund të çaktivizohen."</string>
@@ -706,6 +710,7 @@
     <string name="show_demo_mode" msgid="3677956462273059726">"Shfaq modalitetin e demonstrimit"</string>
     <string name="status_bar_ethernet" msgid="5690979758988647484">"Eternet"</string>
     <string name="status_bar_alarm" msgid="87160847643623352">"Alarmi"</string>
+    <string name="active_mode_content_description" msgid="1627555562186515927">"\"<xliff:g id="MODENAME">%1$s</xliff:g>\" është aktiv"</string>
     <string name="wallet_title" msgid="5369767670735827105">"Portofoli"</string>
     <string name="wallet_empty_state_label" msgid="7776761245237530394">"Konfiguro për të kryer pagesa më të shpejta dhe më të sigurta përmes telefonit"</string>
     <string name="wallet_app_button_label" msgid="7123784239111190992">"Shfaqi të gjitha"</string>
@@ -1405,26 +1410,38 @@
     <string name="launch_touchpad_tutorial_notification_content" msgid="7931085031240753226">"Mëso gjestet e bllokut me prekje"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_title" msgid="1940023776496198762">"Navigo duke përdorur tastierën dhe bllokun me prekje"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Mëso gjestet e bllokut me prekje, shkurtoret e tastierës etj."</string>
-    <string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Gjesti i kthimit prapa"</string>
-    <string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Gjesti për të shkuar tek ekrani bazë"</string>
+    <!-- no translation found for touchpad_tutorial_back_gesture_button (3104716365403620315) -->
+    <skip />
+    <!-- no translation found for touchpad_tutorial_home_gesture_button (8023973153559885624) -->
+    <skip />
     <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Shiko aplikacionet e fundit"</string>
     <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"U krye"</string>
     <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Kthehu prapa"</string>
-    <string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"Për t\'u kthyer, rrëshqit shpejt majtas ose djathtas duke përdorur tri gishta kudo në bllokun me prekje.\n\nPër ta bërë këtë, mund të përdorësh gjithashtu shkurtoren e tastierës \"Action + ESC\"."</string>
-    <string name="touchpad_back_gesture_success_title" msgid="7240576648330612171">"Punë e shkëlqyer!"</string>
+    <!-- no translation found for touchpad_back_gesture_guidance (5352221087725906542) -->
+    <skip />
+    <!-- no translation found for touchpad_back_gesture_success_title (7370719098633023496) -->
+    <skip />
     <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"E ke përfunduar gjestin e kthimit prapa."</string>
     <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"Shko tek ekrani bazë"</string>
-    <string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"Për të shkuar tek ekrani bazë në çdo kohë, rrëshqit shpejt lart me tre gishta nga fundi i ekranit."</string>
-    <string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Bukur!"</string>
-    <string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"E ke përfunduar gjestin e kalimit tek ekrani bazë."</string>
+    <!-- no translation found for touchpad_home_gesture_guidance (4178219118381915899) -->
+    <skip />
+    <!-- no translation found for touchpad_home_gesture_success_title (3648264553645798470) -->
+    <skip />
+    <!-- no translation found for touchpad_home_gesture_success_body (2590690589194027059) -->
+    <skip />
     <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"Shiko aplikacionet e fundit"</string>
-    <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"Rrëshqit shpejt lart dhe mbaj shtypur me tre gishta në bllokun me prekje."</string>
+    <!-- no translation found for touchpad_recent_apps_gesture_guidance (6304446013842271822) -->
+    <skip />
     <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Punë e shkëlqyer!"</string>
     <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Përfundove gjestin për shikimin e aplikacioneve të fundit."</string>
-    <string name="tutorial_action_key_title" msgid="2659466586996495447">"Tasti i veprimit"</string>
-    <string name="tutorial_action_key_guidance" msgid="5718948664616999196">"Për t\'u qasur në aplikacionet e tua, shtyp tastin e veprimit në tastierë."</string>
-    <string name="tutorial_action_key_success_title" msgid="466467860120112933">"Urime!"</string>
-    <string name="tutorial_action_key_success_body" msgid="7201991081652850430">"Ke përfunduar gjestin e tastit të veprimit.\n\nVeprimi + / shfaq të gjitha shkurtoret që janë të disponueshme për ty."</string>
+    <!-- no translation found for tutorial_action_key_title (8172535792469008169) -->
+    <skip />
+    <!-- no translation found for tutorial_action_key_guidance (5040613427202799294) -->
+    <skip />
+    <!-- no translation found for tutorial_action_key_success_title (2371827347071979571) -->
+    <skip />
+    <!-- no translation found for tutorial_action_key_success_body (1688986269491357832) -->
+    <skip />
     <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Drita e sfondit e tastierës"</string>
     <string name="keyboard_backlight_value" msgid="7336398765584393538">"Niveli: %1$d nga %2$d"</string>
     <string name="home_controls_dream_label" msgid="6567105701292324257">"Kontrollet e shtëpisë"</string>
@@ -1436,6 +1453,7 @@
     <string name="all_apps_edu_toast_content" msgid="8807496014667211562">"Për të shikuar të gjitha aplikacionet, shtyp tastin e veprimit në tastierë"</string>
     <string name="redacted_notification_single_line_title" msgid="212019960919261670">"Redaktuar"</string>
     <string name="redacted_notification_single_line_text" msgid="8684166405005242945">"Shkyçe për ta parë"</string>
+    <string name="contextual_education_dialog_title" msgid="4630392552837487324">"Edukimi kontekstual"</string>
     <string name="back_edu_notification_title" msgid="5624780717751357278">"Përdor bllokun me prekje për t\'u kthyer prapa"</string>
     <string name="back_edu_notification_content" msgid="2497557451540954068">"Rrëshqit shpejt majtas ose djathtas duke përdorur tre gishta. Trokit për të mësuar më shumë gjeste."</string>
     <string name="home_edu_notification_title" msgid="6097902076909654045">"Përdor bllokun me prekje për të shkuar tek ekrani bazë"</string>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index 164b4aa..599d71a 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -440,7 +440,7 @@
     <string name="zen_mode_on" msgid="9085304934016242591">"Укључено"</string>
     <string name="zen_mode_on_with_details" msgid="7416143430557895497">"Укљ. • <xliff:g id="TRIGGER_DESCRIPTION">%1$s</xliff:g>"</string>
     <string name="zen_mode_off" msgid="1736604456618147306">"Искључено"</string>
-    <string name="zen_mode_set_up" msgid="7457957033034460064">"Подеси"</string>
+    <string name="zen_mode_set_up" msgid="8231201163894922821">"Није подешено"</string>
     <string name="zen_mode_no_manual_invocation" msgid="1769975741344633672">"Управљајте у подешавањима"</string>
     <string name="zen_mode_active_modes" msgid="1625850411578488856">"{count,plural, =0{Нема активних режима}=1{Активан је {mode} режим}one{Активан је # режим}few{Активна су # режима}other{Активно је # режима}}"</string>
     <string name="zen_priority_introduction" msgid="3159291973383796646">"Неће вас узнемиравати звукови и вибрације осим за аларме, подсетнике, догађаје и позиваоце које наведете. И даље ћете чути све што одаберете да пустите, укључујући музику, видео снимке и игре."</string>
@@ -573,8 +573,7 @@
     <string name="notification_section_header_conversations" msgid="821834744538345661">"Конверзације"</string>
     <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Обришите сва нечујна обавештења"</string>
     <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Обавештења су паузирана режимом Не узнемиравај"</string>
-    <!-- no translation found for modes_suppressing_shade_text (6037581130837903239) -->
-    <skip />
+    <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{Нема обавештења}=1{Обавештења је паузирао {mode}}=2{Обавештења су паузирали {mode} и још један режим}one{Обавештења су паузирали {mode} и још # режим}few{Обавештења су паузирали {mode} и још # режима}other{Обавештења су паузирали {mode} и још # режима}}"</string>
     <string name="media_projection_action_text" msgid="3634906766918186440">"Започни"</string>
     <string name="empty_shade_text" msgid="8935967157319717412">"Нема обавештења"</string>
     <string name="no_unseen_notif_text" msgid="395512586119868682">"Нема нових обавештења"</string>
@@ -673,6 +672,10 @@
     <string name="stream_notification_unavailable" msgid="4313854556205836435">"Недоступно јер је звук искључен"</string>
     <string name="stream_alarm_unavailable" msgid="4059817189292197839">"Недоступно јер је укључен режим Не узнемиравај"</string>
     <string name="stream_media_unavailable" msgid="6823020894438959853">"Недоступно јер је укључен режим Не узнемиравај"</string>
+    <!-- no translation found for stream_unavailable_by_modes (3674139029490353683) -->
+    <skip />
+    <!-- no translation found for stream_unavailable_by_unknown (6908434629318171588) -->
+    <skip />
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Додирните да бисте укључили звук."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Додирните да бисте подесили на вибрацију. Звук услуга приступачности ће можда бити искључен."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Додирните да бисте искључили звук. Звук услуга приступачности ће можда бити искључен."</string>
@@ -706,6 +709,7 @@
     <string name="show_demo_mode" msgid="3677956462273059726">"Прикажи режим демонстрације"</string>
     <string name="status_bar_ethernet" msgid="5690979758988647484">"Етернет"</string>
     <string name="status_bar_alarm" msgid="87160847643623352">"Аларм"</string>
+    <string name="active_mode_content_description" msgid="1627555562186515927">"<xliff:g id="MODENAME">%1$s</xliff:g>: укључено"</string>
     <string name="wallet_title" msgid="5369767670735827105">"Новчаник"</string>
     <string name="wallet_empty_state_label" msgid="7776761245237530394">"Обавите конфигурисање да бисте могли брже и сигурније да купујете помоћу телефона"</string>
     <string name="wallet_app_button_label" msgid="7123784239111190992">"Прикажи све"</string>
@@ -1405,26 +1409,26 @@
     <string name="launch_touchpad_tutorial_notification_content" msgid="7931085031240753226">"Научите покрете за тачпед"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_title" msgid="1940023776496198762">"Крећите се помоћу тастатуре и тачпeда"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Научите покрете за тачпед, тастерске пречице и друго"</string>
-    <string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Покрет за враћање"</string>
-    <string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Покрет за почетну страницу"</string>
+    <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"Назад"</string>
+    <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Иди на почетни екран"</string>
     <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Прикажи недавно коришћене апликације"</string>
     <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Готово"</string>
     <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Назад"</string>
-    <string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"Да бисте се вратили, превуците улево са три прста било где на тачпеду.\n\nМожете да користите и тастерску пречицу Alt + ESC за ово."</string>
-    <string name="touchpad_back_gesture_success_title" msgid="7240576648330612171">"Одлично!"</string>
+    <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"Превуците улево или удесно са три прста на тачпеду"</string>
+    <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"Свака част!"</string>
     <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"Довршили сте покрет за повратак."</string>
     <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"Иди на почетни екран"</string>
-    <string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"Да бисте отишли на почетни екран у било ком тренутку, превуците нагоре од дна екрана помоћу три прста."</string>
-    <string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Свака част!"</string>
-    <string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Довршили сте покрет за повратак на почетну страницу."</string>
+    <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"Превуците нагоре са три прста на тачпеду"</string>
+    <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"Одлично!"</string>
+    <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"Довршили сте покрет за повратак на почетну страницу."</string>
     <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"Прикажи недавно коришћене апликације"</string>
-    <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"Превуците нагоре и задржите помоћу три прста на тачпеду."</string>
+    <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"Превуците нагоре и задржите са три прста на тачпеду"</string>
     <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Одлично!"</string>
     <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Довршили сте покрет за приказивање недавно коришћених апликација."</string>
-    <string name="tutorial_action_key_title" msgid="2659466586996495447">"Тастер радњи"</string>
-    <string name="tutorial_action_key_guidance" msgid="5718948664616999196">"Да бисте приступили апликацијама, притисните тастер радњи на тастатури."</string>
-    <string name="tutorial_action_key_success_title" msgid="466467860120112933">"Честитамо!"</string>
-    <string name="tutorial_action_key_success_body" msgid="7201991081652850430">"Довршили сте покрет помоћу тастера радњи.\n\nРадња + / приказује све пречице које су вам доступне."</string>
+    <string name="tutorial_action_key_title" msgid="8172535792469008169">"Прикажи све апликације"</string>
+    <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Притисните тастер радњи на тастатури"</string>
+    <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Одлично!"</string>
+    <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Довршили сте покрет за приказивање свих апликација."</string>
     <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Позадинско осветљење тастатуре"</string>
     <string name="keyboard_backlight_value" msgid="7336398765584393538">"%1$d. ниво од %2$d"</string>
     <string name="home_controls_dream_label" msgid="6567105701292324257">"Контроле за дом"</string>
@@ -1436,6 +1440,7 @@
     <string name="all_apps_edu_toast_content" msgid="8807496014667211562">"Да бисте погледали све апликације, притисните тастер радњи на тастатури"</string>
     <string name="redacted_notification_single_line_title" msgid="212019960919261670">"Редиговано"</string>
     <string name="redacted_notification_single_line_text" msgid="8684166405005242945">"Откључајте за приказ"</string>
+    <string name="contextual_education_dialog_title" msgid="4630392552837487324">"Контекстуално образовање"</string>
     <string name="back_edu_notification_title" msgid="5624780717751357278">"Користите тачпед да бисте се вратили"</string>
     <string name="back_edu_notification_content" msgid="2497557451540954068">"Превуците улево или удесно са три прста. Додирните да бисте видели више покрета."</string>
     <string name="home_edu_notification_title" msgid="6097902076909654045">"Користите тачпед да бисте отишли на почетни екран"</string>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index 3016e83..e1d13316 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -440,7 +440,7 @@
     <string name="zen_mode_on" msgid="9085304934016242591">"På"</string>
     <string name="zen_mode_on_with_details" msgid="7416143430557895497">"På • <xliff:g id="TRIGGER_DESCRIPTION">%1$s</xliff:g>"</string>
     <string name="zen_mode_off" msgid="1736604456618147306">"Av"</string>
-    <string name="zen_mode_set_up" msgid="7457957033034460064">"Ställ in"</string>
+    <string name="zen_mode_set_up" msgid="8231201163894922821">"Inte angivet"</string>
     <string name="zen_mode_no_manual_invocation" msgid="1769975741344633672">"Hantera i inställningarna"</string>
     <string name="zen_mode_active_modes" msgid="1625850411578488856">"{count,plural, =0{Inga aktiva lägen}=1{{mode} är aktivt}other{# lägen är aktiva}}"</string>
     <string name="zen_priority_introduction" msgid="3159291973383796646">"Du blir inte störd av ljud och vibrationer, förutom från alarm, påminnelser, händelser och specifika samtal. Ljudet är fortfarande på för sådant du väljer att spela upp, till exempel musik, videor och spel."</string>
@@ -573,8 +573,7 @@
     <string name="notification_section_header_conversations" msgid="821834744538345661">"Konversationer"</string>
     <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Rensa alla ljudlösa aviseringar"</string>
     <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Aviseringar har pausats via Stör ej"</string>
-    <!-- no translation found for modes_suppressing_shade_text (6037581130837903239) -->
-    <skip />
+    <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{Inga aviseringar}=1{Aviseringar har pausats av {mode}}=2{Aviseringar har pausats av {mode} och ett annat läge}other{Aviseringar har pausats av {mode} och # andra lägen}}"</string>
     <string name="media_projection_action_text" msgid="3634906766918186440">"Starta nu"</string>
     <string name="empty_shade_text" msgid="8935967157319717412">"Inga aviseringar"</string>
     <string name="no_unseen_notif_text" msgid="395512586119868682">"Det finns inga nya aviseringar"</string>
@@ -673,6 +672,10 @@
     <string name="stream_notification_unavailable" msgid="4313854556205836435">"Otillgängligt eftersom ringljudet är av"</string>
     <string name="stream_alarm_unavailable" msgid="4059817189292197839">"Inte tillgängligt eftersom Stör ej är aktiverat"</string>
     <string name="stream_media_unavailable" msgid="6823020894438959853">"Inte tillgängligt eftersom Stör ej är aktiverat"</string>
+    <!-- no translation found for stream_unavailable_by_modes (3674139029490353683) -->
+    <skip />
+    <!-- no translation found for stream_unavailable_by_unknown (6908434629318171588) -->
+    <skip />
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Tryck här om du vill slå på ljudet."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Tryck här om du vill sätta på vibrationen. Tillgänglighetstjänster kanske inaktiveras."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Tryck här om du vill stänga av ljudet. Tillgänglighetstjänsterna kanske inaktiveras."</string>
@@ -706,6 +709,7 @@
     <string name="show_demo_mode" msgid="3677956462273059726">"Visa demoläge"</string>
     <string name="status_bar_ethernet" msgid="5690979758988647484">"Ethernet"</string>
     <string name="status_bar_alarm" msgid="87160847643623352">"Alarm"</string>
+    <string name="active_mode_content_description" msgid="1627555562186515927">"<xliff:g id="MODENAME">%1$s</xliff:g> är på"</string>
     <string name="wallet_title" msgid="5369767670735827105">"Wallet"</string>
     <string name="wallet_empty_state_label" msgid="7776761245237530394">"Lägg till en betalningsmetod för att betala snabbare och säkrare med telefonen"</string>
     <string name="wallet_app_button_label" msgid="7123784239111190992">"Visa alla"</string>
@@ -1405,26 +1409,26 @@
     <string name="launch_touchpad_tutorial_notification_content" msgid="7931085031240753226">"Lär dig rörelser för styrplattan"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_title" msgid="1940023776496198762">"Navigera med tangentbordet och styrplattan"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Lär dig rörelser för styrplattan, kortkommandon med mera"</string>
-    <string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Tillbaka-rörelse"</string>
-    <string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Rörelse för att öppna startskärmen"</string>
+    <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"Tillbaka"</string>
+    <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Återvänd till startsidan"</string>
     <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Se de senaste apparna"</string>
     <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Klar"</string>
     <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Tillbaka"</string>
-    <string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"Gå tillbaka genom att svepa åt vänster eller höger med tre fingrar var som helst på styrplattan.\n\nDu kan även använda kortkommandot Åtgärd + Esc."</string>
-    <string name="touchpad_back_gesture_success_title" msgid="7240576648330612171">"Bra jobbat!"</string>
+    <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"Svep åt vänster eller höger med tre fingrar på styrplattan"</string>
+    <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"Bra!"</string>
     <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"Du är klar med rörelsen för att gå tillbaka."</string>
     <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"Återvänd till startskärmen"</string>
-    <string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"Öppna startskärmen när som helst genom att svepa uppåt med tre fingrar från skärmens nederkant."</string>
-    <string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Bra!"</string>
-    <string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Du är klar med rörelsen för att öppna startskärmen."</string>
+    <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"Svep uppåt med tre fingrar på styrplattan"</string>
+    <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"Bra jobbat!"</string>
+    <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"Du är klar med rörelsen för att öppna startskärmen"</string>
     <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"Se de senaste apparna"</string>
-    <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"Svep uppåt med tre fingrar på styrplattan och håll kvar."</string>
+    <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"Svep uppåt med tre fingrar på styrplattan och håll kvar"</string>
     <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Bra jobbat!"</string>
     <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Du är klar med rörelsen för att se de senaste apparna."</string>
-    <string name="tutorial_action_key_title" msgid="2659466586996495447">"Åtgärdstangent"</string>
-    <string name="tutorial_action_key_guidance" msgid="5718948664616999196">"Tryck på åtgärdstangenten på tangentbordet för att komma åt dina appar."</string>
-    <string name="tutorial_action_key_success_title" msgid="466467860120112933">"Grattis!"</string>
-    <string name="tutorial_action_key_success_body" msgid="7201991081652850430">"Du är klar med rörelsen med åtgärdstangenten.\n\nÅtgärd + / visar alla tillgängliga genvägar."</string>
+    <string name="tutorial_action_key_title" msgid="8172535792469008169">"Visa alla appar"</string>
+    <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Tryck på åtgärdstangenten på tangentbordet"</string>
+    <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Bra gjort!"</string>
+    <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Du är klar med rörelsen för att se alla apparna."</string>
     <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Bakgrundsbelysning för tangentbord"</string>
     <string name="keyboard_backlight_value" msgid="7336398765584393538">"Nivå %1$d av %2$d"</string>
     <string name="home_controls_dream_label" msgid="6567105701292324257">"Hemstyrning"</string>
@@ -1436,6 +1440,7 @@
     <string name="all_apps_edu_toast_content" msgid="8807496014667211562">"Tryck på åtgärdstangenten på tangentbordet för att se alla appar"</string>
     <string name="redacted_notification_single_line_title" msgid="212019960919261670">"Anonymiserad"</string>
     <string name="redacted_notification_single_line_text" msgid="8684166405005242945">"Lås upp för att visa"</string>
+    <string name="contextual_education_dialog_title" msgid="4630392552837487324">"Kontextuell utbildning"</string>
     <string name="back_edu_notification_title" msgid="5624780717751357278">"Använd styrplattan för att gå tillbaka"</string>
     <string name="back_edu_notification_content" msgid="2497557451540954068">"Svep åt vänster eller höger med tre fingrar. Tryck för att lära dig fler rörelser."</string>
     <string name="home_edu_notification_title" msgid="6097902076909654045">"Använd styrplattan för att gå till startskärmen"</string>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index 45095df..d7ffdd4 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -440,7 +440,7 @@
     <string name="zen_mode_on" msgid="9085304934016242591">"Imewashwa"</string>
     <string name="zen_mode_on_with_details" msgid="7416143430557895497">"Imewashwa • <xliff:g id="TRIGGER_DESCRIPTION">%1$s</xliff:g>"</string>
     <string name="zen_mode_off" msgid="1736604456618147306">"Imezimwa"</string>
-    <string name="zen_mode_set_up" msgid="7457957033034460064">"Ratibu"</string>
+    <string name="zen_mode_set_up" msgid="8231201163894922821">"Haijawekwa"</string>
     <string name="zen_mode_no_manual_invocation" msgid="1769975741344633672">"Dhibiti katika mipangilio"</string>
     <string name="zen_mode_active_modes" msgid="1625850411578488856">"{count,plural, =0{Hakuna hali zinazotumika}=1{Unatumia {mode}}other{Unatumia hali #}}"</string>
     <string name="zen_priority_introduction" msgid="3159291973383796646">"Hutasumbuliwa na sauti na mitetemo, isipokuwa kengele, vikumbusho, matukio na simu zinazopigwa na watu uliobainisha. Bado utasikia chochote utakachochagua kucheza, ikiwa ni pamoja na muziki, video na michezo."</string>
@@ -573,8 +573,7 @@
     <string name="notification_section_header_conversations" msgid="821834744538345661">"Mazungumzo"</string>
     <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Futa arifa zote zisizo na sauti"</string>
     <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Kipengele cha Usinisumbue kimesitisha arifa"</string>
-    <!-- no translation found for modes_suppressing_shade_text (6037581130837903239) -->
-    <skip />
+    <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{Hakuna arifa}=1{Arifa zimesitishwa na {mode}}=2{Arifa zimesitishwa na {mode} na hali nyingine moja}other{Arifa zimesitishwa na {mode} na hali nyingine #}}"</string>
     <string name="media_projection_action_text" msgid="3634906766918186440">"Anza sasa"</string>
     <string name="empty_shade_text" msgid="8935967157319717412">"Hakuna arifa"</string>
     <string name="no_unseen_notif_text" msgid="395512586119868682">"Hakuna arifa mpya"</string>
@@ -673,6 +672,10 @@
     <string name="stream_notification_unavailable" msgid="4313854556205836435">"Halipatikani kwa sababu sauti imezimwa"</string>
     <string name="stream_alarm_unavailable" msgid="4059817189292197839">"Imeshindwa kwa sababu Usinisumbue imewashwa"</string>
     <string name="stream_media_unavailable" msgid="6823020894438959853">"Imeshindwa kwa sababu Usinisumbue imewashwa"</string>
+    <!-- no translation found for stream_unavailable_by_modes (3674139029490353683) -->
+    <skip />
+    <!-- no translation found for stream_unavailable_by_unknown (6908434629318171588) -->
+    <skip />
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Gusa ili urejeshe."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Gusa ili uweke mtetemo. Huenda ikakomesha huduma za zana za walio na matatizo ya kuona au kusikia."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Gusa ili ukomeshe. Huenda ikakomesha huduma za zana za walio na matatizo ya kuona au kusikia."</string>
@@ -706,6 +709,7 @@
     <string name="show_demo_mode" msgid="3677956462273059726">"Onyesha hali ya onyesho"</string>
     <string name="status_bar_ethernet" msgid="5690979758988647484">"Ethaneti"</string>
     <string name="status_bar_alarm" msgid="87160847643623352">"Kengele"</string>
+    <string name="active_mode_content_description" msgid="1627555562186515927">"Umewasha <xliff:g id="MODENAME">%1$s</xliff:g>"</string>
     <string name="wallet_title" msgid="5369767670735827105">"Pochi"</string>
     <string name="wallet_empty_state_label" msgid="7776761245237530394">"Weka njia ya kulipa ili uweze kununua kwa njia salama na haraka zaidi ukitumia simu yako"</string>
     <string name="wallet_app_button_label" msgid="7123784239111190992">"Onyesha zote"</string>
@@ -1405,26 +1409,26 @@
     <string name="launch_touchpad_tutorial_notification_content" msgid="7931085031240753226">"Jifunze kuhusu miguso ya padi ya kugusa"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_title" msgid="1940023776496198762">"Kusogeza kwa kutumia kibodi na padi yako ya kugusa"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Jifunze kuhusu miguso ya padi ya kugusa, mikato ya kibodi na mengineyo"</string>
-    <string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Ishara ya kurudi nyuma"</string>
-    <string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Mguso wa kurudi kwenye skrini ya kwanza"</string>
+    <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"Rudi nyuma"</string>
+    <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Nenda kwenye ukurasa wa mwanzo"</string>
     <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Angalia programu za hivi majuzi"</string>
     <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Nimemaliza"</string>
     <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Rudi nyuma"</string>
-    <string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"Telezesha vidole vitatu kushoto au kulia mahali popote kwenye padi ya kugusa ili urudi nyuma.\n\nUnaweza pia kutumia mikato ya kibodi ya Kitendo pamoja na ESC kutekeleza kitendo hiki."</string>
-    <string name="touchpad_back_gesture_success_title" msgid="7240576648330612171">"Kazi nzuri!"</string>
+    <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"Telezesha vidole vitatu kushoto au kulia kwenye padi yako ya kugusa"</string>
+    <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"Safi!"</string>
     <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"Umekamilisha ishara ya kurudi nyuma."</string>
     <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"Nenda kwenye skrini ya kwanza"</string>
-    <string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"Ili uende kwenye skrini ya kwanza wakati wowote, telezesha vidole vitatu juu kutoka sehemu ya chini ya skrini yako."</string>
-    <string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Safi!"</string>
-    <string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Umeweka ishara ya kwenda kwenye skrini ya kwanza."</string>
+    <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"Telezesha vidole vitatu juu kwenye padi yako ya kugusa"</string>
+    <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"Kazi nzuri!"</string>
+    <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"Umeweka ishara ya kwenda kwenye skrini ya kwanza"</string>
     <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"Angalia programu za hivi majuzi"</string>
-    <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"Telezesha vidole vitatu juu kisha ushikilie kwenye padi yako ya kugusa."</string>
+    <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"Telezesha vidole vitatu juu kisha ushikilie kwenye padi yako ya kugusa"</string>
     <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Kazi nzuri!"</string>
     <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Umekamilisha mafunzo ya mguso wa kuangalia programu za hivi majuzi."</string>
-    <string name="tutorial_action_key_title" msgid="2659466586996495447">"Kitufe cha vitendo"</string>
-    <string name="tutorial_action_key_guidance" msgid="5718948664616999196">"Bonyeza kitufe cha vitendo kwenye kibodi yako ili ufikie programu zako."</string>
-    <string name="tutorial_action_key_success_title" msgid="466467860120112933">"Hongera!"</string>
-    <string name="tutorial_action_key_success_body" msgid="7201991081652850430">"Umekamilisha ishara ya kitufe cha vitendo.\n\nKitendo + / huonyesha njia zote za mkato zinazopatikana."</string>
+    <string name="tutorial_action_key_title" msgid="8172535792469008169">"Angalia programu zote"</string>
+    <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Bonyeza kitufe cha vitendo kwenye kibodi yako"</string>
+    <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Vizuri sana!"</string>
+    <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Umekamilisha mafunzo ya mguso wa kuangalia programu zote"</string>
     <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Mwanga chini ya kibodi"</string>
     <string name="keyboard_backlight_value" msgid="7336398765584393538">"Kiwango cha %1$d kati ya %2$d"</string>
     <string name="home_controls_dream_label" msgid="6567105701292324257">"Dhibiti Vifaa Nyumbani"</string>
@@ -1436,6 +1440,7 @@
     <string name="all_apps_edu_toast_content" msgid="8807496014667211562">"Bonyeza kitufe cha vitendo kwenye kibodi yako ili uangalie programu zako zote"</string>
     <string name="redacted_notification_single_line_title" msgid="212019960919261670">"Maandishi yameondolewa"</string>
     <string name="redacted_notification_single_line_text" msgid="8684166405005242945">"Fungua ili uone"</string>
+    <string name="contextual_education_dialog_title" msgid="4630392552837487324">"Elimu inayolingana na muktadha"</string>
     <string name="back_edu_notification_title" msgid="5624780717751357278">"Kutumia padi yako ya kugusa ili kurudi nyuma"</string>
     <string name="back_edu_notification_content" msgid="2497557451540954068">"Telezesha vidole vitatu kulia au kushoto. Gusa ili upate maelezo kuhusu miguso zaidi."</string>
     <string name="home_edu_notification_title" msgid="6097902076909654045">"Kutumia padi yako ya kugusa ili kurudi kwenye skrini ya kwanza"</string>
diff --git a/packages/SystemUI/res/values-sw600dp-port/config.xml b/packages/SystemUI/res/values-sw600dp-port/config.xml
index 857e162..7daad1a 100644
--- a/packages/SystemUI/res/values-sw600dp-port/config.xml
+++ b/packages/SystemUI/res/values-sw600dp-port/config.xml
@@ -24,6 +24,9 @@
     <!-- The number of columns in the QuickSettings -->
     <integer name="quick_settings_num_columns">3</integer>
 
+    <!-- The number of columns in the infinite grid QuickSettings -->
+    <integer name="quick_settings_infinite_grid_num_columns">6</integer>
+
     <integer name="power_menu_lite_max_columns">2</integer>
     <integer name="power_menu_lite_max_rows">3</integer>
 
diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml
index 3dd0c73..ba1b0ec 100644
--- a/packages/SystemUI/res/values-ta/strings.xml
+++ b/packages/SystemUI/res/values-ta/strings.xml
@@ -440,7 +440,8 @@
     <string name="zen_mode_on" msgid="9085304934016242591">"இயக்கப்பட்டுள்ளது"</string>
     <string name="zen_mode_on_with_details" msgid="7416143430557895497">"ஆன் • <xliff:g id="TRIGGER_DESCRIPTION">%1$s</xliff:g>"</string>
     <string name="zen_mode_off" msgid="1736604456618147306">"முடக்கப்பட்டுள்ளது"</string>
-    <string name="zen_mode_set_up" msgid="7457957033034460064">"அமையுங்கள்"</string>
+    <!-- no translation found for zen_mode_set_up (8231201163894922821) -->
+    <skip />
     <string name="zen_mode_no_manual_invocation" msgid="1769975741344633672">"அமைப்புகளில் நிர்வகியுங்கள்"</string>
     <string name="zen_mode_active_modes" msgid="1625850411578488856">"{count,plural, =0{செயலிலுள்ள பயன்முறைகள் எதுவுமில்லை}=1{{mode} செயலில் உள்ளது}other{# பயன்முறைகள் செயலில் உள்ளன}}"</string>
     <string name="zen_priority_introduction" msgid="3159291973383796646">"அலாரங்கள், நினைவூட்டல்கள், நிகழ்வுகள் மற்றும் குறிப்பிட்ட அழைப்பாளர்களைத் தவிர்த்து, பிற ஒலிகள் மற்றும் அதிர்வுகளின் தொந்தரவு இருக்காது. எனினும், நீங்கள் எதையேனும் (இசை, வீடியோக்கள், கேம்ஸ் போன்றவை) ஒலிக்கும்படி தேர்ந்தெடுத்திருந்தால், அவை வழக்கம் போல் ஒலிக்கும்."</string>
@@ -573,8 +574,7 @@
     <string name="notification_section_header_conversations" msgid="821834744538345661">"உரையாடல்கள்"</string>
     <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"சைலன்ட் அறிவிப்புகள் அனைத்தையும் அழிக்கும்"</string>
     <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"\'தொந்தரவு செய்ய வேண்டாம்\' அம்சத்தின் மூலம் அறிவிப்புகள் இடைநிறுத்தப்பட்டுள்ளன"</string>
-    <!-- no translation found for modes_suppressing_shade_text (6037581130837903239) -->
-    <skip />
+    <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{அறிவிப்புகள் இல்லை}=1{{mode} பயன்முறையால் அறிவிப்புகள் இடைநிறுத்தப்பட்டுள்ளன}=2{{mode} மற்றும் வேறொரு பயன்முறையால் அறிவிப்புகள் இடைநிறுத்தப்பட்டுள்ளன}other{{mode} மற்றும் வேறு # பயன்முறைகளால் அறிவிப்புகள் இடைநிறுத்தப்பட்டுள்ளன}}"</string>
     <string name="media_projection_action_text" msgid="3634906766918186440">"இப்போது தொடங்கு"</string>
     <string name="empty_shade_text" msgid="8935967157319717412">"அறிவிப்புகள் இல்லை"</string>
     <string name="no_unseen_notif_text" msgid="395512586119868682">"புதிய அறிவிப்புகள் இல்லை"</string>
@@ -673,6 +673,10 @@
     <string name="stream_notification_unavailable" msgid="4313854556205836435">"\'ரிங்\' மியூட்டில் உள்ளதால் கிடைக்கவில்லை"</string>
     <string name="stream_alarm_unavailable" msgid="4059817189292197839">"\'தொந்தரவு செய்ய வேண்டாம்\' ஆனில் இருப்பதால் இல்லை"</string>
     <string name="stream_media_unavailable" msgid="6823020894438959853">"\'தொந்தரவு செய்ய வேண்டாம்\' ஆனில் இருப்பதால் இல்லை"</string>
+    <!-- no translation found for stream_unavailable_by_modes (3674139029490353683) -->
+    <skip />
+    <!-- no translation found for stream_unavailable_by_unknown (6908434629318171588) -->
+    <skip />
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. ஒலி இயக்க, தட்டவும்."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. அதிர்விற்கு அமைக்க, தட்டவும். அணுகல்தன்மை சேவைகள் ஒலியடக்கப்படக்கூடும்."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. ஒலியடக்க, தட்டவும். அணுகல்தன்மை சேவைகள் ஒலியடக்கப்படக்கூடும்."</string>
@@ -706,6 +710,7 @@
     <string name="show_demo_mode" msgid="3677956462273059726">"டெமோ முறையைக் காட்டு"</string>
     <string name="status_bar_ethernet" msgid="5690979758988647484">"ஈதர்நெட்"</string>
     <string name="status_bar_alarm" msgid="87160847643623352">"அலாரம்"</string>
+    <string name="active_mode_content_description" msgid="1627555562186515927">"<xliff:g id="MODENAME">%1$s</xliff:g> இயக்கப்பட்டுள்ளது"</string>
     <string name="wallet_title" msgid="5369767670735827105">"Wallet"</string>
     <string name="wallet_empty_state_label" msgid="7776761245237530394">"மொபைல் மூலம் விரைவாகவும் பாதுகாப்பாகவும் பர்ச்சேஸ்கள் செய்ய பேமெண்ட் முறையை அமைக்கவும்"</string>
     <string name="wallet_app_button_label" msgid="7123784239111190992">"அனைத்தையும் காட்டு"</string>
@@ -971,7 +976,7 @@
     <string name="notification_channel_screenshot" msgid="7665814998932211997">"ஸ்கிரீன் ஷாட்டுகள்"</string>
     <string name="notification_channel_instant" msgid="7556135423486752680">"இன்ஸ்டண்ட் ஆப்ஸ்"</string>
     <string name="notification_channel_setup" msgid="7660580986090760350">"அமைவு"</string>
-    <string name="notification_channel_storage" msgid="2720725707628094977">"சேமிப்பிடம்"</string>
+    <string name="notification_channel_storage" msgid="2720725707628094977">"சேமிப்பகம்"</string>
     <string name="notification_channel_hints" msgid="7703783206000346876">"குறிப்புகள்"</string>
     <string name="notification_channel_accessibility" msgid="8956203986976245820">"மாற்றுத்திறன் வசதி"</string>
     <string name="instant_apps" msgid="8337185853050247304">"Instant Apps"</string>
@@ -1405,26 +1410,38 @@
     <string name="launch_touchpad_tutorial_notification_content" msgid="7931085031240753226">"டச்பேட் சைகைள் குறித்துத் தெரிந்துகொள்ளுங்கள்"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_title" msgid="1940023776496198762">"உங்கள் டச்பேட் மற்றும் கீபோர்டைப் பயன்படுத்திச் செல்லுதல்"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"டச்பேட் சைகைகள், கீபோர்டு ஷார்ட்கட்கள் மற்றும் பலவற்றைத் தெரிந்துகொள்ளுங்கள்"</string>
-    <string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"பின்செல்வதற்கான சைகை"</string>
-    <string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"முகப்பிற்குச் செல்வதற்கான சைகை"</string>
+    <!-- no translation found for touchpad_tutorial_back_gesture_button (3104716365403620315) -->
+    <skip />
+    <!-- no translation found for touchpad_tutorial_home_gesture_button (8023973153559885624) -->
+    <skip />
     <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"சமீபத்திய ஆப்ஸைக் காட்டுதல்"</string>
     <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"முடிந்தது"</string>
     <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"பின்செல்"</string>
-    <string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"பின்செல்ல, உங்கள் டச்பேடில் எங்கு வேண்டுமானாலும் இடது அல்லது வலதுபுறமாக மூன்று விரல்களால் ஸ்வைப் செய்யவும்.\n\nஇதற்கு நீங்கள் கீபோர்டு ஷார்ட்கட் செயல்பாடுகள் + Esc பட்டனையும் பயன்படுத்தலாம்."</string>
-    <string name="touchpad_back_gesture_success_title" msgid="7240576648330612171">"அருமை!"</string>
+    <!-- no translation found for touchpad_back_gesture_guidance (5352221087725906542) -->
+    <skip />
+    <!-- no translation found for touchpad_back_gesture_success_title (7370719098633023496) -->
+    <skip />
     <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"பின்செல்வதற்கான சைகையை நிறைவுசெய்துவிட்டீர்கள்."</string>
     <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"முகப்பிற்குச் செல்"</string>
-    <string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"எப்போது வேண்டுமானாலும் உங்கள் முகப்புத் திரைக்குச் செல்ல, மூன்று விரல்களால் திரையின் கீழிருந்து மேல்நோக்கி ஸ்வைப் செய்யவும்."</string>
-    <string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"அற்புதம்!"</string>
-    <string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"முகப்புக்குச் செல்வதற்கான சைகையை நிறைவுசெய்துவிட்டீர்கள்."</string>
+    <!-- no translation found for touchpad_home_gesture_guidance (4178219118381915899) -->
+    <skip />
+    <!-- no translation found for touchpad_home_gesture_success_title (3648264553645798470) -->
+    <skip />
+    <!-- no translation found for touchpad_home_gesture_success_body (2590690589194027059) -->
+    <skip />
     <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"சமீபத்திய ஆப்ஸைக் காட்டுதல்"</string>
-    <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"உங்கள் டச்பேடில் மூன்று விரல்களால் மேல்நோக்கி ஸ்வைப் செய்து பிடிக்கவும்."</string>
+    <!-- no translation found for touchpad_recent_apps_gesture_guidance (6304446013842271822) -->
+    <skip />
     <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"அருமை!"</string>
     <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"சமீபத்தில் பயன்படுத்திய ஆப்ஸுக்கான சைகை பயிற்சியை நிறைவுசெய்துவிட்டீர்கள்."</string>
-    <string name="tutorial_action_key_title" msgid="2659466586996495447">"ஆக்‌ஷன் பட்டன்"</string>
-    <string name="tutorial_action_key_guidance" msgid="5718948664616999196">"ஆப்ஸை அணுக உங்கள் கீபோர்டில் உள்ள ஆக்‌ஷன் பட்டனை அழுத்துங்கள்."</string>
-    <string name="tutorial_action_key_success_title" msgid="466467860120112933">"வாழ்த்துகள்!"</string>
-    <string name="tutorial_action_key_success_body" msgid="7201991081652850430">"ஆக்‌ஷன் பட்டன் சைகையை நிறைவுசெய்துவிட்டீர்கள்.\n\nAction + / உங்களுக்குக் கிடைக்கக்கூடிய எல்லா ஷார்ட்கட்களையும் காட்டும்."</string>
+    <!-- no translation found for tutorial_action_key_title (8172535792469008169) -->
+    <skip />
+    <!-- no translation found for tutorial_action_key_guidance (5040613427202799294) -->
+    <skip />
+    <!-- no translation found for tutorial_action_key_success_title (2371827347071979571) -->
+    <skip />
+    <!-- no translation found for tutorial_action_key_success_body (1688986269491357832) -->
+    <skip />
     <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"கீபோர்டு பேக்லைட்"</string>
     <string name="keyboard_backlight_value" msgid="7336398765584393538">"நிலை, %2$d இல் %1$d"</string>
     <string name="home_controls_dream_label" msgid="6567105701292324257">"ஹோம் கன்ட்ரோல்கள்"</string>
@@ -1436,6 +1453,7 @@
     <string name="all_apps_edu_toast_content" msgid="8807496014667211562">"அனைத்து ஆப்ஸையும் பார்க்க, உங்கள் கீபோர்டில் உள்ள ஆக்ஷன் பட்டனை அழுத்தவும்"</string>
     <string name="redacted_notification_single_line_title" msgid="212019960919261670">"அர்த்தம் புரியாதபடி திருத்தப்பட்டது"</string>
     <string name="redacted_notification_single_line_text" msgid="8684166405005242945">"பார்ப்பதற்கு அன்லாக் செய்யவும்"</string>
+    <string name="contextual_education_dialog_title" msgid="4630392552837487324">"சூழல் சார்ந்த கல்வி"</string>
     <string name="back_edu_notification_title" msgid="5624780717751357278">"பின்செல்ல, உங்கள் டச்பேடைப் பயன்படுத்துங்கள்"</string>
     <string name="back_edu_notification_content" msgid="2497557451540954068">"மூன்று விரல்களால் இடது அல்லது வலதுபுறம் ஸ்வைப் செய்யவும். சைகைகள் குறித்து மேலும் அறிய தட்டவும்."</string>
     <string name="home_edu_notification_title" msgid="6097902076909654045">"முகப்புக்குச் செல்ல, உங்கள் டச்பேடைப் பயன்படுத்துங்கள்"</string>
diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml
index 65de840..8eeb149 100644
--- a/packages/SystemUI/res/values-te/strings.xml
+++ b/packages/SystemUI/res/values-te/strings.xml
@@ -21,7 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4811759950673118541">"సిస్టమ్ UI"</string>
     <string name="battery_low_title" msgid="5319680173344341779">"బ్యాటరీ సేవర్‌ను ఆన్ చేయాలా?"</string>
-    <string name="battery_low_description" msgid="3282977755476423966">"మీకు <xliff:g id="PERCENTAGE">%s</xliff:g> బ్యాటరీ మిగిలి ఉంది. బ్యాటరీ సేవర్ ముదురు రంగు రూపాన్ని ఆన్ చేస్తుంది, బ్యాక్‌గ్రౌండ్ యాక్టివిటీని పరిమితం చేస్తుంది, అలాగే నోటిఫికేషన్‌లను ఆలస్యంగా పంపిస్తుంది."</string>
+    <string name="battery_low_description" msgid="3282977755476423966">"బ్యాటరీ <xliff:g id="PERCENTAGE">%s</xliff:g> మిగిలి ఉంది. \"బ్యాటరీ సేవర్\" వల్ల డార్క్ థీమ్ ఆన్ అవుతుంది, బ్యాక్‌గ్రౌండ్ యాక్టివిటీ పరిమితం అవుతుంది, అలాగే నోటిఫికేషన్‌లు ఆలస్యంగా వస్తాయి."</string>
     <string name="battery_low_intro" msgid="5148725009653088790">"బ్యాటరీ సేవర్ ముదురు రంగు రూపాన్ని ఆన్ చేస్తుంది, బ్యాక్‌గ్రౌండ్ యాక్టివిటీని పరిమితం చేస్తుంది, అలాగే నోటిఫికేషన్‌లను ఆలస్యంగా పంపిస్తుంది."</string>
     <string name="battery_low_percent_format" msgid="4276661262843170964">"<xliff:g id="PERCENTAGE">%s</xliff:g> మిగిలి ఉంది"</string>
     <string name="invalid_charger_title" msgid="938685362320735167">"USB ద్వారా ఛార్జ్ చేయలేరు"</string>
@@ -440,7 +440,7 @@
     <string name="zen_mode_on" msgid="9085304934016242591">"ఆన్‌లో ఉంది"</string>
     <string name="zen_mode_on_with_details" msgid="7416143430557895497">"ఆన్ • <xliff:g id="TRIGGER_DESCRIPTION">%1$s</xliff:g>"</string>
     <string name="zen_mode_off" msgid="1736604456618147306">"ఆఫ్‌లో ఉంది"</string>
-    <string name="zen_mode_set_up" msgid="7457957033034460064">"సెటప్ చేయండి"</string>
+    <string name="zen_mode_set_up" msgid="8231201163894922821">"సెట్ చేసి లేదు"</string>
     <string name="zen_mode_no_manual_invocation" msgid="1769975741344633672">"సెట్టింగ్‌లలో మేనేజ్ చేయండి"</string>
     <string name="zen_mode_active_modes" msgid="1625850411578488856">"{count,plural, =0{మోడ్స్ ఏవీ యాక్టివ్‌గా లేవు}=1{{mode} యాక్టివ్‌గా ఉంది}other{# మోడ్స్ యాక్టివ్‌గా ఉన్నాయి}}"</string>
     <string name="zen_priority_introduction" msgid="3159291973383796646">"మీరు పేర్కొనే అలారాలు, రిమైండర్‌లు, ఈవెంట్‌లు మరియు కాలర్‌ల నుండి మినహా మరే ఇతర ధ్వనులు మరియు వైబ్రేషన్‌లతో మీకు అంతరాయం కలగదు. మీరు ఇప్పటికీ సంగీతం, వీడియోలు మరియు గేమ్‌లతో సహా మీరు ప్లే చేయడానికి ఎంచుకున్నవి ఏవైనా వింటారు."</string>
@@ -573,8 +573,7 @@
     <string name="notification_section_header_conversations" msgid="821834744538345661">"సంభాషణలు"</string>
     <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"అన్ని నిశ్శబ్ద నోటిఫికేషన్‌లను క్లియర్ చేస్తుంది"</string>
     <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"అంతరాయం కలిగించవద్దు ద్వారా నోటిఫికేషన్‌లు పాజ్ చేయబడ్డాయి"</string>
-    <!-- no translation found for modes_suppressing_shade_text (6037581130837903239) -->
-    <skip />
+    <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{నోటిఫికేషన్‌లు ఏవీ లేవు}=1{{mode} ద్వారా నోటిఫికేషన్‌లు పాజ్ చేయబడ్డాయి}=2{నోటిఫికేషన్‌లు, {mode}, మరో ఒక మోడ్ ద్వారా పాజ్ చేయబడ్డాయి}other{నోటిఫికేషన్‌లు, {mode}, మరో # మోడ్‌ల ద్వారా పాజ్ చేయబడ్డాయి}}"</string>
     <string name="media_projection_action_text" msgid="3634906766918186440">"ఇప్పుడే ప్రారంభించండి"</string>
     <string name="empty_shade_text" msgid="8935967157319717412">"నోటిఫికేషన్‌లు లేవు"</string>
     <string name="no_unseen_notif_text" msgid="395512586119868682">"కొత్త నోటిఫికేషన్‌లు ఏవీ లేవు"</string>
@@ -673,6 +672,10 @@
     <string name="stream_notification_unavailable" msgid="4313854556205836435">"వాల్యూమ్ మ్యూట్ అయినందున అందుబాటులో లేదు"</string>
     <string name="stream_alarm_unavailable" msgid="4059817189292197839">"అంతరాయంకలిగించవద్దు ఆన్‌లో ఉన్నందున అందుబాటులోలేదు"</string>
     <string name="stream_media_unavailable" msgid="6823020894438959853">"అంతరాయంకలిగించవద్దు ఆన్‌లో ఉన్నందున అందుబాటులోలేదు"</string>
+    <!-- no translation found for stream_unavailable_by_modes (3674139029490353683) -->
+    <skip />
+    <!-- no translation found for stream_unavailable_by_unknown (6908434629318171588) -->
+    <skip />
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. అన్‌మ్యూట్ చేయడానికి నొక్కండి."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. వైబ్రేషన్‌కు సెట్ చేయడానికి నొక్కండి. యాక్సెస్ సామర్థ్య సేవలు మ్యూట్ చేయబడవచ్చు."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. మ్యూట్ చేయడానికి నొక్కండి. యాక్సెస్ సామర్థ్య సేవలు మ్యూట్ చేయబడవచ్చు."</string>
@@ -706,6 +709,7 @@
     <string name="show_demo_mode" msgid="3677956462273059726">"డెమో మోడ్ చూపు"</string>
     <string name="status_bar_ethernet" msgid="5690979758988647484">"ఈథర్‌నెట్"</string>
     <string name="status_bar_alarm" msgid="87160847643623352">"అలారం"</string>
+    <string name="active_mode_content_description" msgid="1627555562186515927">"<xliff:g id="MODENAME">%1$s</xliff:g> ఆన్‌లో ఉంది"</string>
     <string name="wallet_title" msgid="5369767670735827105">"Wallet"</string>
     <string name="wallet_empty_state_label" msgid="7776761245237530394">"మీ ఫోన్‌తో మరింత వేగంగా, సురక్షితంగా కొనుగోళ్లు చేయడానికి సెటప్ చేయండి"</string>
     <string name="wallet_app_button_label" msgid="7123784239111190992">"అన్నింటినీ చూపు"</string>
@@ -1405,26 +1409,26 @@
     <string name="launch_touchpad_tutorial_notification_content" msgid="7931085031240753226">"టచ్‌ప్యాడ్ సంజ్ఞ గురించి తెలుసుకోండి"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_title" msgid="1940023776496198762">"మీ కీబోర్డ్, టచ్‌ప్యాడ్‌ను ఉపయోగించి నావిగేట్ చేయండి"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"టచ్‌ప్యాడ్ సంజ్ఞలు, కీబోర్డ్ షార్ట్‌కట్‌లు, అలాగే మరిన్నింటిని గురించి తెలుసుకోండి"</string>
-    <string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"వెనుకకు పంపే సంజ్ఞ"</string>
-    <string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"హోమ్‌కు పంపే సంజ్ఞ"</string>
+    <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"వెనుకకు వెళ్లండి"</string>
+    <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"మొదటి ట్యాబ్‌కు వెళ్లండి"</string>
     <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"ఇటీవలి యాప్‌లను చూడండి"</string>
     <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"పూర్తయింది"</string>
     <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"వెనుకకు"</string>
-    <string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"వెనుకకు వెళ్లడానికి, టచ్‌ప్యాడ్‌లో ఎక్కడైనా మూడు వేళ్లను ఉపయోగించి ఎడమ లేదా కుడి వైపునకు స్వైప్ చేయండి.\n\nమీరు దీని కోసం + ESC కీబోర్డ్ షార్ట్‌కట్ యాక్షన్‌ను కూడా ఉపయోగించవచ్చు."</string>
-    <string name="touchpad_back_gesture_success_title" msgid="7240576648330612171">"చక్కగా పూర్తి చేశారు!"</string>
+    <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"మీ టచ్‌ప్యాడ్‌లో మూడు వేళ్లను ఉపయోగించి ఎడమ వైపునకు లేదా కుడి వైపునకు స్వైప్ చేయండి"</string>
+    <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"పనితీరు బాగుంది!"</string>
     <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"తిరిగి వెనుకకు వెళ్ళడానికి ఉపయోగించే సంజ్ఞకు సంబంధించిన ట్యుటోరియల్‌ను మీరు పూర్తి చేశారు."</string>
     <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"మొదటి ట్యాబ్‌కు వెళ్లండి"</string>
-    <string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"ఏ సమయంలోనైనా మీ మొదటి స్క్రీన్‌కు వెళ్లడానికి, మీ స్క్రీన్ కింది నుండి మూడు వేళ్లతో పైకి స్వైప్ చేయండి."</string>
-    <string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"సూపర్!"</string>
-    <string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"మొదటి స్క్రీన్‌కు వెళ్ళడానికి ఉపయోగించే సంజ్ఞకు సంబంధించిన ట్యుటోరియల్‌ను మీరు పూర్తి చేశారు."</string>
+    <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"మీ టచ్‌ప్యాడ్‌పై మూడు వేళ్లతో పైకి స్వైప్ చేయండి"</string>
+    <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"చక్కగా పూర్తి చేశారు!"</string>
+    <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"మీరు మొదటి స్క్రీన్‌కు వెళ్లే సంజ్ఞను పూర్తి చేశారు"</string>
     <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"ఇటీవలి యాప్‌లను చూడండి"</string>
-    <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"మీ టచ్‌ప్యాడ్‌లో మూడు వేళ్లను ఉపయోగించి పైకి స్వైప్ చేసి, హోల్డ్ చేయండి."</string>
+    <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"మీ టచ్‌ప్యాడ్‌లో మూడు వేళ్లను ఉపయోగించి పైకి స్వైప్ చేసి, హోల్డ్ చేయండి"</string>
     <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"పనితీరు అద్భుతంగా ఉంది!"</string>
     <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"మీరు ఇటీవలి యాప్‌ల వీక్షణ సంజ్ఞను పూర్తి చేశారు."</string>
-    <string name="tutorial_action_key_title" msgid="2659466586996495447">"యాక్షన్ కీ"</string>
-    <string name="tutorial_action_key_guidance" msgid="5718948664616999196">"మీ యాప్‌లను యాక్సెస్ చేయడానికి, మీ కీబోర్డ్‌లో యాక్షన్ కీని నొక్కండి."</string>
-    <string name="tutorial_action_key_success_title" msgid="466467860120112933">"అభినందనలు!"</string>
-    <string name="tutorial_action_key_success_body" msgid="7201991081652850430">"మీరు \'యాక్షన్ కీ\' సంజ్ఞను పూర్తి చేశారు.\n\nAction + / నొక్కితే, మీకు అందుబాటులో ఉండే షార్ట్‌కట్‌లన్నీ కనిపిస్తాయి."</string>
+    <string name="tutorial_action_key_title" msgid="8172535792469008169">"అన్ని యాప్‌లను చూడండి"</string>
+    <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"మీ కీబోర్డ్‌లో యాక్షన్ కీని నొక్కండి"</string>
+    <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"చక్కగా చేశారు!"</string>
+    <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"మీరు అన్ని యాప్‌ల వీక్షణ సంజ్ఞను పూర్తి చేశారు"</string>
     <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"కీబోర్డ్ బ్యాక్‌లైట్"</string>
     <string name="keyboard_backlight_value" msgid="7336398765584393538">"%2$dలో %1$dవ స్థాయి"</string>
     <string name="home_controls_dream_label" msgid="6567105701292324257">"హోమ్ కంట్రోల్స్"</string>
@@ -1436,6 +1440,7 @@
     <string name="all_apps_edu_toast_content" msgid="8807496014667211562">"మీ యాప్‌లన్నింటినీ చూడటానికి, మీ కీబోర్డ్‌లో యాక్షన్ కీని నొక్కండి"</string>
     <string name="redacted_notification_single_line_title" msgid="212019960919261670">"దాచిపెట్టినది"</string>
     <string name="redacted_notification_single_line_text" msgid="8684166405005242945">"చూడటానికి అన్‌లాక్ చేయండి"</string>
+    <string name="contextual_education_dialog_title" msgid="4630392552837487324">"సందర్భోచిత విద్య"</string>
     <string name="back_edu_notification_title" msgid="5624780717751357278">"వెనుకకు వెళ్లడానికి మీ టచ్‌ప్యాడ్‌ను ఉపయోగించండి"</string>
     <string name="back_edu_notification_content" msgid="2497557451540954068">"మూడు వేళ్లతో ఎడమ / కుడి వైపునకు స్వైప్ చేయండి. మరిన్ని సంజ్ఞల గురించి తెలుసుకోవడానికి ట్యాప్ చేయండి."</string>
     <string name="home_edu_notification_title" msgid="6097902076909654045">"హోమ్‌కు వెళ్లడానికి మీ టచ్‌ప్యాడ్‌ను ఉపయోగించండి"</string>
@@ -1445,7 +1450,7 @@
     <string name="all_apps_edu_notification_title" msgid="372262997265569063">"యాప్‌లన్నింటినీ చూడటానికి మీ కీబోర్డ్‌ను ఉపయోగించండి"</string>
     <string name="all_apps_edu_notification_content" msgid="3255070575694025585">"ఏ సమయంలోనైనా యాక్షన్ కీని నొక్కండి. మరిన్ని సంజ్ఞల గురించి తెలుసుకోవడానికి ట్యాప్ చేయండి."</string>
     <string name="accessibility_deprecate_extra_dim_dialog_title" msgid="910988771011857460">"కాంతిని మరింత డిమ్ చేసే ఫీచర్ ఇప్పుడు బ్రైట్‌నెస్ స్లయిడర్‌లో ఒక భాగం"</string>
-    <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="4453123359258743230">"మీరు ఇప్పుడు బ్రైట్‌నెస్ స్థాయిని మరింత తగ్గించడం ద్వారా స్క్రీన్‌ను కాంతిని మరింత డిమ్ చేయవచ్చు.\n\nఈ ఫీచర్ ఇప్పుడు బ్రైట్‌నెస్ స్లయిడర్‌లో భాగం కాబట్టి, కాంతిని మరింత డిమ్ చేసే షార్ట్‌కట్‌లు తీసివేయబడుతున్నాయి."</string>
+    <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="4453123359258743230">"మీరు ఇప్పుడు బ్రైట్‌నెస్ స్థాయిని మరింత తగ్గించడం ద్వారా స్క్రీన్‌ కాంతిని మరింత డిమ్ చేయవచ్చు.\n\nఈ ఫీచర్ ఇప్పుడు బ్రైట్‌నెస్ స్లయిడర్‌లో భాగం కాబట్టి, కాంతిని మరింత డిమ్ చేసే షార్ట్‌కట్‌లు తీసివేయబడుతున్నాయి."</string>
     <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="3947537827396916005">"కాంతిని మరింత డిమ్ చేసే షార్ట్‌కట్‌లను తీసివేయండి"</string>
     <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="165474092660941104">"కాంతిని మరింత డిమ్ చేసే షార్ట్‌కట్‌లు తీసివేయబడ్డాయి"</string>
     <string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"కనెక్టివిటీ"</string>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index b8a385a..44a33ec 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -440,7 +440,7 @@
     <string name="zen_mode_on" msgid="9085304934016242591">"เปิด"</string>
     <string name="zen_mode_on_with_details" msgid="7416143430557895497">"เปิด • <xliff:g id="TRIGGER_DESCRIPTION">%1$s</xliff:g>"</string>
     <string name="zen_mode_off" msgid="1736604456618147306">"ปิด"</string>
-    <string name="zen_mode_set_up" msgid="7457957033034460064">"ตั้งค่า"</string>
+    <string name="zen_mode_set_up" msgid="8231201163894922821">"ไม่ได้ตั้งค่า"</string>
     <string name="zen_mode_no_manual_invocation" msgid="1769975741344633672">"จัดการในการตั้งค่า"</string>
     <string name="zen_mode_active_modes" msgid="1625850411578488856">"{count,plural, =0{ไม่มีโหมดที่ใช้งานอยู่}=1{ใช้งานอยู่ {mode} โหมด}other{ใช้งานอยู่ # โหมด}}"</string>
     <string name="zen_priority_introduction" msgid="3159291973383796646">"คุณจะไม่ถูกรบกวนจากเสียงและการสั่น ยกเว้นเสียงนาฬิกาปลุก การช่วยเตือน กิจกรรม และผู้โทรที่ระบุไว้ คุณจะยังคงได้ยินสิ่งที่คุณเลือกเล่น เช่น เพลง วิดีโอ และเกม"</string>
@@ -573,8 +573,7 @@
     <string name="notification_section_header_conversations" msgid="821834744538345661">"การสนทนา"</string>
     <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"ล้างการแจ้งเตือนแบบไม่มีเสียงทั้งหมด"</string>
     <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"หยุดการแจ้งเตือนชั่วคราวโดย \"ห้ามรบกวน\""</string>
-    <!-- no translation found for modes_suppressing_shade_text (6037581130837903239) -->
-    <skip />
+    <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{ไม่มีการแจ้งเตือน}=1{หยุดการแจ้งเตือนชั่วคราวโดย {mode}}=2{หยุดการแจ้งเตือนชั่วคราวโดย {mode} และโหมดอื่นอีก 1 โหมด}other{หยุดการแจ้งเตือนชั่วคราวโดย {mode} และโหมดอื่นอีก # โหมด}}"</string>
     <string name="media_projection_action_text" msgid="3634906766918186440">"เริ่มเลย"</string>
     <string name="empty_shade_text" msgid="8935967157319717412">"ไม่มีการแจ้งเตือน"</string>
     <string name="no_unseen_notif_text" msgid="395512586119868682">"ไม่มีการแจ้งเตือนใหม่"</string>
@@ -673,6 +672,10 @@
     <string name="stream_notification_unavailable" msgid="4313854556205836435">"เปลี่ยนไม่ได้เนื่องจากปิดเสียงเรียกเข้า"</string>
     <string name="stream_alarm_unavailable" msgid="4059817189292197839">"ไม่พร้อมใช้งานเนื่องจากโหมดห้ามรบกวนเปิดอยู่"</string>
     <string name="stream_media_unavailable" msgid="6823020894438959853">"ไม่พร้อมใช้งานเนื่องจากโหมดห้ามรบกวนเปิดอยู่"</string>
+    <!-- no translation found for stream_unavailable_by_modes (3674139029490353683) -->
+    <skip />
+    <!-- no translation found for stream_unavailable_by_unknown (6908434629318171588) -->
+    <skip />
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s แตะเพื่อเปิดเสียง"</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s แตะเพื่อตั้งค่าให้สั่น อาจมีการปิดเสียงบริการการเข้าถึง"</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s แตะเพื่อปิดเสียง อาจมีการปิดเสียงบริการการเข้าถึง"</string>
@@ -706,6 +709,7 @@
     <string name="show_demo_mode" msgid="3677956462273059726">"แสดงโหมดสาธิต"</string>
     <string name="status_bar_ethernet" msgid="5690979758988647484">"อีเทอร์เน็ต"</string>
     <string name="status_bar_alarm" msgid="87160847643623352">"การปลุก"</string>
+    <string name="active_mode_content_description" msgid="1627555562186515927">"<xliff:g id="MODENAME">%1$s</xliff:g> เปิดอยู่"</string>
     <string name="wallet_title" msgid="5369767670735827105">"Wallet"</string>
     <string name="wallet_empty_state_label" msgid="7776761245237530394">"ตั้งค่าเพื่อซื้อสินค้าและบริการด้วยโทรศัพท์ได้อย่างรวดเร็วและปลอดภัยยิ่งขึ้น"</string>
     <string name="wallet_app_button_label" msgid="7123784239111190992">"แสดงทั้งหมด"</string>
@@ -1405,26 +1409,26 @@
     <string name="launch_touchpad_tutorial_notification_content" msgid="7931085031240753226">"ดูข้อมูลเกี่ยวกับท่าทางสัมผัสของทัชแพด"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_title" msgid="1940023776496198762">"ไปยังส่วนต่างๆ โดยใช้แป้นพิมพ์และทัชแพด"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"ดูข้อมูลเกี่ยวกับท่าทางสัมผัสของทัชแพด แป้นพิมพ์ลัด และอื่นๆ"</string>
-    <string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"ท่าทางสัมผัสสำหรับย้อนกลับ"</string>
-    <string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"ท่าทางสัมผัสสำหรับหน้าแรก"</string>
+    <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"ย้อนกลับ"</string>
+    <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"ไปที่หน้าแรก"</string>
     <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"ดูแอปล่าสุด"</string>
     <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"เสร็จสิ้น"</string>
     <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"ย้อนกลับ"</string>
-    <string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"หากต้องการย้อนกลับ ให้ใช้ 3 นิ้วปัดไปทางซ้ายหรือขวาที่ใดก็ได้บนทัชแพด\n\nหรือใช้การดำเนินการแป้นพิมพ์ลัด + ESC ได้เช่นเดียวกัน"</string>
-    <string name="touchpad_back_gesture_success_title" msgid="7240576648330612171">"เก่งมาก"</string>
+    <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"ใช้ 3 นิ้วปัดไปทางซ้ายหรือขวาบนทัชแพด"</string>
+    <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"ดีมาก"</string>
     <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"คุณทำท่าทางสัมผัสเพื่อย้อนกลับเสร็จแล้ว"</string>
     <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"ไปที่หน้าแรก"</string>
-    <string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"ใช้ 3 นิ้วปัดขึ้นจากด้านล่างของหน้าจอเพื่อไปที่หน้าจอหลักได้ทุกเมื่อ"</string>
-    <string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"ดีมาก"</string>
-    <string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"คุณทำท่าทางสัมผัสเพื่อไปที่หน้าแรกเสร็จแล้ว"</string>
+    <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"ใช้ 3 นิ้วปัดขึ้นบนทัชแพด"</string>
+    <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"เก่งมาก"</string>
+    <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"คุณทำท่าทางสัมผัสเพื่อไปที่หน้าแรกเสร็จแล้ว"</string>
     <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"ดูแอปล่าสุด"</string>
-    <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"ใช้ 3 นิ้วปัดขึ้นแล้วค้างไว้บนทัชแพด"</string>
+    <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"ใช้ 3 นิ้วปัดขึ้นแล้วค้างไว้บนทัชแพด"</string>
     <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"เยี่ยมมาก"</string>
     <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"คุณทำท่าทางสัมผัสเพื่อดูแอปล่าสุดสำเร็จแล้ว"</string>
-    <string name="tutorial_action_key_title" msgid="2659466586996495447">"ปุ่มดำเนินการ"</string>
-    <string name="tutorial_action_key_guidance" msgid="5718948664616999196">"หากต้องการเข้าถึงแอป ให้กดปุ่มดำเนินการบนแป้นพิมพ์"</string>
-    <string name="tutorial_action_key_success_title" msgid="466467860120112933">"ยินดีด้วย"</string>
-    <string name="tutorial_action_key_success_body" msgid="7201991081652850430">"คุณทำท่าทางสัมผัสสำหรับปุ่มดำเนินการเสร็จแล้ว\n\nการดำเนินการ + / จะแสดงแป้นพิมพ์ลัดทั้งหมดที่คุณมี"</string>
+    <string name="tutorial_action_key_title" msgid="8172535792469008169">"ดูแอปทั้งหมด"</string>
+    <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"กดปุ่มดำเนินการบนแป้นพิมพ์"</string>
+    <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"ยอดเยี่ยม"</string>
+    <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"คุณทำท่าทางสัมผัสเพื่อดูแอปทั้งหมดเสร็จแล้ว"</string>
     <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"ไฟแบ็กไลต์ของแป้นพิมพ์"</string>
     <string name="keyboard_backlight_value" msgid="7336398765584393538">"ระดับที่ %1$d จาก %2$d"</string>
     <string name="home_controls_dream_label" msgid="6567105701292324257">"ระบบควบคุมอุปกรณ์สมาร์ทโฮม"</string>
@@ -1436,6 +1440,7 @@
     <string name="all_apps_edu_toast_content" msgid="8807496014667211562">"หากต้องการดูแอปทั้งหมด ให้กดปุ่มดำเนินการบนแป้นพิมพ์"</string>
     <string name="redacted_notification_single_line_title" msgid="212019960919261670">"ปกปิดไว้"</string>
     <string name="redacted_notification_single_line_text" msgid="8684166405005242945">"ปลดล็อกเพื่อดู"</string>
+    <string name="contextual_education_dialog_title" msgid="4630392552837487324">"การศึกษาตามบริบท"</string>
     <string name="back_edu_notification_title" msgid="5624780717751357278">"ใช้ทัชแพดเพื่อย้อนกลับ"</string>
     <string name="back_edu_notification_content" msgid="2497557451540954068">"ใช้ 3 นิ้วปัดไปทางซ้ายหรือขวา แตะเพื่อดูข้อมูลเพิ่มเติมเกี่ยวกับท่าทางสัมผัสต่างๆ"</string>
     <string name="home_edu_notification_title" msgid="6097902076909654045">"ใช้ทัชแพดเพื่อไปยังหน้าแรก"</string>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index f2cecf9..c782dd4 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -440,7 +440,7 @@
     <string name="zen_mode_on" msgid="9085304934016242591">"Naka-on"</string>
     <string name="zen_mode_on_with_details" msgid="7416143430557895497">"Naka-on • <xliff:g id="TRIGGER_DESCRIPTION">%1$s</xliff:g>"</string>
     <string name="zen_mode_off" msgid="1736604456618147306">"Naka-off"</string>
-    <string name="zen_mode_set_up" msgid="7457957033034460064">"I-set up"</string>
+    <string name="zen_mode_set_up" msgid="8231201163894922821">"Hindi nakatakda"</string>
     <string name="zen_mode_no_manual_invocation" msgid="1769975741344633672">"Pamahalaan sa mga setting"</string>
     <string name="zen_mode_active_modes" msgid="1625850411578488856">"{count,plural, =0{Walang aktibong mode}=1{Aktibo ang {mode}}one{# mode ang aktibo}other{# na mode ang aktibo}}"</string>
     <string name="zen_priority_introduction" msgid="3159291973383796646">"Hindi ka maiistorbo ng mga tunog at pag-vibrate, maliban mula sa mga alarm, paalala, event, at tumatawag na tutukuyin mo. Maririnig mo pa rin ang kahit na anong piliin mong i-play kabilang ang mga musika, video, at laro."</string>
@@ -573,8 +573,7 @@
     <string name="notification_section_header_conversations" msgid="821834744538345661">"Mga Pag-uusap"</string>
     <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"I-clear ang lahat ng silent na notification"</string>
     <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Mga notification na na-pause ng Huwag Istorbohin"</string>
-    <!-- no translation found for modes_suppressing_shade_text (6037581130837903239) -->
-    <skip />
+    <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{Walang notification}=1{Na-pause ng {mode} ang mga notification}=2{Na-pause ng {mode} at isa pang mode ang mga notification}one{Na-pause ng {mode} at # pang mode ang mga notification}other{Na-pause ng {mode} at # pang mode ang mga notification}}"</string>
     <string name="media_projection_action_text" msgid="3634906766918186440">"Magsimula ngayon"</string>
     <string name="empty_shade_text" msgid="8935967157319717412">"Walang mga notification"</string>
     <string name="no_unseen_notif_text" msgid="395512586119868682">"Walang bagong notification"</string>
@@ -673,6 +672,10 @@
     <string name="stream_notification_unavailable" msgid="4313854556205836435">"Hindi available dahil naka-mute ang ring"</string>
     <string name="stream_alarm_unavailable" msgid="4059817189292197839">"Hindi available dahil naka-on ang Huwag Istorbohin"</string>
     <string name="stream_media_unavailable" msgid="6823020894438959853">"Hindi available dahil naka-on ang Huwag Istorbohin"</string>
+    <!-- no translation found for stream_unavailable_by_modes (3674139029490353683) -->
+    <skip />
+    <!-- no translation found for stream_unavailable_by_unknown (6908434629318171588) -->
+    <skip />
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. I-tap upang i-unmute."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. I-tap upang itakda na mag-vibrate. Maaaring i-mute ang mga serbisyo sa Accessibility."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. I-tap upang i-mute. Maaaring i-mute ang mga serbisyo sa Accessibility."</string>
@@ -706,6 +709,7 @@
     <string name="show_demo_mode" msgid="3677956462273059726">"Ipakita ang demo mode"</string>
     <string name="status_bar_ethernet" msgid="5690979758988647484">"Ethernet"</string>
     <string name="status_bar_alarm" msgid="87160847643623352">"Alarm"</string>
+    <string name="active_mode_content_description" msgid="1627555562186515927">"Naka-on ang <xliff:g id="MODENAME">%1$s</xliff:g>"</string>
     <string name="wallet_title" msgid="5369767670735827105">"Wallet"</string>
     <string name="wallet_empty_state_label" msgid="7776761245237530394">"I-set up para makapagsagawa ng mas mabibilis, mas secure na pagbili gamit ang telepono mo"</string>
     <string name="wallet_app_button_label" msgid="7123784239111190992">"Ipakita lahat"</string>
@@ -1405,26 +1409,26 @@
     <string name="launch_touchpad_tutorial_notification_content" msgid="7931085031240753226">"Matuto ng mga galaw sa touchpad"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_title" msgid="1940023776496198762">"Mag-navigate gamit ang iyong keyboard at touchpad"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Matuto ng mga galaw sa touchpad, keyboard shortcut, at higit pa"</string>
-    <string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Galaw para bumalik"</string>
-    <string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Galaw para sa Home"</string>
+    <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"Bumalik"</string>
+    <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Pumunta sa home"</string>
     <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Tingnan ang mga kamakailang app"</string>
     <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Tapos na"</string>
     <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Bumalik"</string>
-    <string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"Para bumalik, mag-swipe pakaliwa o pakanan gamit ang tatlong daliri saanman sa touchpad.\n\nPuwede mo ring gamitin ang keyboard shortcut na Action + ESC para dito."</string>
-    <string name="touchpad_back_gesture_success_title" msgid="7240576648330612171">"Magaling!"</string>
+    <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"Mag-swipe pakaliwa o pakanan gamit ang tatlong daliri sa iyong touchpad"</string>
+    <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"Magaling!"</string>
     <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"Nakumpleto mo na ang galaw para bumalik."</string>
     <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"Pumunta sa home"</string>
-    <string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"Para pumunta sa iyong home screen anumang oras, mag-swipe pataas gamit ang tatlong daliri mula sa ibaba ng screen. mo."</string>
-    <string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Magaling!"</string>
-    <string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Nakumpleto mo na ang galaw para pumunta sa home."</string>
+    <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"Mag-swipe pataas gamit ang tatlong daliri sa iyong touchpad"</string>
+    <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"Magaling!"</string>
+    <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"Nakumpleto mo na ang galaw para pumunta sa home"</string>
     <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"Tingnan ang mga kamakailang app"</string>
-    <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"Mag-swipe pataas at i-hold gamit ang tatlong daliri sa iyong touchpad."</string>
+    <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"Mag-swipe pataas at i-hold gamit ang tatlong daliri sa iyong touchpad"</string>
     <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Magaling!"</string>
     <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Nakumpleto mo ang galaw sa pag-view ng mga kamakailang app."</string>
-    <string name="tutorial_action_key_title" msgid="2659466586996495447">"Action key"</string>
-    <string name="tutorial_action_key_guidance" msgid="5718948664616999196">"Para ma-access ang iyong mga app, pindutin ang action key sa keyboard mo."</string>
-    <string name="tutorial_action_key_success_title" msgid="466467860120112933">"Binabati kita!"</string>
-    <string name="tutorial_action_key_success_body" msgid="7201991081652850430">"Nakumpleto mo na ang galaw ng action key.\n\nIpinapakita ng Action + / ang lahat ng shortcut na available sa iyo."</string>
+    <string name="tutorial_action_key_title" msgid="8172535792469008169">"Tingnan ang lahat ng app"</string>
+    <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Pindutin ang action key sa iyong keyboard"</string>
+    <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Magaling!"</string>
+    <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Nakumpleto mo ang galaw sa pag-view ng lahat ng app"</string>
     <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Backlight ng keyboard"</string>
     <string name="keyboard_backlight_value" msgid="7336398765584393538">"Level %1$d sa %2$d"</string>
     <string name="home_controls_dream_label" msgid="6567105701292324257">"Mga Home Control"</string>
@@ -1436,6 +1440,7 @@
     <string name="all_apps_edu_toast_content" msgid="8807496014667211562">"Para tingnan ang lahat ng iyong app, pindutin ang action key sa keyboard mo"</string>
     <string name="redacted_notification_single_line_title" msgid="212019960919261670">"Na-redact"</string>
     <string name="redacted_notification_single_line_text" msgid="8684166405005242945">"I-unlock para tingnan"</string>
+    <string name="contextual_education_dialog_title" msgid="4630392552837487324">"Edukasyon ayon sa konteksto"</string>
     <string name="back_edu_notification_title" msgid="5624780717751357278">"Gamitin ang iyong touchpad para bumalik"</string>
     <string name="back_edu_notification_content" msgid="2497557451540954068">"Mag-swipe pakaliwa o pakanan gamit ang tatlong daliri. I-tap para matuto pa tungkol sa mga galaw."</string>
     <string name="home_edu_notification_title" msgid="6097902076909654045">"Gamitin ang touchpad mo para pumunta sa home"</string>
@@ -1445,7 +1450,7 @@
     <string name="all_apps_edu_notification_title" msgid="372262997265569063">"Gamitin ang iyong keyboard para tingnan ang lahat ng app"</string>
     <string name="all_apps_edu_notification_content" msgid="3255070575694025585">"Pindutin ang action key kahit kailan. I-tap para matuto pa tungkol sa mga galaw."</string>
     <string name="accessibility_deprecate_extra_dim_dialog_title" msgid="910988771011857460">"Bahagi na ng slider ng liwanag ang extra dim"</string>
-    <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="4453123359258743230">"Puwede mo nang gawing extra dim ang screen sa pamamagitan ng pagbababa pa sa antas ng liwanag .\n\nDahil bahagi na ang feature na ito ng slider ng liwanag, aalisin na ang mga shortcut sa extra dim."</string>
+    <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="4453123359258743230">"Puwede mo nang gawing extra dim ang screen sa pamamagitan ng pagbababa pa ng antas ng liwanag .\n\nDahil bahagi na ang feature na ito ng slider ng liwanag, aalisin na ang mga shortcut sa extra dim."</string>
     <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="3947537827396916005">"Alisin ang mga shortcut sa extra dim"</string>
     <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="165474092660941104">"Inalis ang mga shortcut sa extra dim"</string>
     <string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"Pagkakonekta"</string>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index 570657d..ad543cf 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -440,7 +440,8 @@
     <string name="zen_mode_on" msgid="9085304934016242591">"Açık"</string>
     <string name="zen_mode_on_with_details" msgid="7416143430557895497">"Açık • <xliff:g id="TRIGGER_DESCRIPTION">%1$s</xliff:g>"</string>
     <string name="zen_mode_off" msgid="1736604456618147306">"Kapalı"</string>
-    <string name="zen_mode_set_up" msgid="7457957033034460064">"Ayarla"</string>
+    <!-- no translation found for zen_mode_set_up (8231201163894922821) -->
+    <skip />
     <string name="zen_mode_no_manual_invocation" msgid="1769975741344633672">"Ayarlarda yönet"</string>
     <string name="zen_mode_active_modes" msgid="1625850411578488856">"{count,plural, =0{Etkin mod yok}=1{{mode} etkin}other{# mod etkin}}"</string>
     <string name="zen_priority_introduction" msgid="3159291973383796646">"Alarmlar, hatırlatıcılar, etkinlikler ve sizin seçtiğiniz kişilerden gelen çağrılar dışında hiçbir ses ve titreşimle rahatsız edilmeyeceksiniz. O sırada çaldığınız müzik, seyrettiğiniz video ya da oynadığınız oyunların sesini duymaya devam edeceksiniz."</string>
@@ -573,8 +574,7 @@
     <string name="notification_section_header_conversations" msgid="821834744538345661">"Görüşmeler"</string>
     <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Sessiz bildirimlerin tümünü temizle"</string>
     <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Bildirimler, Rahatsız Etmeyin özelliği tarafından duraklatıldı"</string>
-    <!-- no translation found for modes_suppressing_shade_text (6037581130837903239) -->
-    <skip />
+    <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{Bildirim yok}=1{Bildirimler {mode} tarafından duraklatıldı}=2{Bildirimler, {mode} ve bir diğer mod tarafından duraklatıldı}other{Bildirimler, {mode} ve # diğer mod tarafından duraklatıldı}}"</string>
     <string name="media_projection_action_text" msgid="3634906766918186440">"Şimdi başlat"</string>
     <string name="empty_shade_text" msgid="8935967157319717412">"Bildirim yok"</string>
     <string name="no_unseen_notif_text" msgid="395512586119868682">"Yeni bildirim yok"</string>
@@ -673,6 +673,10 @@
     <string name="stream_notification_unavailable" msgid="4313854556205836435">"Zil sesi kapatıldığı için kullanılamıyor"</string>
     <string name="stream_alarm_unavailable" msgid="4059817189292197839">"Rahatsız Etmeyin açık olduğu için kullanılamıyor"</string>
     <string name="stream_media_unavailable" msgid="6823020894438959853">"Rahatsız Etmeyin açık olduğu için kullanılamıyor"</string>
+    <!-- no translation found for stream_unavailable_by_modes (3674139029490353683) -->
+    <skip />
+    <!-- no translation found for stream_unavailable_by_unknown (6908434629318171588) -->
+    <skip />
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Sesi açmak için dokunun."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Titreşime ayarlamak için dokunun. Erişilebilirlik hizmetlerinin sesi kapatılabilir."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Sesi kapatmak için dokunun. Erişilebilirlik hizmetlerinin sesi kapatılabilir."</string>
@@ -706,6 +710,7 @@
     <string name="show_demo_mode" msgid="3677956462273059726">"Demo modunu göster"</string>
     <string name="status_bar_ethernet" msgid="5690979758988647484">"Ethernet"</string>
     <string name="status_bar_alarm" msgid="87160847643623352">"Alarm"</string>
+    <string name="active_mode_content_description" msgid="1627555562186515927">"<xliff:g id="MODENAME">%1$s</xliff:g> açık"</string>
     <string name="wallet_title" msgid="5369767670735827105">"Cüzdan"</string>
     <string name="wallet_empty_state_label" msgid="7776761245237530394">"Telefonunuzla daha hızlı ve güvenli satın alma işlemleri gerçekleştirmek için gerekli ayarları yapın"</string>
     <string name="wallet_app_button_label" msgid="7123784239111190992">"Tümünü göster"</string>
@@ -1405,26 +1410,38 @@
     <string name="launch_touchpad_tutorial_notification_content" msgid="7931085031240753226">"Dokunmatik alan hareketlerini öğrenin"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_title" msgid="1940023776496198762">"Klavyenizi ve dokunmatik alanınızı kullanarak gezinin"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Dokunmatik alan hareketlerini, klavye kısayollarını ve daha fazlasını öğrenin"</string>
-    <string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Geri hareketi"</string>
-    <string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Ana sayfa hareketi"</string>
+    <!-- no translation found for touchpad_tutorial_back_gesture_button (3104716365403620315) -->
+    <skip />
+    <!-- no translation found for touchpad_tutorial_home_gesture_button (8023973153559885624) -->
+    <skip />
     <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Son uygulamaları görüntüle"</string>
     <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Bitti"</string>
     <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Geri dön"</string>
-    <string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"Geri dönmek için dokunmatik alanın herhangi bir yerinde üç parmağınızla sola veya sağa kaydırın.\n\nDilerseniz işlem düğmesi + Esc klavye kısayolunu kullanarak da geri dönebilirsiniz."</string>
-    <string name="touchpad_back_gesture_success_title" msgid="7240576648330612171">"Tebrikler!"</string>
+    <!-- no translation found for touchpad_back_gesture_guidance (5352221087725906542) -->
+    <skip />
+    <!-- no translation found for touchpad_back_gesture_success_title (7370719098633023496) -->
+    <skip />
     <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"Geri dön hareketini tamamladınız."</string>
     <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"Ana sayfaya gidin"</string>
-    <string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"İstediğiniz zaman ana ekrana gitmek için üç parmağınızla ekranınızın altından yukarı doğru kaydırın."</string>
-    <string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Güzel!"</string>
-    <string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Ana ekrana git hareketini tamamladınız."</string>
+    <!-- no translation found for touchpad_home_gesture_guidance (4178219118381915899) -->
+    <skip />
+    <!-- no translation found for touchpad_home_gesture_success_title (3648264553645798470) -->
+    <skip />
+    <!-- no translation found for touchpad_home_gesture_success_body (2590690589194027059) -->
+    <skip />
     <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"Son uygulamaları görüntüle"</string>
-    <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"Dokunmatik alanda üç parmağınızla yukarı doğru kaydırıp basılı tutun."</string>
+    <!-- no translation found for touchpad_recent_apps_gesture_guidance (6304446013842271822) -->
+    <skip />
     <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Tebrikler!"</string>
     <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Son uygulamaları görüntüleme hareketini tamamladınız."</string>
-    <string name="tutorial_action_key_title" msgid="2659466586996495447">"Eylem tuşu"</string>
-    <string name="tutorial_action_key_guidance" msgid="5718948664616999196">"Uygulamalarınıza erişmek için klavyenizdeki eylem tuşuna basın."</string>
-    <string name="tutorial_action_key_success_title" msgid="466467860120112933">"Tebrikler!"</string>
-    <string name="tutorial_action_key_success_body" msgid="7201991081652850430">"Eylem tuşu hareketini tamamladınız.\n\nKullanabileceğiniz tüm kısayolları görmek için eylem + / tuşuna basın."</string>
+    <!-- no translation found for tutorial_action_key_title (8172535792469008169) -->
+    <skip />
+    <!-- no translation found for tutorial_action_key_guidance (5040613427202799294) -->
+    <skip />
+    <!-- no translation found for tutorial_action_key_success_title (2371827347071979571) -->
+    <skip />
+    <!-- no translation found for tutorial_action_key_success_body (1688986269491357832) -->
+    <skip />
     <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Klavye aydınlatması"</string>
     <string name="keyboard_backlight_value" msgid="7336398765584393538">"Seviye %1$d / %2$d"</string>
     <string name="home_controls_dream_label" msgid="6567105701292324257">"Ev Kontrolleri"</string>
@@ -1436,6 +1453,7 @@
     <string name="all_apps_edu_toast_content" msgid="8807496014667211562">"Tüm uygulamalarınızı görüntülemek için klavyenizdeki eylem tuşuna basın"</string>
     <string name="redacted_notification_single_line_title" msgid="212019960919261670">"Çıkartıldı"</string>
     <string name="redacted_notification_single_line_text" msgid="8684166405005242945">"Görüntülemek için kilidi açın"</string>
+    <string name="contextual_education_dialog_title" msgid="4630392552837487324">"Bağlama dayalı eğitim"</string>
     <string name="back_edu_notification_title" msgid="5624780717751357278">"Geri dönmek için dokunmatik alanınızı kullanın"</string>
     <string name="back_edu_notification_content" msgid="2497557451540954068">"Üç parmağınızla sola veya sağa kaydırın. Daha fazla hareket öğrenmek için dokunun."</string>
     <string name="home_edu_notification_title" msgid="6097902076909654045">"Ana sayfaya gitmek için dokunmatik alanınızı kullanın"</string>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index 65b1b39..0d664e3 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -440,7 +440,8 @@
     <string name="zen_mode_on" msgid="9085304934016242591">"Увімкнено"</string>
     <string name="zen_mode_on_with_details" msgid="7416143430557895497">"Увімк. • <xliff:g id="TRIGGER_DESCRIPTION">%1$s</xliff:g>"</string>
     <string name="zen_mode_off" msgid="1736604456618147306">"Вимкнено"</string>
-    <string name="zen_mode_set_up" msgid="7457957033034460064">"Налаштувати"</string>
+    <!-- no translation found for zen_mode_set_up (8231201163894922821) -->
+    <skip />
     <string name="zen_mode_no_manual_invocation" msgid="1769975741344633672">"Керувати в налаштуваннях"</string>
     <string name="zen_mode_active_modes" msgid="1625850411578488856">"{count,plural, =0{Немає активних режимів}=1{Активовано режим \"{mode}\"}one{Активовано # режим}few{Активовано # режими}many{Активовано # режимів}other{Активовано # режиму}}"</string>
     <string name="zen_priority_introduction" msgid="3159291973383796646">"Ви отримуватиме звукові та вібросигнали лише для вибраних будильників, нагадувань, подій і абонентів. Однак ви чутимете все, що захочете відтворити, зокрема музику, відео й ігри."</string>
@@ -573,8 +574,7 @@
     <string name="notification_section_header_conversations" msgid="821834744538345661">"Розмови"</string>
     <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Очистити всі беззвучні сповіщення"</string>
     <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Режим \"Не турбувати\" призупинив сповіщення"</string>
-    <!-- no translation found for modes_suppressing_shade_text (6037581130837903239) -->
-    <skip />
+    <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{Немає сповіщень}=1{Режим \"{mode}\" призупинив надсилання сповіщень}=2{\"{mode}\" і ще один режим призупинили надсилання сповіщень}one{\"{mode}\" і ще # режим призупинили надсилання сповіщень}few{\"{mode}\" і ще # режими призупинили надсилання сповіщень}many{\"{mode}\" і ще # режимів призупинили надсилання сповіщень}other{\"{mode}\" і ще # режиму призупинили надсилання сповіщень}}"</string>
     <string name="media_projection_action_text" msgid="3634906766918186440">"Почати зараз"</string>
     <string name="empty_shade_text" msgid="8935967157319717412">"Сповіщень немає"</string>
     <string name="no_unseen_notif_text" msgid="395512586119868682">"Немає нових сповіщень"</string>
@@ -673,6 +673,10 @@
     <string name="stream_notification_unavailable" msgid="4313854556205836435">"Недоступно: звук дзвінків вимкнено"</string>
     <string name="stream_alarm_unavailable" msgid="4059817189292197839">"Недоступно: увімкнено режим \"Не турбувати\""</string>
     <string name="stream_media_unavailable" msgid="6823020894438959853">"Недоступно: увімкнено режим \"Не турбувати\""</string>
+    <!-- no translation found for stream_unavailable_by_modes (3674139029490353683) -->
+    <skip />
+    <!-- no translation found for stream_unavailable_by_unknown (6908434629318171588) -->
+    <skip />
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Торкніться, щоб увімкнути звук."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Торкніться, щоб налаштувати вібросигнал. Спеціальні можливості може бути вимкнено."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Торкніться, щоб вимкнути звук. Спеціальні можливості може бути вимкнено."</string>
@@ -706,6 +710,7 @@
     <string name="show_demo_mode" msgid="3677956462273059726">"Показати демонстраційний режим"</string>
     <string name="status_bar_ethernet" msgid="5690979758988647484">"Ethernet"</string>
     <string name="status_bar_alarm" msgid="87160847643623352">"Будильник"</string>
+    <string name="active_mode_content_description" msgid="1627555562186515927">"Увімкнено режим \"<xliff:g id="MODENAME">%1$s</xliff:g>\""</string>
     <string name="wallet_title" msgid="5369767670735827105">"Гаманець"</string>
     <string name="wallet_empty_state_label" msgid="7776761245237530394">"Швидше й безпечніше сплачуйте за покупки за допомогою телефона"</string>
     <string name="wallet_app_button_label" msgid="7123784239111190992">"Показати все"</string>
@@ -1405,26 +1410,38 @@
     <string name="launch_touchpad_tutorial_notification_content" msgid="7931085031240753226">"Жести для сенсорної панелі: докладніше"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_title" msgid="1940023776496198762">"Навігація за допомогою клавіатури й сенсорної панелі"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Жести для сенсорної панелі, комбінації клавіш тощо: докладніше"</string>
-    <string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Жест \"Назад\""</string>
-    <string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Жест переходу на головний екран"</string>
+    <!-- no translation found for touchpad_tutorial_back_gesture_button (3104716365403620315) -->
+    <skip />
+    <!-- no translation found for touchpad_tutorial_home_gesture_button (8023973153559885624) -->
+    <skip />
     <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Переглянути нещодавні додатки"</string>
     <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Готово"</string>
     <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Назад"</string>
-    <string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"Щоб перейти назад, проведіть трьома пальцями вліво або вправо по сенсорній панелі.\n\nТакож можна скористатися комбінацією \"клавіша дії\" + ESC."</string>
-    <string name="touchpad_back_gesture_success_title" msgid="7240576648330612171">"Чудово!"</string>
+    <!-- no translation found for touchpad_back_gesture_guidance (5352221087725906542) -->
+    <skip />
+    <!-- no translation found for touchpad_back_gesture_success_title (7370719098633023496) -->
+    <skip />
     <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"Ви виконали жест \"Назад\"."</string>
     <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"Перейти на головний екран"</string>
-    <string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"Щоб будь-коли перейти на головний екран, проведіть трьома пальцями вгору від нижнього краю екрана."</string>
-    <string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Чудово!"</string>
-    <string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Ви виконали жест переходу на головний екран."</string>
+    <!-- no translation found for touchpad_home_gesture_guidance (4178219118381915899) -->
+    <skip />
+    <!-- no translation found for touchpad_home_gesture_success_title (3648264553645798470) -->
+    <skip />
+    <!-- no translation found for touchpad_home_gesture_success_body (2590690589194027059) -->
+    <skip />
     <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"Переглянути нещодавні додатки"</string>
-    <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"Проведіть трьома пальцями вгору й утримуйте їх на сенсорній панелі."</string>
+    <!-- no translation found for touchpad_recent_apps_gesture_guidance (6304446013842271822) -->
+    <skip />
     <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Чудово!"</string>
     <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Ви виконали жест для перегляду нещодавно відкритих додатків."</string>
-    <string name="tutorial_action_key_title" msgid="2659466586996495447">"Клавіша дії"</string>
-    <string name="tutorial_action_key_guidance" msgid="5718948664616999196">"Щоб переглянути додатки, натисніть клавішу дії на клавіатурі."</string>
-    <string name="tutorial_action_key_success_title" msgid="466467860120112933">"Вітаємо!"</string>
-    <string name="tutorial_action_key_success_body" msgid="7201991081652850430">"Ви виконали жест клавіші дії.\n\nНатисніть клавішу дії + /, щоб переглянути всі доступні комбінації клавіш."</string>
+    <!-- no translation found for tutorial_action_key_title (8172535792469008169) -->
+    <skip />
+    <!-- no translation found for tutorial_action_key_guidance (5040613427202799294) -->
+    <skip />
+    <!-- no translation found for tutorial_action_key_success_title (2371827347071979571) -->
+    <skip />
+    <!-- no translation found for tutorial_action_key_success_body (1688986269491357832) -->
+    <skip />
     <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Підсвічування клавіатури"</string>
     <string name="keyboard_backlight_value" msgid="7336398765584393538">"Рівень %1$d з %2$d"</string>
     <string name="home_controls_dream_label" msgid="6567105701292324257">"Автоматизація дому"</string>
@@ -1436,6 +1453,7 @@
     <string name="all_apps_edu_toast_content" msgid="8807496014667211562">"Щоб переглянути всі додатки, натисніть клавішу дії на клавіатурі"</string>
     <string name="redacted_notification_single_line_title" msgid="212019960919261670">"Замасковано"</string>
     <string name="redacted_notification_single_line_text" msgid="8684166405005242945">"Розблокуйте, щоб переглянути"</string>
+    <string name="contextual_education_dialog_title" msgid="4630392552837487324">"Контекстне навчання"</string>
     <string name="back_edu_notification_title" msgid="5624780717751357278">"Щоб повернутися, використовуйте сенсорну панель"</string>
     <string name="back_edu_notification_content" msgid="2497557451540954068">"Проведіть трьома пальцями вліво чи вправо. Натисніть, щоб дізнатися про інші жести."</string>
     <string name="home_edu_notification_title" msgid="6097902076909654045">"Щоб перейти на головний екран, використовуйте сенсорну панель"</string>
diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml
index e65fd98..b1ddfc9 100644
--- a/packages/SystemUI/res/values-ur/strings.xml
+++ b/packages/SystemUI/res/values-ur/strings.xml
@@ -440,7 +440,7 @@
     <string name="zen_mode_on" msgid="9085304934016242591">"آن ہے"</string>
     <string name="zen_mode_on_with_details" msgid="7416143430557895497">"آن ہے • <xliff:g id="TRIGGER_DESCRIPTION">%1$s</xliff:g>"</string>
     <string name="zen_mode_off" msgid="1736604456618147306">"آف ہے"</string>
-    <string name="zen_mode_set_up" msgid="7457957033034460064">"سیٹ اپ کریں"</string>
+    <string name="zen_mode_set_up" msgid="8231201163894922821">"سیٹ نہیں ہے"</string>
     <string name="zen_mode_no_manual_invocation" msgid="1769975741344633672">"ترتیبات میں نظم کریں"</string>
     <string name="zen_mode_active_modes" msgid="1625850411578488856">"{count,plural, =0{کوئی فعال موڈ نہیں ہے}=1{{mode} فعال ہے}other{# موڈز فعال ہیں}}"</string>
     <string name="zen_priority_introduction" msgid="3159291973383796646">"الارمز، یاددہانیوں، ایونٹس اور آپ کے متعین کردہ کالرز کے علاوہ، آپ آوازوں اور وائبریشنز سے ڈسٹرب نہیں ہوں گے۔ موسیقی، ویڈیوز اور گیمز سمیت آپ ابھی بھی ہر وہ چیز سنیں گے جسے چلانے کا آپ انتخاب کرتے ہیں۔"</string>
@@ -573,8 +573,7 @@
     <string name="notification_section_header_conversations" msgid="821834744538345661">"گفتگوئیں"</string>
     <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"سبھی خاموش اطلاعات کو صاف کریں"</string>
     <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"\'ڈسٹرب نہ کریں\' کے ذریعے اطلاعات کو موقوف کیا گیا"</string>
-    <!-- no translation found for modes_suppressing_shade_text (6037581130837903239) -->
-    <skip />
+    <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{کوئی اطلاع نہیں ہے}=1{{mode} کی طرف سے اطلاعات کو روک دیا گیا ہے}=2{{mode} اور ایک دوسرے موڈ کے ذریعہ اطلاعات کو روک دیا گیا ہے}other{{mode} اور # دیگر طریقوں کے ذریعے اطلاعات کو روک دیا گیا ہے}}"</string>
     <string name="media_projection_action_text" msgid="3634906766918186440">"ابھی شروع کریں"</string>
     <string name="empty_shade_text" msgid="8935967157319717412">"کوئی اطلاعات نہیں ہیں"</string>
     <string name="no_unseen_notif_text" msgid="395512586119868682">"کوئی نئی اطلاعات نہیں"</string>
@@ -673,6 +672,10 @@
     <string name="stream_notification_unavailable" msgid="4313854556205836435">"دستیاب نہیں ہے کیونکہ رنگ خاموش ہے"</string>
     <string name="stream_alarm_unavailable" msgid="4059817189292197839">"غیر دستیاب ہے کیونکہ ڈسٹرب نہ کریں آن ہے"</string>
     <string name="stream_media_unavailable" msgid="6823020894438959853">"غیر دستیاب ہے کیونکہ ڈسٹرب نہ کریں آن ہے"</string>
+    <!-- no translation found for stream_unavailable_by_modes (3674139029490353683) -->
+    <skip />
+    <!-- no translation found for stream_unavailable_by_unknown (6908434629318171588) -->
+    <skip />
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"‏‎%1$s۔ آواز چالو کرنے کیلئے تھپتھپائیں۔"</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"‏‎%1$s۔ ارتعاش پر سیٹ کرنے کیلئے تھپتھپائیں۔ ایکسیسبیلٹی سروسز شاید خاموش ہوں۔"</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"‏‎%1$s۔ خاموش کرنے کیلئے تھپتھپائیں۔ ایکسیسبیلٹی سروسز شاید خاموش ہوں۔"</string>
@@ -706,6 +709,7 @@
     <string name="show_demo_mode" msgid="3677956462273059726">"ڈیمو موڈ دکھائیں"</string>
     <string name="status_bar_ethernet" msgid="5690979758988647484">"ایتھرنیٹ"</string>
     <string name="status_bar_alarm" msgid="87160847643623352">"الارم"</string>
+    <string name="active_mode_content_description" msgid="1627555562186515927">"<xliff:g id="MODENAME">%1$s</xliff:g> آن ہے"</string>
     <string name="wallet_title" msgid="5369767670735827105">"والٹ"</string>
     <string name="wallet_empty_state_label" msgid="7776761245237530394">"اپنے فون سے تیز تر مزید محفوظ خریداریاں کرنے کے لیے، سیٹ اپ مکمل کریں"</string>
     <string name="wallet_app_button_label" msgid="7123784239111190992">"سبھی دکھائیں"</string>
@@ -1405,26 +1409,26 @@
     <string name="launch_touchpad_tutorial_notification_content" msgid="7931085031240753226">"ٹچ پیڈ کے اشارے کو جانیں"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_title" msgid="1940023776496198762">"اپنے کی بورڈ اور ٹچ پیڈ کا استعمال کر کے نیویگیٹ کریں"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"ٹچ پیڈ کے اشارے، کی بورڈ شارٹ کٹس اور مزید جانیں"</string>
-    <string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"پیچھے جانے کا اشارہ"</string>
-    <string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"ہوم کا اشارہ"</string>
+    <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"واپس جائیں"</string>
+    <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"گھر جائیں"</string>
     <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"حالیہ ایپس دیکھیں"</string>
     <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"ہو گیا"</string>
     <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"واپس جائیں"</string>
-    <string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"‏واپس جانے کے لیے، ٹچ پیڈ پر کہیں بھی تین انگلیوں کی مدد سے دائیں یا بائیں سوائپ کریں۔\n\nآپ اس کیلئے کی بورڈ شارٹ کٹ ایکشن + Esc کا بھی استعمال کر سکتے ہیں۔"</string>
-    <string name="touchpad_back_gesture_success_title" msgid="7240576648330612171">"بہترین!"</string>
+    <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"اپنے ٹچ پیڈ پر تین انگلیوں کا استعمال کرتے ہوئے دائیں یا بائیں طرف سوائپ کریں"</string>
+    <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"عمدہ!"</string>
     <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"آپ نے واپس جائیں اشارے کو مکمل کر لیا۔"</string>
     <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"ہوم پر جائیں"</string>
-    <string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"کسی بھی وقت اپنی ہوم اسکرین پر جانے کے لیے، تین انگلیوں کی مدد سے اپنی اسکرین کے نیچے سے اوپر کی طرف سوائپ کریں۔"</string>
-    <string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"عمدہ!"</string>
-    <string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"آپ نے ہوم پر جانے کا اشارہ مکمل کر لیا۔"</string>
+    <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"اپنے ٹچ پیڈ پر تین انگلیوں کی مدد سے اوپر کی طرف سوائپ کریں"</string>
+    <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"بہترین!"</string>
+    <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"آپ نے ہوم پر جانے کا اشارہ مکمل کر لیا"</string>
     <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"حالیہ ایپس دیکھیں"</string>
-    <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"اپنے ٹچ پیڈ پر تین انگلیوں کا استعمال کرتے ہوئے اوپر کی طرف سوائپ کریں اور دبائے رکھیں۔"</string>
+    <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"اپنے ٹچ پیڈ پر تین انگلیوں کا استعمال کرتے ہوئے اوپر کی طرف سوائپ کریں اور دبائے رکھیں"</string>
     <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"بہترین!"</string>
     <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"آپ نے حالیہ ایپس کا اشارہ مکمل کر لیا ہے۔"</string>
-    <string name="tutorial_action_key_title" msgid="2659466586996495447">"ایکشن کلید"</string>
-    <string name="tutorial_action_key_guidance" msgid="5718948664616999196">"اپنی ایپس تک رسائی حاصل کرنے کے لیے، اپنے کی بورڈ پر ایکشن کلید کو دبائیں۔"</string>
-    <string name="tutorial_action_key_success_title" msgid="466467860120112933">"مبارکباد!"</string>
-    <string name="tutorial_action_key_success_body" msgid="7201991081652850430">"آپ نے ایکشن کلید کا اشارہ مکمل کر لیا۔\n\nایکشن + / دبانے سے آپ کے دستیاب تمام شارٹ کٹس دکھائی دیں گے۔"</string>
+    <string name="tutorial_action_key_title" msgid="8172535792469008169">"سبھی ایپس دیکھیں"</string>
+    <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"اپنے کی بورڈ پر ایکشن کلید دبائیں"</string>
+    <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"بہت خوب!"</string>
+    <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"آپ نے سبھی ایپس کا اشارہ مکمل کر لیا ہے"</string>
     <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"کی بورڈ بیک لائٹ"</string>
     <string name="keyboard_backlight_value" msgid="7336398765584393538">"‏%2$d میں سے ‎%1$d کا لیول"</string>
     <string name="home_controls_dream_label" msgid="6567105701292324257">"ہوم کنٹرولز"</string>
@@ -1436,6 +1440,7 @@
     <string name="all_apps_edu_toast_content" msgid="8807496014667211562">"اپنی سبھی ایپس دیکھنے کے لیے، اپنے کی بورڈ پر ایکشن کلید دبائیں"</string>
     <string name="redacted_notification_single_line_title" msgid="212019960919261670">"چھپانے کیلئے تبدیل کردہ"</string>
     <string name="redacted_notification_single_line_text" msgid="8684166405005242945">"دیکھنے کے لیے غیر مقفل کریں"</string>
+    <string name="contextual_education_dialog_title" msgid="4630392552837487324">"سیاق و سباق کی تعلیم"</string>
     <string name="back_edu_notification_title" msgid="5624780717751357278">"واپس جانے کے لیے اپنے ٹچ پیڈ کا استعمال کریں"</string>
     <string name="back_edu_notification_content" msgid="2497557451540954068">"تین انگلیوں سے دائیں یا بائیں طرف سوائپ کریں۔ مزید اشارے جاننے کے لیے تھپتھپائیں۔"</string>
     <string name="home_edu_notification_title" msgid="6097902076909654045">"ہوم پر جانے کے لیے اپنے ٹچ پیڈ کا استعمال کریں"</string>
@@ -1447,7 +1452,7 @@
     <string name="accessibility_deprecate_extra_dim_dialog_title" msgid="910988771011857460">"اضافی دھندلا اب چمک سلائیڈر کا حصہ ہے"</string>
     <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="4453123359258743230">"آپ چمکیلے پن لیول کو مزید کم کر کے اپنی اسکرین کو اضافی دھندلی بنا سکتے ہیں۔\n\nچونکہ یہ خصوصیت اب چمکیلے پن کے سلائیڈر کا حصہ ہے، اس لیے اضافی دھندلا شارٹ کٹس کو ہٹایا جا رہا ہے۔"</string>
     <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="3947537827396916005">"اضافی دھندلا شارٹ کٹس کو ہٹائیں"</string>
-    <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="165474092660941104">"اضافی دھندلا شارٹ کٹس ہٹا دیے گئے"</string>
+    <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="165474092660941104">"اضافی دھندلے شارٹ کٹس ہٹا دیے گئے"</string>
     <string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"کنیکٹویٹی"</string>
     <string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"ایکسیسبیلٹی"</string>
     <string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"یوٹیلیٹیز"</string>
diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml
index 0f2db37..6d597bd 100644
--- a/packages/SystemUI/res/values-uz/strings.xml
+++ b/packages/SystemUI/res/values-uz/strings.xml
@@ -440,7 +440,7 @@
     <string name="zen_mode_on" msgid="9085304934016242591">"Yoniq"</string>
     <string name="zen_mode_on_with_details" msgid="7416143430557895497">"Yoniq • <xliff:g id="TRIGGER_DESCRIPTION">%1$s</xliff:g>"</string>
     <string name="zen_mode_off" msgid="1736604456618147306">"Yoqilmagan"</string>
-    <string name="zen_mode_set_up" msgid="7457957033034460064">"Sozlash"</string>
+    <string name="zen_mode_set_up" msgid="8231201163894922821">"Sozlanmagan"</string>
     <string name="zen_mode_no_manual_invocation" msgid="1769975741344633672">"Sozlamalarda boshqarish"</string>
     <string name="zen_mode_active_modes" msgid="1625850411578488856">"{count,plural, =0{0 ta rejim faol}=1{{mode} faol}other{# ta rejim faol}}"</string>
     <string name="zen_priority_introduction" msgid="3159291973383796646">"Turli ovoz va tebranishlar endi sizni bezovta qilmaydi. Biroq, signallar, eslatmalar, tadbirlar haqidagi bildirishnomalar va siz tanlagan abonentlardan kelgan chaqiruvlar bundan mustasno. Lekin, ijro etiladigan barcha narsalar, jumladan, musiqa, video va o‘yinlar ovozi eshitiladi."</string>
@@ -573,8 +573,7 @@
     <string name="notification_section_header_conversations" msgid="821834744538345661">"Suhbatlar"</string>
     <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Barcha sokin bildirishnomalarni tozalash"</string>
     <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Bezovta qilinmasin rejimida bildirishnomalar pauza qilinadi"</string>
-    <!-- no translation found for modes_suppressing_shade_text (6037581130837903239) -->
-    <skip />
+    <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{Bildirishnomalar yoʻq}=1{{mode} rejimi bildirishnomalarni pauza qilgan}=2{{mode} va yana bitta boshqa rejim bildirishnomalarni pauza qilgan}other{{mode} va # ta boshqa rejim bildirishnomalarni pauza qilgan}}"</string>
     <string name="media_projection_action_text" msgid="3634906766918186440">"Boshlash"</string>
     <string name="empty_shade_text" msgid="8935967157319717412">"Bildirishnomalar yo‘q"</string>
     <string name="no_unseen_notif_text" msgid="395512586119868682">"Yangi bildirishoma yoʻq"</string>
@@ -673,6 +672,10 @@
     <string name="stream_notification_unavailable" msgid="4313854556205836435">"Jiringlash ovozsizligi uchun ishlamaydi"</string>
     <string name="stream_alarm_unavailable" msgid="4059817189292197839">"Bezovta qilinmasin yoniqligi sababli ishlamaydi"</string>
     <string name="stream_media_unavailable" msgid="6823020894438959853">"Bezovta qilinmasin yoniqligi sababli ishlamaydi"</string>
+    <!-- no translation found for stream_unavailable_by_modes (3674139029490353683) -->
+    <skip />
+    <!-- no translation found for stream_unavailable_by_unknown (6908434629318171588) -->
+    <skip />
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Ovozini yoqish uchun ustiga bosing."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Tebranishni yoqish uchun ustiga bosing. Qulayliklar ishlamasligi mumkin."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Ovozini o‘chirish uchun ustiga bosing. Qulayliklar ishlamasligi mumkin."</string>
@@ -706,6 +709,7 @@
     <string name="show_demo_mode" msgid="3677956462273059726">"Demo rejimni ko‘rsatish"</string>
     <string name="status_bar_ethernet" msgid="5690979758988647484">"Ethernet"</string>
     <string name="status_bar_alarm" msgid="87160847643623352">"Signal"</string>
+    <string name="active_mode_content_description" msgid="1627555562186515927">"<xliff:g id="MODENAME">%1$s</xliff:g> yoniq"</string>
     <string name="wallet_title" msgid="5369767670735827105">"Wallet"</string>
     <string name="wallet_empty_state_label" msgid="7776761245237530394">"Telefonda tezroq va xavfsizroq xarid qilish uchun sozlang"</string>
     <string name="wallet_app_button_label" msgid="7123784239111190992">"Hammasi"</string>
@@ -1405,26 +1409,26 @@
     <string name="launch_touchpad_tutorial_notification_content" msgid="7931085031240753226">"Sensorli panel ishoralari haqida"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_title" msgid="1940023776496198762">"Klaviatura va sensorli panel yordamida kezing"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Sensorli panel ishoralari, tezkor tugmalar va boshqalar haqida"</string>
-    <string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Orqaga qaytish ishorasi"</string>
-    <string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Asosiy ekran ishorasi"</string>
+    <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"Orqaga"</string>
+    <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Boshiga"</string>
     <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Oxirgi ilovalarni koʻrish"</string>
     <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Tayyor"</string>
     <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Orqaga qaytish"</string>
-    <string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"Ortga qaytish uchun sensorli panelda uchta barmoqni chapga yoki oʻngga suring.\n\nBuning uchun Action + ESC tezkor tugmalaridan ham foydalanishingiz mumkin."</string>
-    <string name="touchpad_back_gesture_success_title" msgid="7240576648330612171">"Barakalla!"</string>
+    <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"Sensorli panelda uchta barmoq bilan chapga yoki oʻngga suring"</string>
+    <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"Yaxshi!"</string>
     <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"Ortga qaytish ishorasi darsini tamomladingiz."</string>
     <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"Boshiga"</string>
-    <string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"Istalgan vaqtda bosh ekranga oʻtish uchun ekranning pastidan uchta barmoq bilan tepaga suring."</string>
-    <string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Yaxshi!"</string>
-    <string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Bosh ekranni ochish ishorasi darsini tamomladingiz."</string>
+    <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"Sensorli panelda uchta barmoq bilan tepaga suring"</string>
+    <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"Barakalla!"</string>
+    <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"Bosh ekranni ochish ishorasi darsini tamomladingiz"</string>
     <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"Oxirgi ilovalarni koʻrish"</string>
-    <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"Sensorli panelda uchta barmoq bilan tepaga surib, bosib turing."</string>
+    <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"Sensorli panelda uchta barmoq bilan tepaga surib, bosib turing"</string>
     <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Barakalla!"</string>
     <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Oxirgi ilovalarni koʻrish ishorasini tugalladingiz."</string>
-    <string name="tutorial_action_key_title" msgid="2659466586996495447">"Amal tugmasi"</string>
-    <string name="tutorial_action_key_guidance" msgid="5718948664616999196">"Ilovalarga kirish uchun klaviaturadagi amal tugmasini bosing"</string>
-    <string name="tutorial_action_key_success_title" msgid="466467860120112933">"Tabriklaymiz!"</string>
-    <string name="tutorial_action_key_success_body" msgid="7201991081652850430">"Amal tugmasi ishorasi darsini tamomladingiz.\n\nAmal + / bosilsa, mavjud buyruqlar koʻrsatiladi."</string>
+    <string name="tutorial_action_key_title" msgid="8172535792469008169">"Barcha ilovalarni koʻrish"</string>
+    <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Klaviaturadagi amal tugmasini bosing"</string>
+    <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Barakalla!"</string>
+    <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Hamma ilovalarni koʻrish ishorasini tugalladingiz"</string>
     <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Klaviatura orqa yoritkichi"</string>
     <string name="keyboard_backlight_value" msgid="7336398765584393538">"Daraja: %1$d / %2$d"</string>
     <string name="home_controls_dream_label" msgid="6567105701292324257">"Uy boshqaruvi"</string>
@@ -1436,6 +1440,7 @@
     <string name="all_apps_edu_toast_content" msgid="8807496014667211562">"Barcha ishoralarni koʻrish uchun klaviaturadagi amal tugmasini bosing"</string>
     <string name="redacted_notification_single_line_title" msgid="212019960919261670">"Chiqarildi"</string>
     <string name="redacted_notification_single_line_text" msgid="8684166405005242945">"Koʻrish uchun qulfdan chiqaring"</string>
+    <string name="contextual_education_dialog_title" msgid="4630392552837487324">"Kontekstual taʼlim"</string>
     <string name="back_edu_notification_title" msgid="5624780717751357278">"Sensorli panel orqali orqaga qaytish"</string>
     <string name="back_edu_notification_content" msgid="2497557451540954068">"Uchta barmoq bilan chapga yoki oʻngga suring. Boshqa ishoralar bilan tanishish uchun bosing."</string>
     <string name="home_edu_notification_title" msgid="6097902076909654045">"Sensorli panel orqali bosh ekranga qaytish"</string>
@@ -1446,8 +1451,8 @@
     <string name="all_apps_edu_notification_content" msgid="3255070575694025585">"Amal tugmasini istalganda bosing. Boshqa ishoralar bilan tanishish uchun bosing."</string>
     <string name="accessibility_deprecate_extra_dim_dialog_title" msgid="910988771011857460">"Juda xira endi yorqinlik slayderida joylashgan"</string>
     <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="4453123359258743230">"Endi yorqinlik darajasini yanada pasaytirish orqali ekranni yanada xiralashtirishingiz mumkin.\n\nBu funksiya yorqinlik slayderiga kiritilgani uchun \"juda xira\" buyruqlari olib tashlanmoqda."</string>
-    <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="3947537827396916005">"Juda xira buyruqlarini olib tashlash"</string>
-    <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="165474092660941104">"Juda xira buyruqlari olib tashlandi"</string>
+    <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="3947537827396916005">"“Juda xira” buyruqlarini olib tashlash"</string>
+    <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="165474092660941104">"“Juda xira” buyruqlari olib tashlandi"</string>
     <string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"Aloqa"</string>
     <string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"Qulayliklar"</string>
     <string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"Vositalar"</string>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index a37a7cd..7e1f6e7 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -440,7 +440,7 @@
     <string name="zen_mode_on" msgid="9085304934016242591">"Đang bật"</string>
     <string name="zen_mode_on_with_details" msgid="7416143430557895497">"Bật • <xliff:g id="TRIGGER_DESCRIPTION">%1$s</xliff:g>"</string>
     <string name="zen_mode_off" msgid="1736604456618147306">"Đang tắt"</string>
-    <string name="zen_mode_set_up" msgid="7457957033034460064">"Thiết lập"</string>
+    <string name="zen_mode_set_up" msgid="8231201163894922821">"Chưa đặt"</string>
     <string name="zen_mode_no_manual_invocation" msgid="1769975741344633672">"Quản lý trong phần cài đặt"</string>
     <string name="zen_mode_active_modes" msgid="1625850411578488856">"{count,plural, =0{Không có chế độ nào đang hoạt động}=1{{mode} đang hoạt động}other{# chế độ đang hoạt động}}"</string>
     <string name="zen_priority_introduction" msgid="3159291973383796646">"Bạn sẽ không bị làm phiền bởi âm thanh và tiếng rung, ngoại trừ báo thức, lời nhắc, sự kiện và người gọi mà bạn chỉ định. Bạn sẽ vẫn nghe thấy mọi thứ bạn chọn phát, bao gồm nhạc, video và trò chơi."</string>
@@ -573,8 +573,7 @@
     <string name="notification_section_header_conversations" msgid="821834744538345661">"Cuộc trò chuyện"</string>
     <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Xóa tất cả thông báo im lặng"</string>
     <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Chế độ Không làm phiền đã tạm dừng thông báo"</string>
-    <!-- no translation found for modes_suppressing_shade_text (6037581130837903239) -->
-    <skip />
+    <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{Không có thông báo}=1{{mode} đã tạm dừng thông báo}=2{{mode} và một chế độ khác đã tạm dừng thông báo}other{{mode} và # chế độ khác đã tạm dừng thông báo}}"</string>
     <string name="media_projection_action_text" msgid="3634906766918186440">"Bắt đầu ngay"</string>
     <string name="empty_shade_text" msgid="8935967157319717412">"Không có thông báo nào"</string>
     <string name="no_unseen_notif_text" msgid="395512586119868682">"Không có thông báo mới"</string>
@@ -673,6 +672,10 @@
     <string name="stream_notification_unavailable" msgid="4313854556205836435">"Không hoạt động vì chuông bị tắt"</string>
     <string name="stream_alarm_unavailable" msgid="4059817189292197839">"Bị tắt vì đang bật chế độ Không làm phiền"</string>
     <string name="stream_media_unavailable" msgid="6823020894438959853">"Bị tắt vì đang bật chế độ Không làm phiền"</string>
+    <!-- no translation found for stream_unavailable_by_modes (3674139029490353683) -->
+    <skip />
+    <!-- no translation found for stream_unavailable_by_unknown (6908434629318171588) -->
+    <skip />
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Nhấn để bật tiếng."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Nhấn để đặt chế độ rung. Bạn có thể tắt tiếng dịch vụ trợ năng."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Nhấn để tắt tiếng. Bạn có thể tắt tiếng dịch vụ trợ năng."</string>
@@ -706,6 +709,7 @@
     <string name="show_demo_mode" msgid="3677956462273059726">"Hiển thị chế độ trình diễn"</string>
     <string name="status_bar_ethernet" msgid="5690979758988647484">"Ethernet"</string>
     <string name="status_bar_alarm" msgid="87160847643623352">"Chuông báo"</string>
+    <string name="active_mode_content_description" msgid="1627555562186515927">"<xliff:g id="MODENAME">%1$s</xliff:g> đang bật"</string>
     <string name="wallet_title" msgid="5369767670735827105">"Ví"</string>
     <string name="wallet_empty_state_label" msgid="7776761245237530394">"Thiết lập để mua hàng nhanh hơn và an toàn hơn bằng điện thoại"</string>
     <string name="wallet_app_button_label" msgid="7123784239111190992">"Hiện tất cả"</string>
@@ -1405,26 +1409,26 @@
     <string name="launch_touchpad_tutorial_notification_content" msgid="7931085031240753226">"Tìm hiểu về cử chỉ trên bàn di chuột"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_title" msgid="1940023776496198762">"Di chuyển bằng bàn phím và bàn di chuột"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Tìm hiểu về cử chỉ trên bàn di chuột, phím tắt và nhiều mục khác"</string>
-    <string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Cử chỉ quay lại"</string>
-    <string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Cử chỉ chuyển đến màn hình chính"</string>
+    <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"Quay lại"</string>
+    <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Chuyển đến màn hình chính"</string>
     <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Xem các ứng dụng gần đây"</string>
     <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Xong"</string>
     <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Quay lại"</string>
-    <string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"Để quay lại, hãy dùng 3 ngón tay vuốt sang trái hoặc sang phải ở vị trí bất kỳ trên bàn di chuột.\n\nBạn cũng có thể dùng phím tắt Hành động + ESC cho thao tác này."</string>
-    <string name="touchpad_back_gesture_success_title" msgid="7240576648330612171">"Tuyệt vời!"</string>
+    <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"Dùng 3 ngón tay vuốt sang trái hoặc sang phải trên bàn di chuột"</string>
+    <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"Tuyệt vời!"</string>
     <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"Bạn đã thực hiện xong cử chỉ quay lại."</string>
     <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"Chuyển đến màn hình chính"</string>
-    <string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"Để chuyển đến màn hình chính bất cứ lúc nào, hãy dùng 3 ngón tay vuốt lên từ cuối màn hình lên."</string>
-    <string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Tốt lắm!"</string>
-    <string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Bạn đã thực hiện xong cử chỉ chuyển đến màn hình chính."</string>
+    <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"Dùng 3 ngón tay vuốt lên trên bàn di chuột"</string>
+    <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"Tuyệt vời!"</string>
+    <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"Bạn đã thực hiện xong cử chỉ chuyển đến màn hình chính"</string>
     <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"Xem các ứng dụng gần đây"</string>
-    <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"Dùng 3 ngón tay vuốt lên và giữ trên bàn di chuột."</string>
+    <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"Dùng 3 ngón tay vuốt lên và giữ trên bàn di chuột"</string>
     <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Tuyệt vời!"</string>
     <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Bạn đã hoàn tất cử chỉ xem ứng dụng gần đây."</string>
-    <string name="tutorial_action_key_title" msgid="2659466586996495447">"Phím hành động"</string>
-    <string name="tutorial_action_key_guidance" msgid="5718948664616999196">"Để truy cập vào các ứng dụng của bạn, hãy nhấn phím hành động trên bàn phím."</string>
-    <string name="tutorial_action_key_success_title" msgid="466467860120112933">"Xin chúc mừng!"</string>
-    <string name="tutorial_action_key_success_body" msgid="7201991081652850430">"Bạn đã thực hiện xong cử chỉ nhấn phím hành động.\n\nThao tác + / sẽ hiển thị tất cả phím tắt bạn hiện có."</string>
+    <string name="tutorial_action_key_title" msgid="8172535792469008169">"Xem tất cả các ứng dụng"</string>
+    <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Nhấn phím hành động trên bàn phím"</string>
+    <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Rất tốt!"</string>
+    <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Bạn đã hoàn tất cử chỉ xem tất cả các ứng dụng"</string>
     <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Đèn nền bàn phím"</string>
     <string name="keyboard_backlight_value" msgid="7336398765584393538">"Độ sáng %1$d/%2$d"</string>
     <string name="home_controls_dream_label" msgid="6567105701292324257">"Điều khiển nhà"</string>
@@ -1436,6 +1440,7 @@
     <string name="all_apps_edu_toast_content" msgid="8807496014667211562">"Để xem tất cả ứng dụng của bạn, hãy nhấn phím hành động trên bàn phím"</string>
     <string name="redacted_notification_single_line_title" msgid="212019960919261670">"Bị loại bỏ"</string>
     <string name="redacted_notification_single_line_text" msgid="8684166405005242945">"Mở khoá để xem"</string>
+    <string name="contextual_education_dialog_title" msgid="4630392552837487324">"Hướng dẫn theo bối cảnh"</string>
     <string name="back_edu_notification_title" msgid="5624780717751357278">"Dùng bàn di chuột để quay lại"</string>
     <string name="back_edu_notification_content" msgid="2497557451540954068">"Dùng 3 ngón tay vuốt sang trái hoặc sang phải. Hãy nhấn để tìm hiểu các cử chỉ khác."</string>
     <string name="home_edu_notification_title" msgid="6097902076909654045">"Dùng bàn di chuột để chuyển đến màn hình chính"</string>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index 0d270be..0aa6798 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -440,7 +440,7 @@
     <string name="zen_mode_on" msgid="9085304934016242591">"已开启"</string>
     <string name="zen_mode_on_with_details" msgid="7416143430557895497">"已开启 • <xliff:g id="TRIGGER_DESCRIPTION">%1$s</xliff:g>"</string>
     <string name="zen_mode_off" msgid="1736604456618147306">"已关闭"</string>
-    <string name="zen_mode_set_up" msgid="7457957033034460064">"设置"</string>
+    <string name="zen_mode_set_up" msgid="8231201163894922821">"未设置"</string>
     <string name="zen_mode_no_manual_invocation" msgid="1769975741344633672">"在设置中管理"</string>
     <string name="zen_mode_active_modes" msgid="1625850411578488856">"{count,plural, =0{未启用任何模式}=1{已启用“{mode}”模式}other{已启用 # 个模式}}"</string>
     <string name="zen_priority_introduction" msgid="3159291973383796646">"您将不会受到声音和振动的打扰(闹钟、提醒、活动和所指定来电者的相关提示音除外)。您依然可以听到您选择播放的任何内容(包括音乐、视频和游戏)的相关音效。"</string>
@@ -573,8 +573,7 @@
     <string name="notification_section_header_conversations" msgid="821834744538345661">"对话"</string>
     <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"清除所有静音通知"</string>
     <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"勿扰模式暂停的通知"</string>
-    <!-- no translation found for modes_suppressing_shade_text (6037581130837903239) -->
-    <skip />
+    <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{无通知}=1{{mode}暂停了通知}=2{{mode}和另外 1 种模式暂停了通知}other{{mode}和另外 # 种模式暂停了通知}}"</string>
     <string name="media_projection_action_text" msgid="3634906766918186440">"立即开始"</string>
     <string name="empty_shade_text" msgid="8935967157319717412">"没有通知"</string>
     <string name="no_unseen_notif_text" msgid="395512586119868682">"没有新通知"</string>
@@ -673,6 +672,10 @@
     <string name="stream_notification_unavailable" msgid="4313854556205836435">"该功能无法使用,因为铃声被静音"</string>
     <string name="stream_alarm_unavailable" msgid="4059817189292197839">"“勿扰”模式已开启,因此无法调整音量"</string>
     <string name="stream_media_unavailable" msgid="6823020894438959853">"“勿扰”模式已开启,因此无法调整音量"</string>
+    <!-- no translation found for stream_unavailable_by_modes (3674139029490353683) -->
+    <skip />
+    <!-- no translation found for stream_unavailable_by_unknown (6908434629318171588) -->
+    <skip />
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s。点按即可取消静音。"</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s。点按即可设为振动,但可能会同时将无障碍服务设为静音。"</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s。点按即可设为静音,但可能会同时将无障碍服务设为静音。"</string>
@@ -706,6 +709,7 @@
     <string name="show_demo_mode" msgid="3677956462273059726">"显示演示模式"</string>
     <string name="status_bar_ethernet" msgid="5690979758988647484">"以太网"</string>
     <string name="status_bar_alarm" msgid="87160847643623352">"闹钟"</string>
+    <string name="active_mode_content_description" msgid="1627555562186515927">"“<xliff:g id="MODENAME">%1$s</xliff:g>”处于启用状态"</string>
     <string name="wallet_title" msgid="5369767670735827105">"钱包"</string>
     <string name="wallet_empty_state_label" msgid="7776761245237530394">"开始设置,享受更加快捷安全的手机购物体验"</string>
     <string name="wallet_app_button_label" msgid="7123784239111190992">"全部显示"</string>
@@ -1405,26 +1409,26 @@
     <string name="launch_touchpad_tutorial_notification_content" msgid="7931085031240753226">"了解触控板手势"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_title" msgid="1940023776496198762">"使用键盘和触控板进行导航"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"了解触控板手势、键盘快捷键等"</string>
-    <string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"返回手势"</string>
-    <string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"主屏幕手势"</string>
+    <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"返回"</string>
+    <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"前往主屏幕"</string>
     <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"查看最近用过的应用"</string>
     <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"完成"</string>
     <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"返回"</string>
-    <string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"如要返回,请使用三根手指在触控板上的任意位置左滑或右滑。\n\n您也可以使用键盘快捷操作键 + ESC 键进行返回。"</string>
-    <string name="touchpad_back_gesture_success_title" msgid="7240576648330612171">"太棒了!"</string>
+    <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"在触控板上用三根手指向左或向右滑动"</string>
+    <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"太棒了!"</string>
     <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"您完成了“返回”手势教程。"</string>
     <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"前往主屏幕"</string>
-    <string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"若要随时进入主屏幕,请用三根手指从屏幕的底部向上滑动。"</string>
-    <string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"很好!"</string>
-    <string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"您完成了“前往主屏幕”手势教程。"</string>
+    <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"在触控板上用三根手指向上滑动"</string>
+    <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"太棒了!"</string>
+    <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"您已完成“前往主屏幕”手势"</string>
     <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"查看最近用过的应用"</string>
-    <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"在触控板上用三根手指向上滑动并按住。"</string>
+    <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"在触控板上用三根手指向上滑动并按住"</string>
     <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"太棒了!"</string>
     <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"您已完成“查看最近用过的应用”的手势教程。"</string>
-    <string name="tutorial_action_key_title" msgid="2659466586996495447">"快捷操作按键"</string>
-    <string name="tutorial_action_key_guidance" msgid="5718948664616999196">"如要访问您的应用,请按下键盘上的快捷操作按键。"</string>
-    <string name="tutorial_action_key_success_title" msgid="466467860120112933">"恭喜!"</string>
-    <string name="tutorial_action_key_success_body" msgid="7201991081652850430">"您完成了“快捷操作按键”手势教程。\n\n按下快捷操作按键 + / 可显示所有可用快捷键。"</string>
+    <string name="tutorial_action_key_title" msgid="8172535792469008169">"查看所有应用"</string>
+    <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"按键盘上的快捷操作按键"</string>
+    <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"非常棒!"</string>
+    <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"您已完成“查看所有应用”手势"</string>
     <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"键盘背光"</string>
     <string name="keyboard_backlight_value" msgid="7336398765584393538">"第 %1$d 级,共 %2$d 级"</string>
     <string name="home_controls_dream_label" msgid="6567105701292324257">"家居控制"</string>
@@ -1436,6 +1440,7 @@
     <string name="all_apps_edu_toast_content" msgid="8807496014667211562">"如要查看所有应用,请按下键盘上的快捷操作按键"</string>
     <string name="redacted_notification_single_line_title" msgid="212019960919261670">"已隐去"</string>
     <string name="redacted_notification_single_line_text" msgid="8684166405005242945">"解锁即可查看"</string>
+    <string name="contextual_education_dialog_title" msgid="4630392552837487324">"内容相关指导"</string>
     <string name="back_edu_notification_title" msgid="5624780717751357278">"使用触控板返回"</string>
     <string name="back_edu_notification_content" msgid="2497557451540954068">"用三根手指向左或向右滑动。点按即可了解更多手势。"</string>
     <string name="home_edu_notification_title" msgid="6097902076909654045">"使用触控板前往主屏幕"</string>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index d9a0877..4ff574e 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -440,7 +440,7 @@
     <string name="zen_mode_on" msgid="9085304934016242591">"開啟"</string>
     <string name="zen_mode_on_with_details" msgid="7416143430557895497">"開 • <xliff:g id="TRIGGER_DESCRIPTION">%1$s</xliff:g>"</string>
     <string name="zen_mode_off" msgid="1736604456618147306">"關閉"</string>
-    <string name="zen_mode_set_up" msgid="7457957033034460064">"設定"</string>
+    <string name="zen_mode_set_up" msgid="8231201163894922821">"未設定"</string>
     <string name="zen_mode_no_manual_invocation" msgid="1769975741344633672">"在「設定」中管理"</string>
     <string name="zen_mode_active_modes" msgid="1625850411578488856">"{count,plural, =0{沒有啟用模式}=1{已啟用{mode}}other{已啟用 # 個模式}}"</string>
     <string name="zen_priority_introduction" msgid="3159291973383796646">"你不會受到聲音和震動騷擾 (鬧鐘、提醒、活動和你指定的來電者鈴聲除外)。當你選擇播放音樂、影片和遊戲等,仍可以聽到該內容的聲音。"</string>
@@ -573,8 +573,7 @@
     <string name="notification_section_header_conversations" msgid="821834744538345661">"對話"</string>
     <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"清除所有靜音通知"</string>
     <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"「請勿騷擾」模式已將通知暫停"</string>
-    <!-- no translation found for modes_suppressing_shade_text (6037581130837903239) -->
-    <skip />
+    <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{沒有通知}=1{{mode}已暫停通知}=2{{mode}和另外一個模式已暫停通知}other{{mode}和另外 # 個模式已暫停通知}}"</string>
     <string name="media_projection_action_text" msgid="3634906766918186440">"立即開始"</string>
     <string name="empty_shade_text" msgid="8935967157319717412">"沒有通知"</string>
     <string name="no_unseen_notif_text" msgid="395512586119868682">"沒有新通知"</string>
@@ -673,6 +672,10 @@
     <string name="stream_notification_unavailable" msgid="4313854556205836435">"鈴聲已設定為靜音,因此無法使用"</string>
     <string name="stream_alarm_unavailable" msgid="4059817189292197839">"「請勿騷擾」已開啟,因此無法使用"</string>
     <string name="stream_media_unavailable" msgid="6823020894438959853">"「請勿騷擾」已開啟,因此無法使用"</string>
+    <!-- no translation found for stream_unavailable_by_modes (3674139029490353683) -->
+    <skip />
+    <!-- no translation found for stream_unavailable_by_unknown (6908434629318171588) -->
+    <skip />
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s。輕按即可取消靜音。"</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s。輕按即可設為震動。無障礙功能服務可能已經設為靜音。"</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s。輕按即可設為靜音。無障礙功能服務可能已經設為靜音。"</string>
@@ -706,6 +709,7 @@
     <string name="show_demo_mode" msgid="3677956462273059726">"顯示示範模式"</string>
     <string name="status_bar_ethernet" msgid="5690979758988647484">"以太網"</string>
     <string name="status_bar_alarm" msgid="87160847643623352">"鬧鐘"</string>
+    <string name="active_mode_content_description" msgid="1627555562186515927">"<xliff:g id="MODENAME">%1$s</xliff:g>開咗"</string>
     <string name="wallet_title" msgid="5369767670735827105">"錢包"</string>
     <string name="wallet_empty_state_label" msgid="7776761245237530394">"完成設定後即可透過手機更快速安全地購物"</string>
     <string name="wallet_app_button_label" msgid="7123784239111190992">"顯示全部"</string>
@@ -1405,26 +1409,26 @@
     <string name="launch_touchpad_tutorial_notification_content" msgid="7931085031240753226">"瞭解觸控板手勢"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_title" msgid="1940023776496198762">"使用鍵盤和觸控板導覽"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"瞭解觸控板手勢、鍵盤快速鍵等等"</string>
-    <string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"返去手勢"</string>
-    <string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"主畫面手勢"</string>
+    <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"返回"</string>
+    <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"返回主畫面"</string>
     <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"查看最近使用的應用程式"</string>
     <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"完成"</string>
     <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"返回"</string>
-    <string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"用三隻手指在觸控板上任何一處向左或向右滑動即可返回。\n\n你也可使用鍵盤快速鍵 Action 鍵 + Esc 鍵執行此操作。"</string>
-    <string name="touchpad_back_gesture_success_title" msgid="7240576648330612171">"太好了!"</string>
+    <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"在觸控板上用三隻手指向左或向右滑動"</string>
+    <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"很好!"</string>
     <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"你已完成「返回」手勢的教學課程。"</string>
     <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"返回主畫面"</string>
-    <string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"只要用三隻手指從螢幕底部向上滑動,隨時可以返回主畫面。"</string>
-    <string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"做得好!"</string>
-    <string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"你已完成「返回主畫面」手勢的教學課程。"</string>
+    <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"在觸控板上用三隻手指向上滑動"</string>
+    <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"太好了!"</string>
+    <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"你已完成「返回主畫面」手勢的教學課程"</string>
     <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"查看最近使用的應用程式"</string>
-    <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"用三隻手指在觸控板向上滑動並按住。"</string>
+    <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"在觸控板上用三隻手指向上滑動並按住"</string>
     <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"做得好!"</string>
     <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"你已完成「查看最近使用的應用程式」手勢的教學課程。"</string>
-    <string name="tutorial_action_key_title" msgid="2659466586996495447">"快捷操作鍵"</string>
-    <string name="tutorial_action_key_guidance" msgid="5718948664616999196">"如要存取應用程式,請在鍵盤上按下快捷操作鍵。"</string>
-    <string name="tutorial_action_key_success_title" msgid="466467860120112933">"恭喜!"</string>
-    <string name="tutorial_action_key_success_body" msgid="7201991081652850430">"你已完成「快捷操作鍵」手勢的教學課程。\n\n按下動作 + / 鍵即可顯示所有可使用的快速鍵。"</string>
+    <string name="tutorial_action_key_title" msgid="8172535792469008169">"查看所有應用程式"</string>
+    <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"按下鍵盤上的快捷操作鍵"</string>
+    <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"做得好!"</string>
+    <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"你已完成「查看所有應用程式」手勢的教學課程"</string>
     <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"鍵盤背光"</string>
     <string name="keyboard_backlight_value" msgid="7336398765584393538">"第 %1$d 級,共 %2$d 級"</string>
     <string name="home_controls_dream_label" msgid="6567105701292324257">"智能家居"</string>
@@ -1436,6 +1440,7 @@
     <string name="all_apps_edu_toast_content" msgid="8807496014667211562">"如要查看所有應用程式,請在鍵盤上按下快捷操作鍵"</string>
     <string name="redacted_notification_single_line_title" msgid="212019960919261670">"已剔除"</string>
     <string name="redacted_notification_single_line_text" msgid="8684166405005242945">"解鎖即可查看"</string>
+    <string name="contextual_education_dialog_title" msgid="4630392552837487324">"內容教學"</string>
     <string name="back_edu_notification_title" msgid="5624780717751357278">"使用觸控板返回"</string>
     <string name="back_edu_notification_content" msgid="2497557451540954068">"用三隻手指向左或向右滑動。輕按即可瞭解更多手勢。"</string>
     <string name="home_edu_notification_title" msgid="6097902076909654045">"使用觸控板返回主畫面"</string>
@@ -1445,7 +1450,7 @@
     <string name="all_apps_edu_notification_title" msgid="372262997265569063">"使用鍵盤查看所有應用程式"</string>
     <string name="all_apps_edu_notification_content" msgid="3255070575694025585">"隨時按下快捷操作鍵。輕按即可瞭解更多手勢。"</string>
     <string name="accessibility_deprecate_extra_dim_dialog_title" msgid="910988771011857460">"亮度滑桿現已加入超暗功能"</string>
-    <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="4453123359258743230">"而家只要將亮度校得越低,螢幕就會更加暗。\n\n由於亮度滑桿而家加入咗呢個功能,所以系統將會移除超暗功能捷徑。"</string>
+    <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="4453123359258743230">"現在,只要調校亮度就能將螢幕變得超暗。\n\n由於超暗功能已加到亮度滑桿,其功能捷徑將被移除。"</string>
     <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="3947537827396916005">"移除超暗功能捷徑"</string>
     <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="165474092660941104">"超暗功能捷徑已移除"</string>
     <string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"裝置連接"</string>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index 83b456b..9fea9bc 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -440,7 +440,7 @@
     <string name="zen_mode_on" msgid="9085304934016242591">"開啟"</string>
     <string name="zen_mode_on_with_details" msgid="7416143430557895497">"已開啟 • <xliff:g id="TRIGGER_DESCRIPTION">%1$s</xliff:g>"</string>
     <string name="zen_mode_off" msgid="1736604456618147306">"關閉"</string>
-    <string name="zen_mode_set_up" msgid="7457957033034460064">"設定"</string>
+    <string name="zen_mode_set_up" msgid="8231201163894922821">"未設定"</string>
     <string name="zen_mode_no_manual_invocation" msgid="1769975741344633672">"在「設定」中管理"</string>
     <string name="zen_mode_active_modes" msgid="1625850411578488856">"{count,plural, =0{未啟用任何模式}=1{已啟用 {mode} 個模式}other{已啟用 # 個模式}}"</string>
     <string name="zen_priority_introduction" msgid="3159291973383796646">"裝置不會發出音效或震動造成干擾,但是會保留與鬧鐘、提醒、活動和指定來電者有關的設定。如果你選擇播放音樂、影片和遊戲等內容,還是可以聽見相關音訊。"</string>
@@ -573,8 +573,7 @@
     <string name="notification_section_header_conversations" msgid="821834744538345661">"對話"</string>
     <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"清除所有靜音通知"</string>
     <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"「零打擾」模式已將通知設為暫停"</string>
-    <!-- no translation found for modes_suppressing_shade_text (6037581130837903239) -->
-    <skip />
+    <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{沒有通知}=1{「{mode}」模式已將通知設為暫停}=2{「{mode}」和另一個模式已將通知設為暫停}other{「{mode}」和另外 # 個模式已將通知設為暫停}}"</string>
     <string name="media_projection_action_text" msgid="3634906766918186440">"立即開始"</string>
     <string name="empty_shade_text" msgid="8935967157319717412">"沒有通知"</string>
     <string name="no_unseen_notif_text" msgid="395512586119868682">"沒有新通知"</string>
@@ -673,6 +672,10 @@
     <string name="stream_notification_unavailable" msgid="4313854556205836435">"鈴聲已設為靜音,因此無法使用"</string>
     <string name="stream_alarm_unavailable" msgid="4059817189292197839">"「零打擾」模式已開啟,因此無法調整音量"</string>
     <string name="stream_media_unavailable" msgid="6823020894438959853">"「零打擾」模式已開啟,因此無法調整音量"</string>
+    <!-- no translation found for stream_unavailable_by_modes (3674139029490353683) -->
+    <skip />
+    <!-- no translation found for stream_unavailable_by_unknown (6908434629318171588) -->
+    <skip />
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s。輕觸即可取消靜音。"</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s。輕觸即可設為震動,但系統可能會將無障礙服務一併設為靜音。"</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s。輕觸即可設為靜音,但系統可能會將無障礙服務一併設為靜音。"</string>
@@ -706,6 +709,7 @@
     <string name="show_demo_mode" msgid="3677956462273059726">"顯示展示模式"</string>
     <string name="status_bar_ethernet" msgid="5690979758988647484">"乙太網路"</string>
     <string name="status_bar_alarm" msgid="87160847643623352">"鬧鐘"</string>
+    <string name="active_mode_content_description" msgid="1627555562186515927">"<xliff:g id="MODENAME">%1$s</xliff:g>已開啟"</string>
     <string name="wallet_title" msgid="5369767670735827105">"錢包"</string>
     <string name="wallet_empty_state_label" msgid="7776761245237530394">"完成相關設定之後,就能以更快速安全的方式透過手機消費"</string>
     <string name="wallet_app_button_label" msgid="7123784239111190992">"顯示全部"</string>
@@ -1405,26 +1409,26 @@
     <string name="launch_touchpad_tutorial_notification_content" msgid="7931085031240753226">"學習觸控板手勢"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_title" msgid="1940023776496198762">"使用鍵盤和觸控板操作"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"學習觸控板手勢、鍵盤快速鍵等"</string>
-    <string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"返回手勢"</string>
-    <string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"主畫面手勢"</string>
+    <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"返回"</string>
+    <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"返回主畫面"</string>
     <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"查看最近使用的應用程式"</string>
     <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"完成"</string>
     <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"返回"</string>
-    <string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"如要返回,請在觸控板的任何位置上用三指向左或向右滑動。\n\n使用快捷操作鍵 + ESC 鍵 (鍵盤快速鍵) 也可以返回。"</string>
-    <string name="touchpad_back_gesture_success_title" msgid="7240576648330612171">"太棒了!"</string>
+    <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"在觸控板上用三指向左或向右滑動"</string>
+    <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"很好!"</string>
     <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"你已完成「返回」手勢的教學課程。"</string>
     <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"返回主畫面"</string>
-    <string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"用 3 指從螢幕底部向上滑動,就能隨時返回主畫面。"</string>
-    <string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"太棒了!"</string>
-    <string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"你已完成「返回主畫面」手勢的教學課程。"</string>
+    <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"在觸控板上用三指向上滑動"</string>
+    <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"太棒了!"</string>
+    <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"你已完成「返回主畫面」手勢教學課程"</string>
     <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"查看最近使用的應用程式"</string>
-    <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"在觸控板上用三指向上滑動並按住。"</string>
+    <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"在觸控板上用三指向上滑動並按住"</string>
     <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"太棒了!"</string>
     <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"你已完成「查看最近使用的應用程式」手勢教學課程。"</string>
-    <string name="tutorial_action_key_title" msgid="2659466586996495447">"快捷操作鍵"</string>
-    <string name="tutorial_action_key_guidance" msgid="5718948664616999196">"如要存取應用程式,請按下鍵盤上的快捷操作鍵。"</string>
-    <string name="tutorial_action_key_success_title" msgid="466467860120112933">"恭喜!"</string>
-    <string name="tutorial_action_key_success_body" msgid="7201991081652850430">"你已完成「快捷操作鍵」手勢的教學課程。\n\n按下快捷操作鍵 + / 鍵,就能顯示所有可用的快速鍵。"</string>
+    <string name="tutorial_action_key_title" msgid="8172535792469008169">"查看所有應用程式"</string>
+    <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"按下鍵盤上的快捷操作鍵"</string>
+    <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"非常好!"</string>
+    <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"你已完成「查看所有應用程式」手勢教學課程"</string>
     <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"鍵盤背光"</string>
     <string name="keyboard_backlight_value" msgid="7336398765584393538">"第 %1$d 級,共 %2$d 級"</string>
     <string name="home_controls_dream_label" msgid="6567105701292324257">"居家控制"</string>
@@ -1436,6 +1440,7 @@
     <string name="all_apps_edu_toast_content" msgid="8807496014667211562">"如要查看所有應用程式,請按下鍵盤上的快捷操作鍵"</string>
     <string name="redacted_notification_single_line_title" msgid="212019960919261670">"已遮蓋"</string>
     <string name="redacted_notification_single_line_text" msgid="8684166405005242945">"解鎖即可查看"</string>
+    <string name="contextual_education_dialog_title" msgid="4630392552837487324">"內容教學"</string>
     <string name="back_edu_notification_title" msgid="5624780717751357278">"使用觸控板返回"</string>
     <string name="back_edu_notification_content" msgid="2497557451540954068">"用三指向左或向右滑動。輕觸即可進一步瞭解手勢。"</string>
     <string name="home_edu_notification_title" msgid="6097902076909654045">"使用觸控板前往主畫面"</string>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index 34f3683..9ff3e5d 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -440,7 +440,7 @@
     <string name="zen_mode_on" msgid="9085304934016242591">"Vuliwe"</string>
     <string name="zen_mode_on_with_details" msgid="7416143430557895497">"Vuliwe • <xliff:g id="TRIGGER_DESCRIPTION">%1$s</xliff:g>"</string>
     <string name="zen_mode_off" msgid="1736604456618147306">"Valiwe"</string>
-    <string name="zen_mode_set_up" msgid="7457957033034460064">"Setha"</string>
+    <string name="zen_mode_set_up" msgid="8231201163894922821">"Akusethiwe"</string>
     <string name="zen_mode_no_manual_invocation" msgid="1769975741344633672">"Phatha kumasethingi"</string>
     <string name="zen_mode_active_modes" msgid="1625850411578488856">"{count,plural, =0{Awekho amamodi asebenzayo}=1{I-{mode} iyasebenza}one{Amamodi angu-# ayasebenza}other{Amamodi angu-# ayasebenza}}"</string>
     <string name="zen_priority_introduction" msgid="3159291973383796646">"Ngeke uphazanyiswe imisindo nokudlidliza, ngaphandle kusukela kuma-alamu, izikhumbuzi, imicimbi, nabafonayo obacacisayo. Usazozwa noma yini okhetha ukuyidlala okufaka umculo, amavidiyo, namageyimu."</string>
@@ -573,8 +573,7 @@
     <string name="notification_section_header_conversations" msgid="821834744538345661">"Izingxoxo"</string>
     <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Sula zonke izaziso ezithulile"</string>
     <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Izaziso zimiswe okwesikhashana ukungaphazamisi"</string>
-    <!-- no translation found for modes_suppressing_shade_text (6037581130837903239) -->
-    <skip />
+    <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{Azikho izaziso}=1{Izaziso zimiswe okwesikhashana yi-{mode}}=2{Izaziso zimiswe okwesikhashana yi-{mode} nelinye imodi elilodwa}one{Izaziso zimiswe okwesikhashana yi-{mode} kanye namanye amamodi angu-#}other{Izaziso zimiswe okwesikhashana yi-{mode} kanye namanye amamodi angu-#}}"</string>
     <string name="media_projection_action_text" msgid="3634906766918186440">"Qala manje"</string>
     <string name="empty_shade_text" msgid="8935967157319717412">"Azikho izaziso"</string>
     <string name="no_unseen_notif_text" msgid="395512586119868682">"Azikho izaziso ezintsha"</string>
@@ -673,6 +672,10 @@
     <string name="stream_notification_unavailable" msgid="4313854556205836435">"Ayitholakali ngoba ukukhala kuthulisiwe"</string>
     <string name="stream_alarm_unavailable" msgid="4059817189292197839">"Ayitholakali ngoba okuthi Ungaphazamisi kuvuliwe"</string>
     <string name="stream_media_unavailable" msgid="6823020894438959853">"Ayitholakali ngoba okuthi Ungaphazamisi kuvuliwe"</string>
+    <!-- no translation found for stream_unavailable_by_modes (3674139029490353683) -->
+    <skip />
+    <!-- no translation found for stream_unavailable_by_unknown (6908434629318171588) -->
+    <skip />
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Thepha ukuze ususe ukuthula."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Thepha ukuze usethe ukudlidliza. Amasevisi okufinyelela angathuliswa."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Thepha ukuze uthulise. Amasevisi okufinyelela angathuliswa."</string>
@@ -706,6 +709,7 @@
     <string name="show_demo_mode" msgid="3677956462273059726">"Bonisa imodi yedemo"</string>
     <string name="status_bar_ethernet" msgid="5690979758988647484">"I-Ethernet"</string>
     <string name="status_bar_alarm" msgid="87160847643623352">"I-alamu"</string>
+    <string name="active_mode_content_description" msgid="1627555562186515927">"I-<xliff:g id="MODENAME">%1$s</xliff:g> ivuliwe"</string>
     <string name="wallet_title" msgid="5369767670735827105">"I-wallet"</string>
     <string name="wallet_empty_state_label" msgid="7776761245237530394">"Lungela ukuthenga ngokushesha, ngokuphepha ngefoni yakho"</string>
     <string name="wallet_app_button_label" msgid="7123784239111190992">"Bonisa konke"</string>
@@ -1405,26 +1409,26 @@
     <string name="launch_touchpad_tutorial_notification_content" msgid="7931085031240753226">"Funda ukunyakaza kwephedi lokuthinta"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_title" msgid="1940023776496198762">"Funa usebenzisa ikhibhodi yakho nephedi yokuthinta"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Funda ukunyakaza kwephedi yokuthinta, izinqamuleli zamakhibhodi, nokuningi"</string>
-    <string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Ukunyakazisa umzimba kwangemuva"</string>
-    <string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Ukunyakazisa umzimba kwasekhaya"</string>
+    <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"Iya emuva"</string>
+    <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Iya ekhasini lokuqala"</string>
     <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Buka ama-app akamuva"</string>
     <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Kwenziwe"</string>
     <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Buyela emuva"</string>
-    <string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"Ukuze ubuyele emuva, swayiphela kwesokunxele noma kwesokudla usebenzisa iminwe emithathu noma yikuphi ephedini yokuthinta.\n\nUngasebenzisa nesinqamuleli sekhibhodi Isenzo + ESC kulokhu."</string>
-    <string name="touchpad_back_gesture_success_title" msgid="7240576648330612171">"Umsebenzi omuhle!"</string>
+    <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"Swayiphela kwesokunxele noma kwesokudla usebenzisa iminwe emithathu kuphedi yokuthinta"</string>
+    <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"Kuhle!"</string>
     <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"Ukuqedile ukuthinta kokubuyela emuva."</string>
     <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"Iya ekhasini lokuqala"</string>
-    <string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"Ukuze uye esikrinini sakho sasekhaya nganoma isiphi isikhathi, swayipha uye phezulu ngeminwe emithathu usuka phansi esikrinini sakho."</string>
-    <string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Kuhle!"</string>
-    <string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Ukuqedile ukuthinta kokuya ekhaya."</string>
+    <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"Swayiphela phezulu ngeminwe emithathu ephedini yakho yokuthinta"</string>
+    <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"Umsebenzi omuhle!"</string>
+    <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"Ukuqedile ukunyakaza kokuya ekhaya"</string>
     <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"Buka ama-app akamuva"</string>
-    <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"Swayiphela phezulu bese ubamba usebenzisa iminwe emithathu kuphedi yokuthinta."</string>
+    <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"Swayiphela phezulu bese ubamba usebenzisa iminwe emithathu ephedini yokuthinta."</string>
     <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Umsebenzi omuhle!"</string>
     <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Uqedele ukubuka ukuthinta kwama-app akamuva."</string>
-    <string name="tutorial_action_key_title" msgid="2659466586996495447">"Inkinobho yokufinyelela"</string>
-    <string name="tutorial_action_key_guidance" msgid="5718948664616999196">"Ukuze ufinyelele ama-app wakho, cindezela inkinobho yokufinyelela kukhibhodi yakho."</string>
-    <string name="tutorial_action_key_success_title" msgid="466467860120112933">"Halala!"</string>
-    <string name="tutorial_action_key_success_body" msgid="7201991081652850430">"Uqedele ukuthinta inkinobho yokufinyelela.\n\nIsenzo +/ sibonisa zonke izinqamuleli onazo."</string>
+    <string name="tutorial_action_key_title" msgid="8172535792469008169">"Buka wonke ama-app"</string>
+    <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Cindezela inkinobho yokufinyelela kukhibhodi yakho"</string>
+    <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Wenze kahle!"</string>
+    <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Uqedele ukunyakazisa kokubuka onke ama-app."</string>
     <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Ilambu lekhibhodi"</string>
     <string name="keyboard_backlight_value" msgid="7336398765584393538">"Ileveli %1$d ka-%2$d"</string>
     <string name="home_controls_dream_label" msgid="6567105701292324257">"Izilawuli Zasekhaya"</string>
@@ -1436,6 +1440,7 @@
     <string name="all_apps_edu_toast_content" msgid="8807496014667211562">"Ukuze ubuke wonke ama-app wakho, cindezela inkinobho yokufinyelela kukhibhodi yakho"</string>
     <string name="redacted_notification_single_line_title" msgid="212019960919261670">"Kwenziwe iredact"</string>
     <string name="redacted_notification_single_line_text" msgid="8684166405005242945">"Vula ukuze ubuke"</string>
+    <string name="contextual_education_dialog_title" msgid="4630392552837487324">"Imfundo yokuqukethwe"</string>
     <string name="back_edu_notification_title" msgid="5624780717751357278">"Sebenzisa iphedi yokuthinta ukuze ubuyele emuva"</string>
     <string name="back_edu_notification_content" msgid="2497557451540954068">"Swayiphela kwesokunxele noma kwesokudla usebenzisa iminwe emithathu. Thepha ukuze ufunde kabanzi ngokunyakazisa umzimba."</string>
     <string name="home_edu_notification_title" msgid="6097902076909654045">"Sebenzisa iphedi yokuthinta ukuya ekhaya"</string>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 38ef0e9..6f94f9e 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -73,6 +73,9 @@
     <!-- The number of columns in the infinite grid QuickSettings -->
     <integer name="quick_settings_infinite_grid_num_columns">4</integer>
 
+    <!-- The number of columns in the Dual Shade QuickSettings -->
+    <integer name="quick_settings_dual_shade_num_columns">4</integer>
+
     <!-- Override column number for quick settings.
     For now, this value has effect only when flag lockscreen.enable_landscape is enabled.
     TODO (b/293252410) - change this comment/resource when flag is enabled -->
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 629c94f..6c8a740 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -591,7 +591,7 @@
 
     <dimen name="volume_dialog_panel_width_half">28dp</dimen>
 
-    <dimen name="volume_dialog_slider_width">42dp</dimen>
+    <dimen name="volume_dialog_slider_width_legacy">42dp</dimen>
 
     <dimen name="volume_dialog_slider_corner_radius">21dp</dimen>
 
@@ -622,10 +622,6 @@
 
     <dimen name="volume_tool_tip_arrow_corner_radius">2dp</dimen>
 
-    <!-- Volume panel slices dimensions -->
-    <dimen name="volume_panel_slice_vertical_padding">8dp</dimen>
-    <dimen name="volume_panel_slice_horizontal_padding">24dp</dimen>
-
     <dimen name="bottom_sheet_corner_radius">28dp</dimen>
 
     <!-- Size of each item in the ringer selector drawer. -->
@@ -2048,5 +2044,24 @@
     <dimen name="abc_slice_big_pic_min_height">64dp</dimen>
     <dimen name="abc_slice_big_pic_max_height">64dp</dimen>
 
-    <dimen name="contextual_edu_dialog_bottom_margin">70dp</dimen>
+    <dimen name="contextual_edu_dialog_bottom_margin">80dp</dimen>
+    <dimen name="contextual_edu_dialog_elevation">2dp</dimen>
+
+    <!-- Volume start -->
+    <dimen name="volume_dialog_background_corner_radius">30dp</dimen>
+    <dimen name="volume_dialog_width">60dp</dimen>
+    <dimen name="volume_dialog_vertical_padding">6dp</dimen>
+    <dimen name="volume_dialog_components_spacing">8dp</dimen>
+    <dimen name="volume_dialog_floating_sliders_spacing">8dp</dimen>
+    <dimen name="volume_dialog_floating_sliders_vertical_padding">10dp</dimen>
+    <dimen name="volume_dialog_floating_sliders_horizontal_padding">4dp</dimen>
+    <dimen name="volume_dialog_spacing">4dp</dimen>
+    <dimen name="volume_dialog_button_size">48dp</dimen>
+    <dimen name="volume_dialog_floating_sliders_bottom_padding">48dp</dimen>
+    <dimen name="volume_dialog_slider_width">52dp</dimen>
+    <dimen name="volume_dialog_slider_height">254dp</dimen>
+
+    <dimen name="volume_panel_slice_vertical_padding">8dp</dimen>
+    <dimen name="volume_panel_slice_horizontal_padding">24dp</dimen>
+    <!-- Volume end -->
 </resources>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 96a85d7..2c5fb56 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -765,6 +765,14 @@
     <string name="quick_settings_bluetooth_audio_sharing_button_sharing">Sharing audio</string>
     <!-- QuickSettings: Bluetooth dialog audio sharing button text accessibility label. Used as part of the string "Double tap to enter audio sharing settings". [CHAR LIMIT=50]-->
     <string name="quick_settings_bluetooth_audio_sharing_button_accessibility">enter audio sharing settings</string>
+    <!-- QuickSettings: Bluetooth audio sharing dialog message. [CHAR LIMIT=NONE]-->
+    <string name="quick_settings_bluetooth_audio_sharing_dialog_message">This device\'s music and videos will play on both pairs of headphones</string>
+    <!-- QuickSettings: Bluetooth audio sharing dialog title. [CHAR LIMIT=NONE]-->
+    <string name="quick_settings_bluetooth_audio_sharing_dialog_title">Share your audio</string>
+    <!-- QuickSettings: Bluetooth audio sharing dialog subtitle. [CHAR LIMIT=NONE]-->
+    <string name="quick_settings_bluetooth_audio_sharing_dialog_subtitle"><xliff:g id="available_device_name" example="device 1">%1$s</xliff:g> and <xliff:g id="active_device_name" example="device 2">%2$s</xliff:g></string>
+    <!-- QuickSettings: Bluetooth audio sharing dialog button text. [CHAR LIMIT=NONE]-->
+    <string name="quick_settings_bluetooth_audio_sharing_dialog_switch_to_button">Switch to <xliff:g id="available_device_name" example="device 1">%1$s</xliff:g></string>
 
     <!-- QuickSettings: Bluetooth secondary label for the battery level of a connected device [CHAR LIMIT=20]-->
     <string name="quick_settings_bluetooth_secondary_label_battery_level"><xliff:g id="battery_level_as_percentage">%s</xliff:g> battery</string>
@@ -1746,6 +1754,11 @@
     <!-- A message shown when the media volume changing is disabled because of the don't disturb mode [CHAR_LIMIT=50]-->
     <string name="stream_media_unavailable">Unavailable because Do Not Disturb is on</string>
 
+    <!-- A message shown when a specific volume (e.g. Alarms, Media, etc) is disabled because an active mode is muting that audio stream altogether [CHAR_LIMIT=50]-->
+    <string name="stream_unavailable_by_modes">Unavailable because <xliff:g id="mode" example="Bedtime">%s</xliff:g> is on</string>
+    <!-- A message shown when a specific volume (e.g. Alarms, Media, etc) is disabled but we don't know which mode (or anything else) is responsible. [CHAR_LIMIT=50]-->
+    <string name="stream_unavailable_by_unknown">Unavailable</string>
+
     <!-- Shown in the header of quick settings to indicate to the user that their phone ringer is on vibrate. [CHAR_LIMIT=NONE] -->
     <!-- Shown in the header of quick settings to indicate to the user that their phone ringer is on silent (muted). [CHAR_LIMIT=NONE] -->
 
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 94b0b5f..e1f25f9 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -1721,10 +1721,4 @@
     <style name="ShortcutHelperTheme" parent="@style/ShortcutHelperThemeCommon">
         <item name="android:windowLightNavigationBar">true</item>
     </style>
-
-    <style name="ContextualEduDialog" parent="@android:style/Theme.DeviceDefault.Light.Dialog.NoActionBar">
-        <!-- To make the dialog wrap to content when the education text is short -->
-        <item name="windowMinWidthMajor">0%</item>
-        <item name="windowMinWidthMinor">0%</item>
-    </style>
 </resources>
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 8e01e04..83ab524 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -315,6 +315,7 @@
     };
     private final FaceWakeUpTriggersConfig mFaceWakeUpTriggersConfig;
 
+    private final Object mSimDataLockObject = new Object();
     HashMap<Integer, SimData> mSimDatas = new HashMap<>();
     HashMap<Integer, ServiceState> mServiceStates = new HashMap<>();
 
@@ -610,14 +611,26 @@
 
         // It is possible for active subscriptions to become invalid (-1), and these will not be
         // present in the subscriptionInfo list
-        Iterator<Map.Entry<Integer, SimData>> iter = mSimDatas.entrySet().iterator();
-        while (iter.hasNext()) {
-            Map.Entry<Integer, SimData> simData = iter.next();
-            if (!activeSubIds.contains(simData.getKey())) {
-                mSimLogger.logInvalidSubId(simData.getKey());
-                iter.remove();
+        synchronized (mSimDataLockObject) {
+            Iterator<Map.Entry<Integer, SimData>> iter = mSimDatas.entrySet().iterator();
+            while (iter.hasNext()) {
+                Map.Entry<Integer, SimData> simData = iter.next();
+                if (!activeSubIds.contains(simData.getKey())) {
+                    mSimLogger.logInvalidSubId(simData.getKey());
+                    iter.remove();
 
-                SimData data = simData.getValue();
+                    SimData data = simData.getValue();
+                    for (int j = 0; j < mCallbacks.size(); j++) {
+                        KeyguardUpdateMonitorCallback cb = mCallbacks.get(j).get();
+                        if (cb != null) {
+                            cb.onSimStateChanged(data.subId, data.slotId, data.simState);
+                        }
+                    }
+                }
+            }
+
+            for (int i = 0; i < changedSubscriptions.size(); i++) {
+                SimData data = mSimDatas.get(changedSubscriptions.get(i).getSubscriptionId());
                 for (int j = 0; j < mCallbacks.size(); j++) {
                     KeyguardUpdateMonitorCallback cb = mCallbacks.get(j).get();
                     if (cb != null) {
@@ -625,18 +638,8 @@
                     }
                 }
             }
+            callbacksRefreshCarrierInfo();
         }
-
-        for (int i = 0; i < changedSubscriptions.size(); i++) {
-            SimData data = mSimDatas.get(changedSubscriptions.get(i).getSubscriptionId());
-            for (int j = 0; j < mCallbacks.size(); j++) {
-                KeyguardUpdateMonitorCallback cb = mCallbacks.get(j).get();
-                if (cb != null) {
-                    cb.onSimStateChanged(data.subId, data.slotId, data.simState);
-                }
-            }
-        }
-        callbacksRefreshCarrierInfo();
     }
 
     private void handleAirplaneModeChanged() {
@@ -1872,7 +1875,9 @@
                     if (posture == DEVICE_POSTURE_OPENED) {
                         mLogger.d("Posture changed to open - attempting to request active"
                                 + " unlock and run face auth");
-                        getFaceAuthInteractor().onDeviceUnfolded();
+                        if (getFaceAuthInteractor() != null) {
+                            getFaceAuthInteractor().onDeviceUnfolded();
+                        }
                         requestActiveUnlockFromWakeReason(PowerManager.WAKE_REASON_UNFOLD_DEVICE,
                                 false);
                     }
@@ -3376,12 +3381,15 @@
      * Removes all valid subscription info from the map for the given slotId.
      */
     private void invalidateSlot(int slotId) {
-        Iterator<Map.Entry<Integer, SimData>> iter = mSimDatas.entrySet().iterator();
-        while (iter.hasNext()) {
-            SimData data = iter.next().getValue();
-            if (data.slotId == slotId && SubscriptionManager.isValidSubscriptionId(data.subId)) {
-                mSimLogger.logInvalidSubId(data.subId);
-                iter.remove();
+        synchronized (mSimDataLockObject) {
+            Iterator<Map.Entry<Integer, SimData>> iter = mSimDatas.entrySet().iterator();
+            while (iter.hasNext()) {
+                SimData data = iter.next().getValue();
+                if (data.slotId == slotId
+                        && SubscriptionManager.isValidSubscriptionId(data.subId)) {
+                    mSimLogger.logInvalidSubId(data.subId);
+                    iter.remove();
+                }
             }
         }
     }
@@ -3408,23 +3416,25 @@
         }
 
         // TODO(b/327476182): Preserve SIM_STATE_CARD_IO_ERROR sims in a separate data source.
-        SimData data = mSimDatas.get(subId);
-        final boolean changed;
-        if (data == null) {
-            data = new SimData(state, slotId, subId);
-            mSimDatas.put(subId, data);
-            changed = true; // no data yet; force update
-        } else {
-            changed = (data.simState != state || data.subId != subId || data.slotId != slotId);
-            data.simState = state;
-            data.subId = subId;
-            data.slotId = slotId;
-        }
-        if ((changed || becameAbsent)) {
-            for (int i = 0; i < mCallbacks.size(); i++) {
-                KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
-                if (cb != null) {
-                    cb.onSimStateChanged(subId, slotId, state);
+        synchronized (mSimDataLockObject) {
+            SimData data = mSimDatas.get(subId);
+            final boolean changed;
+            if (data == null) {
+                data = new SimData(state, slotId, subId);
+                mSimDatas.put(subId, data);
+                changed = true; // no data yet; force update
+            } else {
+                changed = (data.simState != state || data.subId != subId || data.slotId != slotId);
+                data.simState = state;
+                data.subId = subId;
+                data.slotId = slotId;
+            }
+            if ((changed || becameAbsent)) {
+                for (int i = 0; i < mCallbacks.size(); i++) {
+                    KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
+                    if (cb != null) {
+                        cb.onSimStateChanged(subId, slotId, state);
+                    }
                 }
             }
         }
@@ -3684,9 +3694,11 @@
         callback.onKeyguardVisibilityChanged(isKeyguardVisible());
         callback.onTelephonyCapable(mTelephonyCapable);
 
-        for (Entry<Integer, SimData> data : mSimDatas.entrySet()) {
-            final SimData state = data.getValue();
-            callback.onSimStateChanged(state.subId, state.slotId, state.simState);
+        synchronized (mSimDataLockObject) {
+            for (Entry<Integer, SimData> data : mSimDatas.entrySet()) {
+                final SimData state = data.getValue();
+                callback.onSimStateChanged(state.subId, state.slotId, state.simState);
+            }
         }
     }
 
@@ -3823,19 +3835,23 @@
     }
 
     public int getSimState(int subId) {
-        if (mSimDatas.containsKey(subId)) {
-            return mSimDatas.get(subId).simState;
-        } else {
-            return TelephonyManager.SIM_STATE_UNKNOWN;
+        synchronized (mSimDataLockObject) {
+            if (mSimDatas.containsKey(subId)) {
+                return mSimDatas.get(subId).simState;
+            } else {
+                return TelephonyManager.SIM_STATE_UNKNOWN;
+            }
         }
     }
 
     private int getSlotId(int subId) {
-        if (!mSimDatas.containsKey(subId)) {
-            refreshSimState(subId, SubscriptionManager.getSlotIndex(subId));
+        synchronized (mSimDataLockObject) {
+            if (!mSimDatas.containsKey(subId)) {
+                refreshSimState(subId, SubscriptionManager.getSlotIndex(subId));
+            }
+            SimData simData = mSimDatas.get(subId);
+            return simData != null ? simData.slotId : SubscriptionManager.INVALID_SUBSCRIPTION_ID;
         }
-        SimData simData = mSimDatas.get(subId);
-        return simData != null ? simData.slotId : SubscriptionManager.INVALID_SUBSCRIPTION_ID;
     }
 
     private final TaskStackChangeListener mTaskStackListener = new TaskStackChangeListener() {
@@ -3876,22 +3892,24 @@
      */
     private boolean refreshSimState(int subId, int slotId) {
         int state = mTelephonyManager.getSimState(slotId);
-        SimData data = mSimDatas.get(subId);
+        synchronized (mSimDataLockObject) {
+            SimData data = mSimDatas.get(subId);
 
-        if (!SubscriptionManager.isValidSubscriptionId(subId)) {
-            invalidateSlot(slotId);
-        }
+            if (!SubscriptionManager.isValidSubscriptionId(subId)) {
+                invalidateSlot(slotId);
+            }
 
-        final boolean changed;
-        if (data == null) {
-            data = new SimData(state, slotId, subId);
-            mSimDatas.put(subId, data);
-            changed = true; // no data yet; force update
-        } else {
-            changed = data.simState != state;
-            data.simState = state;
+            final boolean changed;
+            if (data == null) {
+                data = new SimData(state, slotId, subId);
+                mSimDatas.put(subId, data);
+                changed = true; // no data yet; force update
+            } else {
+                changed = data.simState != state;
+                data.simState = state;
+            }
+            return changed;
         }
-        return changed;
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/keyguard/dagger/ClockRegistryModule.java b/packages/SystemUI/src/com/android/keyguard/dagger/ClockRegistryModule.java
index 831543d..ef172a1 100644
--- a/packages/SystemUI/src/com/android/keyguard/dagger/ClockRegistryModule.java
+++ b/packages/SystemUI/src/com/android/keyguard/dagger/ClockRegistryModule.java
@@ -69,7 +69,9 @@
                         layoutInflater,
                         resources,
                         featureFlags.isEnabled(Flags.STEP_CLOCK_ANIMATION),
-                        MigrateClocksToBlueprint.isEnabled()),
+                        MigrateClocksToBlueprint.isEnabled(),
+                        com.android.systemui.Flags.clockReactiveVariants()
+                ),
                 context.getString(R.string.lockscreen_clock_id_fallback),
                 clockBuffers,
                 /* keepAllLoaded = */ false,
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuController.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuController.java
index 275147e..41b9d33 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuController.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuController.java
@@ -226,7 +226,11 @@
             mBtnTargets =
                     mAccessibilityButtonTargetsObserver.getCurrentAccessibilityButtonTargets();
             mHandler.post(
-                    () -> handleFloatingMenuVisibility(mIsKeyguardVisible, mBtnMode, mBtnTargets));
+                    () -> {
+                        // Force a refresh by destroying the menu if it exists.
+                        destroyFloatingMenu();
+                        handleFloatingMenuVisibility(mIsKeyguardVisible, mBtnMode, mBtnTargets);
+                    });
         }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java b/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java
index e0f73a6..cbdb882 100644
--- a/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java
@@ -319,7 +319,7 @@
             if (item == null && active) {
                 item = new AppOpItem(code, uid, packageName, mClock.elapsedRealtime());
                 if (isOpMicrophone(code)) {
-                    item.setDisabled(isAnyRecordingPausedLocked(uid));
+                    item.setDisabled(isAllRecordingPausedLocked(uid));
                 } else if (isOpCamera(code)) {
                     item.setDisabled(mCameraDisabled);
                 }
@@ -521,18 +521,21 @@
 
     }
 
-    private boolean isAnyRecordingPausedLocked(int uid) {
+    // TODO(b/365843152) remove AudioRecordingConfiguration listening
+    private boolean isAllRecordingPausedLocked(int uid) {
         if (mMicMuted) {
             return true;
         }
         List<AudioRecordingConfiguration> configs = mRecordingsByUid.get(uid);
         if (configs == null) return false;
+        // If we are aware of AudioRecordConfigs, suppress the indicator if all of them are known
+        // to be silenced.
         int configsNum = configs.size();
         for (int i = 0; i < configsNum; i++) {
             AudioRecordingConfiguration config = configs.get(i);
-            if (config.isClientSilenced()) return true;
+            if (!config.isClientSilenced()) return false;
         }
-        return false;
+        return true;
     }
 
     private void updateSensorDisabledStatus() {
@@ -543,7 +546,7 @@
 
                 boolean paused = false;
                 if (isOpMicrophone(item.getCode())) {
-                    paused = isAnyRecordingPausedLocked(item.getUid());
+                    paused = isAllRecordingPausedLocked(item.getUid());
                 } else if (isOpCamera(item.getCode())) {
                     paused = mCameraDisabled;
                 }
diff --git a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/AudioSharingButtonViewModel.kt b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/AudioSharingButtonViewModel.kt
new file mode 100644
index 0000000..a6fb150
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/AudioSharingButtonViewModel.kt
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.bluetooth.qsdialog
+
+import androidx.annotation.StringRes
+import com.android.settingslib.bluetooth.BluetoothUtils
+import com.android.settingslib.bluetooth.LocalBluetoothManager
+import com.android.systemui.lifecycle.ExclusiveActivatable
+import com.android.systemui.res.R
+import dagger.assisted.AssistedFactory
+import dagger.assisted.AssistedInject
+import kotlinx.coroutines.awaitCancellation
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.asStateFlow
+import kotlinx.coroutines.flow.combine
+
+sealed class AudioSharingButtonState {
+    object Gone : AudioSharingButtonState()
+
+    data class Visible(@StringRes val resId: Int, val isActive: Boolean) :
+        AudioSharingButtonState()
+}
+
+class AudioSharingButtonViewModel
+@AssistedInject
+constructor(
+    private val localBluetoothManager: LocalBluetoothManager?,
+    private val audioSharingInteractor: AudioSharingInteractor,
+    private val bluetoothStateInteractor: BluetoothStateInteractor,
+    private val deviceItemInteractor: DeviceItemInteractor,
+) : ExclusiveActivatable() {
+
+    private val mutableButtonState =
+        MutableStateFlow<AudioSharingButtonState>(AudioSharingButtonState.Gone)
+    /** Flow representing the update of AudioSharingButtonState. */
+    val audioSharingButtonStateUpdate: StateFlow<AudioSharingButtonState> =
+        mutableButtonState.asStateFlow()
+
+    override suspend fun onActivated(): Nothing {
+        combine(
+                bluetoothStateInteractor.bluetoothStateUpdate,
+                deviceItemInteractor.deviceItemUpdate,
+                audioSharingInteractor.isAudioSharingOn
+            ) { bluetoothState, deviceItem, audioSharingOn ->
+                getButtonState(bluetoothState, deviceItem, audioSharingOn)
+            }
+            .collect { mutableButtonState.value = it }
+        awaitCancellation()
+    }
+
+    private fun getButtonState(
+        bluetoothState: Boolean,
+        deviceItem: List<DeviceItem>,
+        audioSharingOn: Boolean
+    ): AudioSharingButtonState {
+        return when {
+            // Don't show button when bluetooth is off
+            !bluetoothState -> AudioSharingButtonState.Gone
+            // Show sharing audio when broadcasting
+            audioSharingOn ->
+                AudioSharingButtonState.Visible(
+                    R.string.quick_settings_bluetooth_audio_sharing_button_sharing,
+                    isActive = true
+                )
+            // When not broadcasting, don't show button if there's connected source in any device
+            deviceItem.any {
+                BluetoothUtils.hasConnectedBroadcastSource(
+                    it.cachedBluetoothDevice,
+                    localBluetoothManager
+                )
+            } -> AudioSharingButtonState.Gone
+            // Show audio sharing when there's a connected LE audio device
+            deviceItem.any { BluetoothUtils.isActiveLeAudioDevice(it.cachedBluetoothDevice) } ->
+                AudioSharingButtonState.Visible(
+                    R.string.quick_settings_bluetooth_audio_sharing_button,
+                    isActive = false
+                )
+            else -> AudioSharingButtonState.Gone
+        }
+    }
+
+    @AssistedFactory
+    interface Factory {
+        fun create(): AudioSharingButtonViewModel
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/AudioSharingDeviceItemActionInteractorImpl.kt b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/AudioSharingDeviceItemActionInteractorImpl.kt
new file mode 100644
index 0000000..692a78b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/AudioSharingDeviceItemActionInteractorImpl.kt
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.bluetooth.qsdialog
+
+import android.bluetooth.BluetoothDevice
+import android.content.Intent
+import android.os.Bundle
+import android.provider.Settings
+import com.android.internal.logging.UiEventLogger
+import com.android.settingslib.bluetooth.A2dpProfile
+import com.android.settingslib.bluetooth.BluetoothUtils
+import com.android.settingslib.bluetooth.HeadsetProfile
+import com.android.settingslib.bluetooth.HearingAidProfile
+import com.android.settingslib.bluetooth.LeAudioProfile
+import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcast
+import com.android.settingslib.bluetooth.LocalBluetoothManager
+import com.android.settingslib.flags.Flags.audioSharingQsDialogImprovement
+import com.android.systemui.animation.DialogTransitionAnimator
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.plugins.ActivityStarter
+import com.android.systemui.statusbar.phone.SystemUIDialog
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.withContext
+
+@SysUISingleton
+class AudioSharingDeviceItemActionInteractorImpl
+@Inject
+constructor(
+    private val activityStarter: ActivityStarter,
+    private val audioSharingInteractor: AudioSharingInteractor,
+    private val dialogTransitionAnimator: DialogTransitionAnimator,
+    private val localBluetoothManager: LocalBluetoothManager?,
+    @Main private val mainDispatcher: CoroutineDispatcher,
+    @Background private val backgroundDispatcher: CoroutineDispatcher,
+    private val logger: BluetoothTileDialogLogger,
+    private val uiEventLogger: UiEventLogger,
+    private val delegateFactory: AudioSharingDialogDelegate.Factory,
+    private val deviceItemActionInteractorImpl: DeviceItemActionInteractorImpl,
+) : DeviceItemActionInteractor {
+
+    override suspend fun onClick(deviceItem: DeviceItem, dialog: SystemUIDialog) {
+        withContext(backgroundDispatcher) {
+            if (!audioSharingInteractor.audioSharingAvailable()) {
+                return@withContext deviceItemActionInteractorImpl.onClick(deviceItem, dialog)
+            }
+            val inAudioSharing = BluetoothUtils.isBroadcasting(localBluetoothManager)
+            logger.logDeviceClickInAudioSharingWhenEnabled(inAudioSharing)
+
+            when {
+                deviceItem.type ==
+                    DeviceItemType.AVAILABLE_AUDIO_SHARING_MEDIA_BLUETOOTH_DEVICE -> {
+                    if (audioSharingQsDialogImprovement()) {
+                        withContext(mainDispatcher) {
+                            delegateFactory
+                                .create(deviceItem.cachedBluetoothDevice)
+                                .createDialog()
+                                .let { dialogTransitionAnimator.showFromDialog(it, dialog) }
+                        }
+                    } else {
+                        launchSettings(deviceItem.cachedBluetoothDevice.device, dialog)
+                        logger.logLaunchSettingsCriteriaMatched(
+                            "AvailableAudioSharingDeviceClicked",
+                            deviceItem,
+                        )
+                    }
+                    uiEventLogger.log(
+                        BluetoothTileDialogUiEvent.AVAILABLE_AUDIO_SHARING_DEVICE_CLICKED
+                    )
+                }
+                inSharingAndDeviceNoSource(inAudioSharing, deviceItem) -> {
+                    launchSettings(deviceItem.cachedBluetoothDevice.device, dialog)
+                    logger.logLaunchSettingsCriteriaMatched("InSharingClickedNoSource", deviceItem)
+                    uiEventLogger.log(
+                        if (deviceItem.isLeAudioSupported)
+                            BluetoothTileDialogUiEvent.LAUNCH_SETTINGS_IN_SHARING_LE_DEVICE_CLICKED
+                        else
+                            BluetoothTileDialogUiEvent
+                                .LAUNCH_SETTINGS_IN_SHARING_NON_LE_DEVICE_CLICKED
+                    )
+                }
+                else -> {
+                    deviceItemActionInteractorImpl.onClick(deviceItem, dialog)
+                }
+            }
+        }
+    }
+
+    private fun inSharingAndDeviceNoSource(
+        inAudioSharing: Boolean,
+        deviceItem: DeviceItem,
+    ): Boolean {
+        return inAudioSharing &&
+            deviceItem.isMediaDevice &&
+            !BluetoothUtils.hasConnectedBroadcastSource(
+                deviceItem.cachedBluetoothDevice,
+                localBluetoothManager,
+            )
+    }
+
+    private fun launchSettings(device: BluetoothDevice, dialog: SystemUIDialog) {
+        val intent =
+            Intent(Settings.ACTION_BLUETOOTH_SETTINGS).apply {
+                putExtra(
+                    EXTRA_SHOW_FRAGMENT_ARGUMENTS,
+                    Bundle().apply {
+                        putParcelable(LocalBluetoothLeBroadcast.EXTRA_BLUETOOTH_DEVICE, device)
+                    },
+                )
+            }
+        intent.flags = Intent.FLAG_ACTIVITY_CLEAR_TASK
+        activityStarter.postStartActivityDismissingKeyguard(
+            intent,
+            0,
+            dialogTransitionAnimator.createActivityTransitionController(dialog),
+        )
+    }
+
+    private companion object {
+        const val EXTRA_SHOW_FRAGMENT_ARGUMENTS = ":settings:show_fragment_args"
+
+        val DeviceItem.isLeAudioSupported: Boolean
+            get() =
+                cachedBluetoothDevice.profiles.any { profile ->
+                    profile is LeAudioProfile && profile.isEnabled(cachedBluetoothDevice.device)
+                }
+
+        val DeviceItem.isMediaDevice: Boolean
+            get() =
+                cachedBluetoothDevice.uiAccessibleProfiles.any {
+                    it is A2dpProfile ||
+                        it is HearingAidProfile ||
+                        it is LeAudioProfile ||
+                        it is HeadsetProfile
+                }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/AudioSharingDialogDelegate.kt b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/AudioSharingDialogDelegate.kt
new file mode 100644
index 0000000..3ac942b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/AudioSharingDialogDelegate.kt
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.bluetooth.qsdialog
+
+import android.os.Bundle
+import android.widget.Button
+import android.widget.TextView
+import com.android.internal.logging.UiEventLogger
+import com.android.settingslib.bluetooth.CachedBluetoothDevice
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.res.R
+import com.android.systemui.statusbar.phone.SystemUIDialog
+import dagger.assisted.Assisted
+import dagger.assisted.AssistedFactory
+import dagger.assisted.AssistedInject
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.launch
+
+class AudioSharingDialogDelegate
+@AssistedInject
+constructor(
+    @Assisted private val cachedBluetoothDevice: CachedBluetoothDevice,
+    @Application private val coroutineScope: CoroutineScope,
+    private val viewModelFactory: AudioSharingDialogViewModel.Factory,
+    private val sysuiDialogFactory: SystemUIDialog.Factory,
+    private val uiEventLogger: UiEventLogger,
+) : SystemUIDialog.Delegate {
+
+    override fun createDialog(): SystemUIDialog = sysuiDialogFactory.create(this)
+
+    override fun beforeCreate(dialog: SystemUIDialog, savedInstanceState: Bundle?) {
+        with(dialog.layoutInflater.inflate(R.layout.audio_sharing_dialog, null)) {
+            dialog.setView(this)
+            val subtitleTextView = requireViewById<TextView>(R.id.subtitle)
+            val shareAudioButton = requireViewById<TextView>(R.id.share_audio_button)
+            val switchActiveButton = requireViewById<Button>(R.id.switch_active_button)
+            val job =
+                coroutineScope.launch {
+                    val viewModel = viewModelFactory.create(cachedBluetoothDevice, this)
+                    viewModel.dialogState.collect {
+                        when (it) {
+                            is AudioSharingDialogState.Hide -> dialog.dismiss()
+                            is AudioSharingDialogState.Show -> {
+                                subtitleTextView.text = it.subtitle
+                                switchActiveButton.text = it.switchButtonText
+                                switchActiveButton.setOnClickListener {
+                                    viewModel.switchActiveClicked()
+                                    uiEventLogger.log(
+                                        BluetoothTileDialogUiEvent
+                                            .AUDIO_SHARING_DIALOG_SWITCH_ACTIVE_CLICKED
+                                    )
+                                    dialog.dismiss()
+                                }
+                                shareAudioButton.setOnClickListener {
+                                    viewModel.shareAudioClicked()
+                                    uiEventLogger.log(
+                                        BluetoothTileDialogUiEvent
+                                            .AUDIO_SHARING_DIALOG_SHARE_AUDIO_CLICKED
+                                    )
+                                    dialog.dismiss()
+                                }
+                            }
+                        }
+                    }
+                }
+            SystemUIDialog.registerDismissListener(dialog) { job.cancel() }
+        }
+    }
+
+    @AssistedFactory
+    interface Factory {
+        fun create(cachedBluetoothDevice: CachedBluetoothDevice): AudioSharingDialogDelegate
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/AudioSharingDialogViewModel.kt b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/AudioSharingDialogViewModel.kt
new file mode 100644
index 0000000..dc970aea
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/AudioSharingDialogViewModel.kt
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.bluetooth.qsdialog
+
+import android.content.Context
+import com.android.settingslib.bluetooth.CachedBluetoothDevice
+import com.android.settingslib.bluetooth.LocalBluetoothManager
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.res.R
+import dagger.assisted.Assisted
+import dagger.assisted.AssistedFactory
+import dagger.assisted.AssistedInject
+import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.flowOn
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.onStart
+import kotlinx.coroutines.launch
+
+sealed class AudioSharingDialogState {
+    data object Hide : AudioSharingDialogState()
+
+    data class Show(val subtitle: String, val switchButtonText: String) : AudioSharingDialogState()
+}
+
+class AudioSharingDialogViewModel
+@AssistedInject
+constructor(
+    deviceItemInteractor: DeviceItemInteractor,
+    private val audioSharingInteractor: AudioSharingInteractor,
+    private val context: Context,
+    private val localBluetoothManager: LocalBluetoothManager?,
+    @Assisted private val cachedBluetoothDevice: CachedBluetoothDevice,
+    @Assisted private val coroutineScope: CoroutineScope,
+    @Background private val backgroundDispatcher: CoroutineDispatcher,
+) {
+    val dialogState: Flow<AudioSharingDialogState> =
+        deviceItemInteractor.deviceItemUpdateRequest
+            .map {
+                if (
+                    audioSharingInteractor.isAvailableAudioSharingMediaBluetoothDevice(
+                        cachedBluetoothDevice
+                    )
+                ) {
+                    createShowState(cachedBluetoothDevice)
+                } else {
+                    AudioSharingDialogState.Hide
+                }
+            }
+            .onStart { emit(createShowState(cachedBluetoothDevice)) }
+            .flowOn(backgroundDispatcher)
+            .distinctUntilChanged()
+
+    fun switchActiveClicked() {
+        coroutineScope.launch { audioSharingInteractor.switchActive(cachedBluetoothDevice) }
+    }
+
+    fun shareAudioClicked() {
+        coroutineScope.launch { audioSharingInteractor.startAudioSharing() }
+    }
+
+    private fun createShowState(
+        cachedBluetoothDevice: CachedBluetoothDevice
+    ): AudioSharingDialogState {
+        val activeDeviceName =
+            localBluetoothManager
+                ?.profileManager
+                ?.leAudioProfile
+                ?.activeDevices
+                ?.firstOrNull()
+                ?.let { localBluetoothManager.cachedDeviceManager?.findDevice(it)?.name } ?: ""
+        val availableDeviceName = cachedBluetoothDevice.name
+        return AudioSharingDialogState.Show(
+            context.getString(
+                R.string.quick_settings_bluetooth_audio_sharing_dialog_subtitle,
+                availableDeviceName,
+                activeDeviceName
+            ),
+            context.getString(
+                R.string.quick_settings_bluetooth_audio_sharing_dialog_switch_to_button,
+                availableDeviceName
+            )
+        )
+    }
+
+    @AssistedFactory
+    interface Factory {
+        fun create(
+            cachedBluetoothDevice: CachedBluetoothDevice,
+            coroutineScope: CoroutineScope
+        ): AudioSharingDialogViewModel
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/AudioSharingInteractor.kt b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/AudioSharingInteractor.kt
index 817f2d7..65f1105 100644
--- a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/AudioSharingInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/AudioSharingInteractor.kt
@@ -16,82 +16,148 @@
 
 package com.android.systemui.bluetooth.qsdialog
 
-import androidx.annotation.StringRes
 import com.android.settingslib.bluetooth.BluetoothUtils
+import com.android.settingslib.bluetooth.CachedBluetoothDevice
 import com.android.settingslib.bluetooth.LocalBluetoothManager
+import com.android.settingslib.bluetooth.onPlaybackStarted
 import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.dagger.qualifiers.Background
-import com.android.systemui.res.R
 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.combine
+import kotlinx.coroutines.flow.emptyFlow
+import kotlinx.coroutines.flow.firstOrNull
+import kotlinx.coroutines.flow.flatMapLatest
+import kotlinx.coroutines.flow.flow
+import kotlinx.coroutines.flow.flowOf
 import kotlinx.coroutines.flow.flowOn
-import kotlinx.coroutines.flow.stateIn
-
-internal sealed class AudioSharingButtonState {
-    object Gone : AudioSharingButtonState()
-
-    data class Visible(@StringRes val resId: Int, val isActive: Boolean) :
-        AudioSharingButtonState()
-}
+import kotlinx.coroutines.flow.mapNotNull
+import kotlinx.coroutines.withContext
 
 /** Holds business logic for the audio sharing state. */
+interface AudioSharingInteractor {
+    val isAudioSharingOn: Flow<Boolean>
+
+    val audioSourceStateUpdate: Flow<Unit>
+
+    suspend fun handleAudioSourceWhenReady()
+
+    suspend fun isAvailableAudioSharingMediaBluetoothDevice(
+        cachedBluetoothDevice: CachedBluetoothDevice
+    ): Boolean
+
+    suspend fun switchActive(cachedBluetoothDevice: CachedBluetoothDevice)
+
+    suspend fun startAudioSharing()
+
+    suspend fun audioSharingAvailable(): Boolean
+}
+
 @SysUISingleton
-internal class AudioSharingInteractor
+@OptIn(ExperimentalCoroutinesApi::class)
+class AudioSharingInteractorImpl
 @Inject
 constructor(
     private val localBluetoothManager: LocalBluetoothManager?,
-    bluetoothStateInteractor: BluetoothStateInteractor,
-    deviceItemInteractor: DeviceItemInteractor,
-    @Application private val coroutineScope: CoroutineScope,
+    private val audioSharingRepository: AudioSharingRepository,
     @Background private val backgroundDispatcher: CoroutineDispatcher,
-) {
-    /** Flow representing the update of AudioSharingButtonState. */
-    internal val audioSharingButtonStateUpdate: Flow<AudioSharingButtonState> =
-        combine(
-                bluetoothStateInteractor.bluetoothStateUpdate,
-                deviceItemInteractor.deviceItemUpdate
-            ) { bluetoothState, deviceItem ->
-                getButtonState(bluetoothState, deviceItem)
+) : AudioSharingInteractor {
+
+    override val isAudioSharingOn: Flow<Boolean> =
+        flow { emit(audioSharingAvailable()) }
+            .flatMapLatest { isEnabled ->
+                if (isEnabled) {
+                    audioSharingRepository.inAudioSharing
+                } else {
+                    flowOf(false)
+                }
             }
             .flowOn(backgroundDispatcher)
-            .stateIn(
-                coroutineScope,
-                SharingStarted.WhileSubscribed(replayExpirationMillis = 0),
-                initialValue = AudioSharingButtonState.Gone
-            )
 
-    private fun getButtonState(
-        bluetoothState: Boolean,
-        deviceItem: List<DeviceItem>
-    ): AudioSharingButtonState {
-        return when {
-            // Don't show button when bluetooth is off
-            !bluetoothState -> AudioSharingButtonState.Gone
-            // Show sharing audio when broadcasting
-            BluetoothUtils.isBroadcasting(localBluetoothManager) ->
-                AudioSharingButtonState.Visible(
-                    R.string.quick_settings_bluetooth_audio_sharing_button_sharing,
-                    isActive = true
-                )
-            // When not broadcasting, don't show button if there's connected source in any device
-            deviceItem.any {
-                BluetoothUtils.hasConnectedBroadcastSource(
-                    it.cachedBluetoothDevice,
-                    localBluetoothManager
-                )
-            } -> AudioSharingButtonState.Gone
-            // Show audio sharing when there's a connected LE audio device
-            deviceItem.any { BluetoothUtils.isActiveLeAudioDevice(it.cachedBluetoothDevice) } ->
-                AudioSharingButtonState.Visible(
-                    R.string.quick_settings_bluetooth_audio_sharing_button,
-                    isActive = false
-                )
-            else -> AudioSharingButtonState.Gone
+    override val audioSourceStateUpdate =
+        isAudioSharingOn
+            .flatMapLatest {
+                if (it) {
+                    audioSharingRepository.audioSourceStateUpdate
+                } else {
+                    emptyFlow()
+                }
+            }
+            .flowOn(backgroundDispatcher)
+
+    override suspend fun handleAudioSourceWhenReady() {
+        withContext(backgroundDispatcher) {
+            if (audioSharingAvailable()) {
+                audioSharingRepository.leAudioBroadcastProfile?.let { profile ->
+                    isAudioSharingOn
+                        .mapNotNull { audioSharingOn ->
+                            if (audioSharingOn) {
+                                // onPlaybackStarted could emit multiple times during one
+                                // audio sharing session, we only perform add source on the
+                                // first time
+                                profile.onPlaybackStarted.firstOrNull()
+                            } else {
+                                null
+                            }
+                        }
+                        .flowOn(backgroundDispatcher)
+                        .collect { audioSharingRepository.addSource() }
+                }
+            }
         }
     }
+
+    override suspend fun isAvailableAudioSharingMediaBluetoothDevice(
+        cachedBluetoothDevice: CachedBluetoothDevice
+    ): Boolean {
+        return withContext(backgroundDispatcher) {
+            if (audioSharingAvailable()) {
+                BluetoothUtils.isAvailableAudioSharingMediaBluetoothDevice(
+                    cachedBluetoothDevice,
+                    localBluetoothManager,
+                )
+            } else {
+                false
+            }
+        }
+    }
+
+    override suspend fun switchActive(cachedBluetoothDevice: CachedBluetoothDevice) {
+        if (!audioSharingAvailable()) {
+            return
+        }
+        audioSharingRepository.setActive(cachedBluetoothDevice)
+    }
+
+    override suspend fun startAudioSharing() {
+        if (!audioSharingAvailable()) {
+            return
+        }
+        audioSharingRepository.startAudioSharing()
+    }
+
+    // TODO(b/367965193): Move this after flags rollout
+    override suspend fun audioSharingAvailable(): Boolean {
+        return audioSharingRepository.audioSharingAvailable()
+    }
+}
+
+@SysUISingleton
+class AudioSharingInteractorEmptyImpl @Inject constructor() : AudioSharingInteractor {
+    override val isAudioSharingOn: Flow<Boolean> = flowOf(false)
+
+    override val audioSourceStateUpdate: Flow<Unit> = emptyFlow()
+
+    override suspend fun handleAudioSourceWhenReady() {}
+
+    override suspend fun isAvailableAudioSharingMediaBluetoothDevice(
+        cachedBluetoothDevice: CachedBluetoothDevice
+    ) = false
+
+    override suspend fun switchActive(cachedBluetoothDevice: CachedBluetoothDevice) {}
+
+    override suspend fun startAudioSharing() {}
+
+    override suspend fun audioSharingAvailable(): Boolean = false
 }
diff --git a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/AudioSharingRepository.kt b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/AudioSharingRepository.kt
new file mode 100644
index 0000000..b9b8d36
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/AudioSharingRepository.kt
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.bluetooth.qsdialog
+
+import com.android.settingslib.bluetooth.CachedBluetoothDevice
+import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcast
+import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastAssistant
+import com.android.settingslib.bluetooth.LocalBluetoothManager
+import com.android.settingslib.bluetooth.onSourceConnectedOrRemoved
+import com.android.settingslib.volume.data.repository.AudioSharingRepository as SettingsLibAudioSharingRepository
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Background
+import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.emptyFlow
+import kotlinx.coroutines.withContext
+
+interface AudioSharingRepository {
+    val leAudioBroadcastProfile: LocalBluetoothLeBroadcast?
+
+    val audioSourceStateUpdate: Flow<Unit>
+
+    val inAudioSharing: StateFlow<Boolean>
+
+    suspend fun audioSharingAvailable(): Boolean
+
+    suspend fun addSource()
+
+    suspend fun setActive(cachedBluetoothDevice: CachedBluetoothDevice)
+
+    suspend fun startAudioSharing()
+}
+
+@SysUISingleton
+class AudioSharingRepositoryImpl(
+    private val localBluetoothManager: LocalBluetoothManager,
+    private val settingsLibAudioSharingRepository: SettingsLibAudioSharingRepository,
+    @Background private val backgroundDispatcher: CoroutineDispatcher,
+) : AudioSharingRepository {
+
+    override val leAudioBroadcastProfile: LocalBluetoothLeBroadcast?
+        get() = localBluetoothManager.profileManager?.leAudioBroadcastProfile
+
+    private val leAudioBroadcastAssistantProfile: LocalBluetoothLeBroadcastAssistant?
+        get() = localBluetoothManager.profileManager?.leAudioBroadcastAssistantProfile
+
+    override val audioSourceStateUpdate: Flow<Unit> =
+        leAudioBroadcastAssistantProfile?.onSourceConnectedOrRemoved ?: emptyFlow()
+
+    override val inAudioSharing: StateFlow<Boolean> =
+        settingsLibAudioSharingRepository.inAudioSharing
+
+    override suspend fun audioSharingAvailable(): Boolean {
+        return settingsLibAudioSharingRepository.audioSharingAvailable()
+    }
+
+    override suspend fun addSource() {
+        withContext(backgroundDispatcher) {
+            if (!settingsLibAudioSharingRepository.audioSharingAvailable()) {
+                return@withContext
+            }
+            leAudioBroadcastProfile?.latestBluetoothLeBroadcastMetadata?.let { metadata ->
+                leAudioBroadcastAssistantProfile?.let {
+                    it.allConnectedDevices.forEach { sink -> it.addSource(sink, metadata, false) }
+                }
+            }
+        }
+    }
+
+    override suspend fun setActive(cachedBluetoothDevice: CachedBluetoothDevice) {
+        withContext(backgroundDispatcher) {
+            if (!settingsLibAudioSharingRepository.audioSharingAvailable()) {
+                return@withContext
+            }
+            cachedBluetoothDevice.setActive()
+        }
+    }
+
+    override suspend fun startAudioSharing() {
+        withContext(backgroundDispatcher) {
+            if (!settingsLibAudioSharingRepository.audioSharingAvailable()) {
+                return@withContext
+            }
+            leAudioBroadcastProfile?.startPrivateBroadcast()
+        }
+    }
+}
+
+@SysUISingleton
+class AudioSharingRepositoryEmptyImpl : AudioSharingRepository {
+    override val leAudioBroadcastProfile: LocalBluetoothLeBroadcast? = null
+
+    override val audioSourceStateUpdate: Flow<Unit> = emptyFlow()
+
+    override val inAudioSharing: StateFlow<Boolean> = MutableStateFlow(false)
+
+    override suspend fun audioSharingAvailable(): Boolean = false
+
+    override suspend fun addSource() {}
+
+    override suspend fun setActive(cachedBluetoothDevice: CachedBluetoothDevice) {}
+
+    override suspend fun startAudioSharing() {}
+}
diff --git a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothStateInteractor.kt b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothStateInteractor.kt
index 17f9e63..55d4d3e 100644
--- a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothStateInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothStateInteractor.kt
@@ -39,7 +39,7 @@
 
 /** Holds business logic for the Bluetooth Dialog's bluetooth and device connection state */
 @SysUISingleton
-internal class BluetoothStateInteractor
+class BluetoothStateInteractor
 @Inject
 constructor(
     private val localBluetoothManager: LocalBluetoothManager?,
diff --git a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogDelegate.kt b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogDelegate.kt
index 7deea73..a9c5c69 100644
--- a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogDelegate.kt
+++ b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogDelegate.kt
@@ -300,7 +300,7 @@
     }
 
     private fun getProgressBarBackground(dialog: SystemUIDialog): View {
-        return dialog.requireViewById(R.id.bluetooth_tile_dialog_progress_animation)
+        return dialog.requireViewById(R.id.bluetooth_tile_dialog_progress_background)
     }
 
     private fun getScrollViewContent(dialog: SystemUIDialog): View {
diff --git a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogUiEvent.kt b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogUiEvent.kt
index bdd4c16..aad233f 100644
--- a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogUiEvent.kt
+++ b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogUiEvent.kt
@@ -42,6 +42,7 @@
     LAUNCH_SETTINGS_IN_SHARING_LE_DEVICE_CLICKED(1717),
     @UiEvent(doc = "Currently broadcasting and a non-LE audio supported device is clicked")
     LAUNCH_SETTINGS_IN_SHARING_NON_LE_DEVICE_CLICKED(1718),
+    @Deprecated("Use case no longer needed")
     @UiEvent(
         doc = "Not broadcasting, having one connected, another saved LE audio device is clicked"
     )
@@ -52,8 +53,13 @@
     )
     @UiEvent(doc = "Not broadcasting, one of the two connected LE audio devices is clicked")
     LAUNCH_SETTINGS_NOT_SHARING_CONNECTED_LE_DEVICE_CLICKED(1720),
+    @Deprecated("Use case no longer needed")
     @UiEvent(doc = "Not broadcasting, having two connected, the active LE audio devices is clicked")
-    LAUNCH_SETTINGS_NOT_SHARING_ACTIVE_LE_DEVICE_CLICKED(1881);
+    LAUNCH_SETTINGS_NOT_SHARING_ACTIVE_LE_DEVICE_CLICKED(1881),
+    @UiEvent(doc = "Clicked on switch active button on audio sharing dialog")
+    AUDIO_SHARING_DIALOG_SWITCH_ACTIVE_CLICKED(1890),
+    @UiEvent(doc = "Clicked on share audio button on audio sharing dialog")
+    AUDIO_SHARING_DIALOG_SHARE_AUDIO_CLICKED(1891);
 
     override fun getId() = metricId
 }
diff --git a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogViewModel.kt b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogViewModel.kt
index a8f7fc3..5c35c52 100644
--- a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogViewModel.kt
@@ -28,8 +28,8 @@
 import androidx.annotation.VisibleForTesting
 import com.android.internal.jank.InteractionJankMonitor
 import com.android.internal.logging.UiEventLogger
-import com.android.settingslib.bluetooth.BluetoothUtils
 import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcast
+import com.android.settingslib.flags.Flags.audioSharingQsDialogImprovement
 import com.android.systemui.Prefs
 import com.android.systemui.animation.DialogCuj
 import com.android.systemui.animation.DialogTransitionAnimator
@@ -51,6 +51,7 @@
 import kotlinx.coroutines.channels.awaitClose
 import kotlinx.coroutines.channels.produce
 import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.emptyFlow
 import kotlinx.coroutines.flow.filterNotNull
 import kotlinx.coroutines.flow.launchIn
 import kotlinx.coroutines.flow.merge
@@ -68,10 +69,12 @@
     private val bluetoothStateInteractor: BluetoothStateInteractor,
     private val bluetoothAutoOnInteractor: BluetoothAutoOnInteractor,
     private val audioSharingInteractor: AudioSharingInteractor,
+    private val audioSharingButtonViewModelFactory: AudioSharingButtonViewModel.Factory,
     private val bluetoothDeviceMetadataInteractor: BluetoothDeviceMetadataInteractor,
     private val dialogTransitionAnimator: DialogTransitionAnimator,
     private val activityStarter: ActivityStarter,
     private val uiEventLogger: UiEventLogger,
+    private val logger: BluetoothTileDialogLogger,
     @Application private val coroutineScope: CoroutineScope,
     @Main private val mainDispatcher: CoroutineDispatcher,
     @Background private val backgroundDispatcher: CoroutineDispatcher,
@@ -102,7 +105,7 @@
                     expandable?.dialogTransitionController(
                         DialogCuj(
                             InteractionJankMonitor.CUJ_SHADE_DIALOG_OPEN,
-                            INTERACTION_JANK_TAG
+                            INTERACTION_JANK_TAG,
                         )
                     )
                 controller?.let {
@@ -117,7 +120,7 @@
                 // stop the progress bar.
                 combine(
                         deviceItemInteractor.deviceItemUpdate,
-                        deviceItemInteractor.showSeeAllUpdate
+                        deviceItemInteractor.showSeeAllUpdate,
                     ) { deviceItem, showSeeAll ->
                         updateDialogUiJob?.cancel()
                         updateDialogUiJob = launch {
@@ -127,7 +130,7 @@
                                     deviceItem,
                                     showSeeAll,
                                     showPairNewDevice =
-                                        bluetoothStateInteractor.isBluetoothEnabled()
+                                        bluetoothStateInteractor.isBluetoothEnabled(),
                                 )
                                 animateProgressBar(dialog, false)
                             }
@@ -139,7 +142,15 @@
                 // the device item list and animate the progress bar.
                 merge(
                         deviceItemInteractor.deviceItemUpdateRequest,
-                        bluetoothDeviceMetadataInteractor.metadataUpdate
+                        bluetoothDeviceMetadataInteractor.metadataUpdate,
+                        if (
+                            audioSharingInteractor.audioSharingAvailable() &&
+                                audioSharingQsDialogImprovement()
+                        ) {
+                            audioSharingInteractor.audioSourceStateUpdate
+                        } else {
+                            emptyFlow()
+                        },
                     )
                     .onEach {
                         dialogDelegate.animateProgressBar(dialog, true)
@@ -147,35 +158,42 @@
                         updateDeviceItemJob = launch {
                             deviceItemInteractor.updateDeviceItems(
                                 context,
-                                DeviceFetchTrigger.BLUETOOTH_CALLBACK_RECEIVED
+                                DeviceFetchTrigger.BLUETOOTH_CALLBACK_RECEIVED,
                             )
                         }
                     }
                     .launchIn(this)
 
-                if (BluetoothUtils.isAudioSharingEnabled()) {
-                    audioSharingInteractor.audioSharingButtonStateUpdate
-                        .onEach {
-                            when (it) {
-                                is AudioSharingButtonState.Visible -> {
-                                    dialogDelegate.onAudioSharingButtonUpdated(
-                                        dialog,
-                                        VISIBLE,
-                                        context.getString(it.resId),
-                                        it.isActive
-                                    )
-                                }
-                                is AudioSharingButtonState.Gone -> {
-                                    dialogDelegate.onAudioSharingButtonUpdated(
-                                        dialog,
-                                        GONE,
-                                        label = null,
-                                        isActive = false
-                                    )
+                if (audioSharingInteractor.audioSharingAvailable()) {
+                    if (audioSharingQsDialogImprovement()) {
+                        launch { audioSharingInteractor.handleAudioSourceWhenReady() }
+                    }
+
+                    audioSharingButtonViewModelFactory.create().run {
+                        audioSharingButtonStateUpdate
+                            .onEach {
+                                when (it) {
+                                    is AudioSharingButtonState.Visible -> {
+                                        dialogDelegate.onAudioSharingButtonUpdated(
+                                            dialog,
+                                            VISIBLE,
+                                            context.getString(it.resId),
+                                            it.isActive,
+                                        )
+                                    }
+                                    is AudioSharingButtonState.Gone -> {
+                                        dialogDelegate.onAudioSharingButtonUpdated(
+                                            dialog,
+                                            GONE,
+                                            label = null,
+                                            isActive = false,
+                                        )
+                                    }
                                 }
                             }
-                        }
-                        .launchIn(this)
+                            .launchIn(this@launch)
+                        launch { activate() }
+                    }
                 }
 
                 // bluetoothStateUpdate is emitted when bluetooth on/off state is changed, re-fetch
@@ -185,13 +203,13 @@
                         dialogDelegate.onBluetoothStateUpdated(
                             dialog,
                             it,
-                            UiProperties.build(it, isAutoOnToggleFeatureAvailable())
+                            UiProperties.build(it, isAutoOnToggleFeatureAvailable()),
                         )
                         updateDeviceItemJob?.cancel()
                         updateDeviceItemJob = launch {
                             deviceItemInteractor.updateDeviceItems(
                                 context,
-                                DeviceFetchTrigger.BLUETOOTH_STATE_CHANGE_RECEIVED
+                                DeviceFetchTrigger.BLUETOOTH_STATE_CHANGE_RECEIVED,
                             )
                         }
                     }
@@ -209,7 +227,10 @@
 
                 // deviceItemClick is emitted when user clicked on a device item.
                 dialogDelegate.deviceItemClick
-                    .onEach { deviceItemActionInteractor.onClick(it, dialog) }
+                    .onEach {
+                        deviceItemActionInteractor.onClick(it, dialog)
+                        logger.logDeviceClick(it.cachedBluetoothDevice.address, it.type)
+                    }
                     .launchIn(this)
 
                 // contentHeight is emitted when the dialog is dismissed.
@@ -230,7 +251,7 @@
                                 dialog,
                                 it,
                                 if (it) R.string.turn_on_bluetooth_auto_info_enabled
-                                else R.string.turn_on_bluetooth_auto_info_disabled
+                                else R.string.turn_on_bluetooth_auto_info_disabled,
                             )
                         }
                         .launchIn(this)
@@ -252,18 +273,18 @@
             withContext(backgroundDispatcher) {
                 sharedPreferences.getInt(
                     CONTENT_HEIGHT_PREF_KEY,
-                    ViewGroup.LayoutParams.WRAP_CONTENT
+                    ViewGroup.LayoutParams.WRAP_CONTENT,
                 )
             }
 
         return bluetoothDialogDelegateFactory.create(
             UiProperties.build(
                 bluetoothStateInteractor.isBluetoothEnabled(),
-                isAutoOnToggleFeatureAvailable()
+                isAutoOnToggleFeatureAvailable(),
             ),
             cachedContentHeight,
             this@BluetoothTileDialogViewModel,
-            { cancelJob() }
+            { cancelJob() },
         )
     }
 
@@ -275,7 +296,7 @@
                     EXTRA_SHOW_FRAGMENT_ARGUMENTS,
                     Bundle().apply {
                         putString("device_address", deviceItem.cachedBluetoothDevice.address)
-                    }
+                    },
                 )
             }
         startSettingsActivity(intent, view)
@@ -299,7 +320,7 @@
                     EXTRA_SHOW_FRAGMENT_ARGUMENTS,
                     Bundle().apply {
                         putBoolean(LocalBluetoothLeBroadcast.EXTRA_START_LE_AUDIO_SHARING, true)
-                    }
+                    },
                 )
             }
         startSettingsActivity(intent, view)
@@ -345,7 +366,7 @@
         companion object {
             internal fun build(
                 isBluetoothEnabled: Boolean,
-                isAutoOnToggleFeatureAvailable: Boolean
+                isAutoOnToggleFeatureAvailable: Boolean,
             ) =
                 UiProperties(
                     subTitleResId = getSubtitleResId(isBluetoothEnabled),
@@ -355,7 +376,7 @@
                     scrollViewMinHeightResId =
                         if (isAutoOnToggleFeatureAvailable)
                             R.dimen.bluetooth_dialog_scroll_view_min_height_with_auto_on
-                        else R.dimen.bluetooth_dialog_scroll_view_min_height
+                        else R.dimen.bluetooth_dialog_scroll_view_min_height,
                 )
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/DeviceItemActionInteractor.kt b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/DeviceItemActionInteractor.kt
index f1894d3..cf0f19f 100644
--- a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/DeviceItemActionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/DeviceItemActionInteractor.kt
@@ -16,87 +16,28 @@
 
 package com.android.systemui.bluetooth.qsdialog
 
-import android.bluetooth.BluetoothDevice
-import android.bluetooth.BluetoothProfile
-import android.content.Intent
-import android.os.Bundle
-import android.provider.Settings
 import com.android.internal.logging.UiEventLogger
-import com.android.settingslib.bluetooth.A2dpProfile
-import com.android.settingslib.bluetooth.BluetoothUtils
-import com.android.settingslib.bluetooth.HeadsetProfile
-import com.android.settingslib.bluetooth.HearingAidProfile
-import com.android.settingslib.bluetooth.LeAudioProfile
-import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcast
-import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastAssistant
-import com.android.settingslib.bluetooth.LocalBluetoothManager
-import com.android.systemui.animation.DialogTransitionAnimator
-import com.android.systemui.bluetooth.qsdialog.DeviceItemActionInteractor.LaunchSettingsCriteria.Companion.getCurrentConnectedLeByGroupId
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Background
-import com.android.systemui.plugins.ActivityStarter
 import com.android.systemui.statusbar.phone.SystemUIDialog
 import javax.inject.Inject
 import kotlinx.coroutines.CoroutineDispatcher
 import kotlinx.coroutines.withContext
 
+interface DeviceItemActionInteractor {
+    suspend fun onClick(deviceItem: DeviceItem, dialog: SystemUIDialog) {}
+}
+
 @SysUISingleton
-class DeviceItemActionInteractor
+class DeviceItemActionInteractorImpl
 @Inject
 constructor(
-    private val activityStarter: ActivityStarter,
-    private val dialogTransitionAnimator: DialogTransitionAnimator,
-    private val localBluetoothManager: LocalBluetoothManager?,
     @Background private val backgroundDispatcher: CoroutineDispatcher,
-    private val logger: BluetoothTileDialogLogger,
     private val uiEventLogger: UiEventLogger,
-) {
-    private val leAudioProfile: LeAudioProfile?
-        get() = localBluetoothManager?.profileManager?.leAudioProfile
+) : DeviceItemActionInteractor {
 
-    private val assistantProfile: LocalBluetoothLeBroadcastAssistant?
-        get() = localBluetoothManager?.profileManager?.leAudioBroadcastAssistantProfile
-
-    private val launchSettingsCriteriaList: List<LaunchSettingsCriteria>
-        get() =
-            listOf(
-                InSharingClickedNoSource(localBluetoothManager, backgroundDispatcher, logger),
-                NotSharingClickedNonConnect(
-                    leAudioProfile,
-                    assistantProfile,
-                    backgroundDispatcher,
-                    logger
-                ),
-                NotSharingClickedActive(
-                    leAudioProfile,
-                    assistantProfile,
-                    backgroundDispatcher,
-                    logger
-                )
-            )
-
-    suspend fun onClick(deviceItem: DeviceItem, dialog: SystemUIDialog) {
+    override suspend fun onClick(deviceItem: DeviceItem, dialog: SystemUIDialog) {
         withContext(backgroundDispatcher) {
-            logger.logDeviceClick(deviceItem.cachedBluetoothDevice.address, deviceItem.type)
-            if (
-                BluetoothUtils.isAudioSharingEnabled() &&
-                    localBluetoothManager != null &&
-                    leAudioProfile != null &&
-                    assistantProfile != null
-            ) {
-                val inAudioSharing = BluetoothUtils.isBroadcasting(localBluetoothManager)
-                logger.logDeviceClickInAudioSharingWhenEnabled(inAudioSharing)
-
-                val criteriaMatched =
-                    launchSettingsCriteriaList.firstOrNull {
-                        it.matched(inAudioSharing, deviceItem)
-                    }
-                if (criteriaMatched != null) {
-                    uiEventLogger.log(criteriaMatched.getClickUiEvent(deviceItem))
-                    launchSettings(deviceItem.cachedBluetoothDevice.device, dialog)
-                    return@withContext
-                }
-            }
             deviceItem.cachedBluetoothDevice.apply {
                 when (deviceItem.type) {
                     DeviceItemType.ACTIVE_MEDIA_BLUETOOTH_DEVICE -> {
@@ -106,12 +47,6 @@
                     DeviceItemType.AUDIO_SHARING_MEDIA_BLUETOOTH_DEVICE -> {
                         uiEventLogger.log(BluetoothTileDialogUiEvent.AUDIO_SHARING_DEVICE_CLICKED)
                     }
-                    DeviceItemType.AVAILABLE_AUDIO_SHARING_MEDIA_BLUETOOTH_DEVICE -> {
-                        // TODO(b/360759048): pop up dialog
-                        uiEventLogger.log(
-                            BluetoothTileDialogUiEvent.AVAILABLE_AUDIO_SHARING_DEVICE_CLICKED
-                        )
-                    }
                     DeviceItemType.AVAILABLE_MEDIA_BLUETOOTH_DEVICE -> {
                         setActive()
                         uiEventLogger.log(BluetoothTileDialogUiEvent.CONNECTED_DEVICE_SET_ACTIVE)
@@ -126,186 +61,12 @@
                         connect()
                         uiEventLogger.log(BluetoothTileDialogUiEvent.SAVED_DEVICE_CONNECT)
                     }
-                }
-            }
-        }
-    }
-
-    private fun launchSettings(device: BluetoothDevice, dialog: SystemUIDialog) {
-        val intent =
-            Intent(Settings.ACTION_BLUETOOTH_SETTINGS).apply {
-                putExtra(
-                    EXTRA_SHOW_FRAGMENT_ARGUMENTS,
-                    Bundle().apply {
-                        putParcelable(LocalBluetoothLeBroadcast.EXTRA_BLUETOOTH_DEVICE, device)
+                    DeviceItemType.AVAILABLE_AUDIO_SHARING_MEDIA_BLUETOOTH_DEVICE -> {
+                        // Do nothing. Should already be handled in
+                        // AudioSharingDeviceItemActionInteractor.
                     }
-                )
-            }
-        intent.flags = Intent.FLAG_ACTIVITY_CLEAR_TASK
-        activityStarter.postStartActivityDismissingKeyguard(
-            intent,
-            0,
-            dialogTransitionAnimator.createActivityTransitionController(dialog)
-        )
-    }
-
-    private interface LaunchSettingsCriteria {
-        suspend fun matched(inAudioSharing: Boolean, deviceItem: DeviceItem): Boolean
-
-        suspend fun getClickUiEvent(deviceItem: DeviceItem): BluetoothTileDialogUiEvent
-
-        companion object {
-            suspend fun getCurrentConnectedLeByGroupId(
-                leAudioProfile: LeAudioProfile,
-                assistantProfile: LocalBluetoothLeBroadcastAssistant,
-                @Background backgroundDispatcher: CoroutineDispatcher,
-                logger: BluetoothTileDialogLogger,
-            ): Map<Int, List<BluetoothDevice>> {
-                return withContext(backgroundDispatcher) {
-                    assistantProfile
-                        .getDevicesMatchingConnectionStates(
-                            intArrayOf(BluetoothProfile.STATE_CONNECTED)
-                        )
-                        ?.filterNotNull()
-                        ?.groupBy { leAudioProfile.getGroupId(it) }
-                        ?.also { logger.logConnectedLeByGroupId(it) } ?: emptyMap()
                 }
             }
         }
     }
-
-    private class InSharingClickedNoSource(
-        private val localBluetoothManager: LocalBluetoothManager?,
-        @Background private val backgroundDispatcher: CoroutineDispatcher,
-        private val logger: BluetoothTileDialogLogger,
-    ) : LaunchSettingsCriteria {
-        // If currently broadcasting and the clicked device is not connected to the source
-        override suspend fun matched(inAudioSharing: Boolean, deviceItem: DeviceItem): Boolean {
-            return withContext(backgroundDispatcher) {
-                val matched =
-                    inAudioSharing &&
-                        deviceItem.isMediaDevice &&
-                        !BluetoothUtils.hasConnectedBroadcastSource(
-                            deviceItem.cachedBluetoothDevice,
-                            localBluetoothManager
-                        )
-
-                if (matched) {
-                    logger.logLaunchSettingsCriteriaMatched("InSharingClickedNoSource", deviceItem)
-                }
-
-                matched
-            }
-        }
-
-        override suspend fun getClickUiEvent(deviceItem: DeviceItem) =
-            if (deviceItem.isLeAudioSupported)
-                BluetoothTileDialogUiEvent.LAUNCH_SETTINGS_IN_SHARING_LE_DEVICE_CLICKED
-            else BluetoothTileDialogUiEvent.LAUNCH_SETTINGS_IN_SHARING_NON_LE_DEVICE_CLICKED
-    }
-
-    private class NotSharingClickedNonConnect(
-        private val leAudioProfile: LeAudioProfile?,
-        private val assistantProfile: LocalBluetoothLeBroadcastAssistant?,
-        @Background private val backgroundDispatcher: CoroutineDispatcher,
-        private val logger: BluetoothTileDialogLogger,
-    ) : LaunchSettingsCriteria {
-        // If not broadcasting, having one device connected, and clicked on a not yet connected LE
-        // audio device
-        override suspend fun matched(inAudioSharing: Boolean, deviceItem: DeviceItem): Boolean {
-            return withContext(backgroundDispatcher) {
-                val matched =
-                    leAudioProfile?.let { leAudio ->
-                        assistantProfile?.let { assistant ->
-                            !inAudioSharing &&
-                                getCurrentConnectedLeByGroupId(
-                                        leAudio,
-                                        assistant,
-                                        backgroundDispatcher,
-                                        logger
-                                    )
-                                    .size == 1 &&
-                                deviceItem.isNotConnectedLeAudioSupported
-                        }
-                    } ?: false
-
-                if (matched) {
-                    logger.logLaunchSettingsCriteriaMatched(
-                        "NotSharingClickedNonConnect",
-                        deviceItem
-                    )
-                }
-
-                matched
-            }
-        }
-
-        override suspend fun getClickUiEvent(deviceItem: DeviceItem) =
-            BluetoothTileDialogUiEvent.LAUNCH_SETTINGS_NOT_SHARING_SAVED_LE_DEVICE_CLICKED
-    }
-
-    private class NotSharingClickedActive(
-        private val leAudioProfile: LeAudioProfile?,
-        private val assistantProfile: LocalBluetoothLeBroadcastAssistant?,
-        @Background private val backgroundDispatcher: CoroutineDispatcher,
-        private val logger: BluetoothTileDialogLogger,
-    ) : LaunchSettingsCriteria {
-        // If not broadcasting, having two device connected, clicked on the active LE audio
-        // device
-        override suspend fun matched(inAudioSharing: Boolean, deviceItem: DeviceItem): Boolean {
-            return withContext(backgroundDispatcher) {
-                val matched =
-                    leAudioProfile?.let { leAudio ->
-                        assistantProfile?.let { assistant ->
-                            !inAudioSharing &&
-                                getCurrentConnectedLeByGroupId(
-                                        leAudio,
-                                        assistant,
-                                        backgroundDispatcher,
-                                        logger
-                                    )
-                                    .size == 2 &&
-                                deviceItem.isActiveLeAudioSupported
-                        }
-                    } ?: false
-
-                if (matched) {
-                    logger.logLaunchSettingsCriteriaMatched(
-                        "NotSharingClickedConnected",
-                        deviceItem
-                    )
-                }
-
-                matched
-            }
-        }
-
-        override suspend fun getClickUiEvent(deviceItem: DeviceItem) =
-            BluetoothTileDialogUiEvent.LAUNCH_SETTINGS_NOT_SHARING_ACTIVE_LE_DEVICE_CLICKED
-    }
-
-    private companion object {
-        const val EXTRA_SHOW_FRAGMENT_ARGUMENTS = ":settings:show_fragment_args"
-
-        val DeviceItem.isLeAudioSupported: Boolean
-            get() =
-                cachedBluetoothDevice.profiles.any { profile ->
-                    profile is LeAudioProfile && profile.isEnabled(cachedBluetoothDevice.device)
-                }
-
-        val DeviceItem.isNotConnectedLeAudioSupported: Boolean
-            get() = type == DeviceItemType.SAVED_BLUETOOTH_DEVICE && isLeAudioSupported
-
-        val DeviceItem.isActiveLeAudioSupported: Boolean
-            get() = type == DeviceItemType.ACTIVE_MEDIA_BLUETOOTH_DEVICE && isLeAudioSupported
-
-        val DeviceItem.isMediaDevice: Boolean
-            get() =
-                cachedBluetoothDevice.uiAccessibleProfiles.any {
-                    it is A2dpProfile ||
-                        it is HearingAidProfile ||
-                        it is LeAudioProfile ||
-                        it is HeadsetProfile
-                }
-    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/DeviceItemFactory.kt b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/DeviceItemFactory.kt
index 7280489..7ed5629 100644
--- a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/DeviceItemFactory.kt
+++ b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/DeviceItemFactory.kt
@@ -23,7 +23,6 @@
 import com.android.settingslib.bluetooth.CachedBluetoothDevice
 import com.android.settingslib.bluetooth.LocalBluetoothManager
 import com.android.settingslib.flags.Flags
-import com.android.settingslib.flags.Flags.enableLeAudioSharing
 import com.android.systemui.res.R
 
 private val backgroundOn = R.drawable.settingslib_switch_bar_bg_on
@@ -56,7 +55,7 @@
             connectionSummary: String,
             background: Int,
             actionAccessibilityLabel: String,
-            isActive: Boolean
+            isActive: Boolean,
         ): DeviceItem {
             return DeviceItem(
                 type = type,
@@ -70,7 +69,7 @@
                 background = background,
                 isEnabled = !cachedDevice.isBusy,
                 actionAccessibilityLabel = actionAccessibilityLabel,
-                isActive = isActive
+                isActive = isActive,
             )
         }
     }
@@ -80,7 +79,7 @@
     override fun isFilterMatched(
         context: Context,
         cachedDevice: CachedBluetoothDevice,
-        audioManager: AudioManager
+        audioManager: AudioManager,
     ): Boolean {
         return BluetoothUtils.isActiveMediaDevice(cachedDevice) &&
             BluetoothUtils.isAvailableMediaBluetoothDevice(cachedDevice, audioManager)
@@ -94,20 +93,20 @@
             cachedDevice.connectionSummary ?: "",
             backgroundOn,
             context.getString(actionAccessibilityLabelDisconnect),
-            isActive = true
+            isActive = true,
         )
     }
 }
 
 internal class AudioSharingMediaDeviceItemFactory(
-    private val localBluetoothManager: LocalBluetoothManager?
+    private val localBluetoothManager: LocalBluetoothManager
 ) : DeviceItemFactory() {
     override fun isFilterMatched(
         context: Context,
         cachedDevice: CachedBluetoothDevice,
-        audioManager: AudioManager
+        audioManager: AudioManager,
     ): Boolean {
-        return enableLeAudioSharing() &&
+        return BluetoothUtils.isAudioSharingEnabled() &&
             BluetoothUtils.hasConnectedBroadcastSource(cachedDevice, localBluetoothManager)
     }
 
@@ -120,24 +119,24 @@
                 ?: context.getString(audioSharing),
             if (cachedDevice.isBusy) backgroundOffBusy else backgroundOn,
             "",
-            isActive = !cachedDevice.isBusy
+            isActive = !cachedDevice.isBusy,
         )
     }
 }
 
 internal class AvailableAudioSharingMediaDeviceItemFactory(
-    private val localBluetoothManager: LocalBluetoothManager?
+    private val localBluetoothManager: LocalBluetoothManager
 ) : AvailableMediaDeviceItemFactory() {
     override fun isFilterMatched(
         context: Context,
         cachedDevice: CachedBluetoothDevice,
-        audioManager: AudioManager
+        audioManager: AudioManager,
     ): Boolean {
         return BluetoothUtils.isAudioSharingEnabled() &&
             super.isFilterMatched(context, cachedDevice, audioManager) &&
             BluetoothUtils.isAvailableAudioSharingMediaBluetoothDevice(
                 cachedDevice,
-                localBluetoothManager
+                localBluetoothManager,
             )
     }
 
@@ -151,7 +150,7 @@
             ),
             if (cachedDevice.isBusy) backgroundOffBusy else backgroundOff,
             "",
-            isActive = false
+            isActive = false,
         )
     }
 }
@@ -160,7 +159,7 @@
     override fun isFilterMatched(
         context: Context,
         cachedDevice: CachedBluetoothDevice,
-        audioManager: AudioManager
+        audioManager: AudioManager,
     ): Boolean {
         return BluetoothUtils.isActiveMediaDevice(cachedDevice) &&
             BluetoothUtils.isAvailableHearingDevice(cachedDevice)
@@ -171,7 +170,7 @@
     override fun isFilterMatched(
         context: Context,
         cachedDevice: CachedBluetoothDevice,
-        audioManager: AudioManager
+        audioManager: AudioManager,
     ): Boolean {
         return !BluetoothUtils.isActiveMediaDevice(cachedDevice) &&
             BluetoothUtils.isAvailableMediaBluetoothDevice(cachedDevice, audioManager)
@@ -186,7 +185,7 @@
                 ?: context.getString(connected),
             if (cachedDevice.isBusy) backgroundOffBusy else backgroundOff,
             context.getString(actionAccessibilityLabelActivate),
-            isActive = false
+            isActive = false,
         )
     }
 }
@@ -195,7 +194,7 @@
     override fun isFilterMatched(
         context: Context,
         cachedDevice: CachedBluetoothDevice,
-        audioManager: AudioManager
+        audioManager: AudioManager,
     ): Boolean {
         return !BluetoothUtils.isActiveMediaDevice(cachedDevice) &&
             BluetoothUtils.isAvailableHearingDevice(cachedDevice)
@@ -206,7 +205,7 @@
     override fun isFilterMatched(
         context: Context,
         cachedDevice: CachedBluetoothDevice,
-        audioManager: AudioManager
+        audioManager: AudioManager,
     ): Boolean {
         return if (Flags.enableHideExclusivelyManagedBluetoothDevice()) {
             !BluetoothUtils.isExclusivelyManagedBluetoothDevice(context, cachedDevice.device) &&
@@ -225,7 +224,7 @@
                 ?: context.getString(connected),
             if (cachedDevice.isBusy) backgroundOffBusy else backgroundOff,
             context.getString(actionAccessibilityLabelDisconnect),
-            isActive = false
+            isActive = false,
         )
     }
 }
@@ -234,7 +233,7 @@
     override fun isFilterMatched(
         context: Context,
         cachedDevice: CachedBluetoothDevice,
-        audioManager: AudioManager
+        audioManager: AudioManager,
     ): Boolean {
         return if (Flags.enableHideExclusivelyManagedBluetoothDevice()) {
             !BluetoothUtils.isExclusivelyManagedBluetoothDevice(context, cachedDevice.device) &&
@@ -254,7 +253,7 @@
                 ?: context.getString(saved),
             if (cachedDevice.isBusy) backgroundOffBusy else backgroundOff,
             context.getString(actionAccessibilityLabelActivate),
-            isActive = false
+            isActive = false,
         )
     }
 }
@@ -263,12 +262,12 @@
     override fun isFilterMatched(
         context: Context,
         cachedDevice: CachedBluetoothDevice,
-        audioManager: AudioManager
+        audioManager: AudioManager,
     ): Boolean {
         return if (Flags.enableHideExclusivelyManagedBluetoothDevice()) {
             !BluetoothUtils.isExclusivelyManagedBluetoothDevice(
                 context,
-                cachedDevice.getDevice()
+                cachedDevice.getDevice(),
             ) &&
                 cachedDevice.isHearingAidDevice &&
                 cachedDevice.bondState == BluetoothDevice.BOND_BONDED &&
diff --git a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/DeviceItemInteractor.kt b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/DeviceItemInteractor.kt
index 9114eca..01b84da 100644
--- a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/DeviceItemInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/DeviceItemInteractor.kt
@@ -39,6 +39,7 @@
 import kotlinx.coroutines.flow.SharingStarted
 import kotlinx.coroutines.flow.asSharedFlow
 import kotlinx.coroutines.flow.asStateFlow
+import kotlinx.coroutines.flow.flowOn
 import kotlinx.coroutines.flow.shareIn
 import kotlinx.coroutines.isActive
 import kotlinx.coroutines.withContext
@@ -54,6 +55,8 @@
     private val localBluetoothManager: LocalBluetoothManager?,
     private val systemClock: SystemClock,
     private val logger: BluetoothTileDialogLogger,
+    private val deviceItemFactoryList: List<@JvmSuppressWildcards DeviceItemFactory>,
+    private val deviceItemDisplayPriority: List<@JvmSuppressWildcards DeviceItemType>,
     @Application private val coroutineScope: CoroutineScope,
     @Background private val backgroundDispatcher: CoroutineDispatcher,
 ) {
@@ -67,7 +70,7 @@
     internal val showSeeAllUpdate
         get() = mutableShowSeeAllUpdate.asStateFlow()
 
-    internal val deviceItemUpdateRequest: SharedFlow<Unit> =
+    val deviceItemUpdateRequest: SharedFlow<Unit> =
         conflatedCallbackFlow {
                 val listener =
                     object : BluetoothCallback {
@@ -112,28 +115,9 @@
                 localBluetoothManager?.eventManager?.registerCallback(listener)
                 awaitClose { localBluetoothManager?.eventManager?.unregisterCallback(listener) }
             }
+            .flowOn(backgroundDispatcher)
             .shareIn(coroutineScope, SharingStarted.WhileSubscribed(replayExpirationMillis = 0))
 
-    private var deviceItemFactoryList: List<DeviceItemFactory> =
-        listOf(
-            ActiveMediaDeviceItemFactory(),
-            AudioSharingMediaDeviceItemFactory(localBluetoothManager),
-            AvailableAudioSharingMediaDeviceItemFactory(localBluetoothManager),
-            AvailableMediaDeviceItemFactory(),
-            ConnectedDeviceItemFactory(),
-            SavedDeviceItemFactory()
-        )
-
-    private var displayPriority: List<DeviceItemType> =
-        listOf(
-            DeviceItemType.ACTIVE_MEDIA_BLUETOOTH_DEVICE,
-            DeviceItemType.AUDIO_SHARING_MEDIA_BLUETOOTH_DEVICE,
-            DeviceItemType.AVAILABLE_AUDIO_SHARING_MEDIA_BLUETOOTH_DEVICE,
-            DeviceItemType.AVAILABLE_MEDIA_BLUETOOTH_DEVICE,
-            DeviceItemType.CONNECTED_BLUETOOTH_DEVICE,
-            DeviceItemType.SAVED_BLUETOOTH_DEVICE,
-        )
-
     internal suspend fun updateDeviceItems(context: Context, trigger: DeviceFetchTrigger) {
         withContext(backgroundDispatcher) {
             val start = systemClock.elapsedRealtime()
@@ -144,7 +128,7 @@
                             .firstOrNull { it.isFilterMatched(context, cachedDevice, audioManager) }
                             ?.create(context, cachedDevice)
                     }
-                    .sort(displayPriority, bluetoothAdapter?.mostRecentlyConnectedDevices)
+                    .sort(deviceItemDisplayPriority, bluetoothAdapter?.mostRecentlyConnectedDevices)
             // Only emit when the job is not cancelled
             if (isActive) {
                 mutableDeviceItemUpdate.tryEmit(deviceItems.take(MAX_DEVICE_ITEM_ENTRY))
@@ -176,14 +160,6 @@
         )
     }
 
-    internal fun setDeviceItemFactoryListForTesting(list: List<DeviceItemFactory>) {
-        deviceItemFactoryList = list
-    }
-
-    internal fun setDisplayPriorityForTesting(list: List<DeviceItemType>) {
-        displayPriority = list
-    }
-
     companion object {
         private const val TAG = "DeviceItemInteractor"
         private const val MAX_DEVICE_ITEM_ENTRY = 3
diff --git a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/dagger/AudioSharingModule.kt b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/dagger/AudioSharingModule.kt
new file mode 100644
index 0000000..50970a5
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/dagger/AudioSharingModule.kt
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.bluetooth.qsdialog.dagger
+
+import com.android.settingslib.bluetooth.LocalBluetoothManager
+import com.android.settingslib.flags.Flags
+import com.android.settingslib.volume.data.repository.AudioSharingRepository as SettingsLibAudioSharingRepository
+import com.android.systemui.bluetooth.qsdialog.ActiveMediaDeviceItemFactory
+import com.android.systemui.bluetooth.qsdialog.AudioSharingDeviceItemActionInteractorImpl
+import com.android.systemui.bluetooth.qsdialog.AudioSharingInteractor
+import com.android.systemui.bluetooth.qsdialog.AudioSharingInteractorEmptyImpl
+import com.android.systemui.bluetooth.qsdialog.AudioSharingInteractorImpl
+import com.android.systemui.bluetooth.qsdialog.AudioSharingMediaDeviceItemFactory
+import com.android.systemui.bluetooth.qsdialog.AudioSharingRepository
+import com.android.systemui.bluetooth.qsdialog.AudioSharingRepositoryEmptyImpl
+import com.android.systemui.bluetooth.qsdialog.AudioSharingRepositoryImpl
+import com.android.systemui.bluetooth.qsdialog.AvailableAudioSharingMediaDeviceItemFactory
+import com.android.systemui.bluetooth.qsdialog.AvailableMediaDeviceItemFactory
+import com.android.systemui.bluetooth.qsdialog.ConnectedDeviceItemFactory
+import com.android.systemui.bluetooth.qsdialog.DeviceItemActionInteractor
+import com.android.systemui.bluetooth.qsdialog.DeviceItemActionInteractorImpl
+import com.android.systemui.bluetooth.qsdialog.DeviceItemFactory
+import com.android.systemui.bluetooth.qsdialog.DeviceItemType
+import com.android.systemui.bluetooth.qsdialog.SavedDeviceItemFactory
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Background
+import dagger.Lazy
+import dagger.Module
+import dagger.Provides
+import kotlinx.coroutines.CoroutineDispatcher
+
+/** Dagger module for audio sharing code for BT QS dialog */
+@Module
+interface AudioSharingModule {
+
+    companion object {
+        @Provides
+        @SysUISingleton
+        fun provideAudioSharingRepository(
+            localBluetoothManager: LocalBluetoothManager?,
+            settingsLibAudioSharingRepository: SettingsLibAudioSharingRepository,
+            @Background backgroundDispatcher: CoroutineDispatcher,
+        ): AudioSharingRepository =
+            if (
+                Flags.enableLeAudioSharing() &&
+                    Flags.audioSharingQsDialogImprovement() &&
+                    localBluetoothManager != null
+            ) {
+                AudioSharingRepositoryImpl(
+                    localBluetoothManager,
+                    settingsLibAudioSharingRepository,
+                    backgroundDispatcher,
+                )
+            } else {
+                AudioSharingRepositoryEmptyImpl()
+            }
+
+        @Provides
+        @SysUISingleton
+        fun provideAudioSharingInteractor(
+            localBluetoothManager: LocalBluetoothManager?,
+            impl: Lazy<AudioSharingInteractorImpl>,
+            emptyImpl: Lazy<AudioSharingInteractorEmptyImpl>,
+        ): AudioSharingInteractor =
+            if (Flags.enableLeAudioSharing() && localBluetoothManager != null) {
+                impl.get()
+            } else {
+                emptyImpl.get()
+            }
+
+        @Provides
+        @SysUISingleton
+        fun provideDeviceItemActionInteractor(
+            localBluetoothManager: LocalBluetoothManager?,
+            audioSharingImpl: Lazy<AudioSharingDeviceItemActionInteractorImpl>,
+            impl: Lazy<DeviceItemActionInteractorImpl>,
+        ): DeviceItemActionInteractor =
+            if (Flags.enableLeAudioSharing() && localBluetoothManager != null) {
+                audioSharingImpl.get()
+            } else {
+                impl.get()
+            }
+
+        @Provides
+        @SysUISingleton
+        fun provideDeviceItemFactoryList(
+            localBluetoothManager: LocalBluetoothManager?
+        ): List<DeviceItemFactory> = buildList {
+            add(ActiveMediaDeviceItemFactory())
+            if (Flags.enableLeAudioSharing() && localBluetoothManager != null) {
+                add(AudioSharingMediaDeviceItemFactory(localBluetoothManager))
+                add(AvailableAudioSharingMediaDeviceItemFactory(localBluetoothManager))
+            }
+            add(AvailableMediaDeviceItemFactory())
+            add(ConnectedDeviceItemFactory())
+            add(SavedDeviceItemFactory())
+        }
+
+        @Provides
+        @SysUISingleton
+        fun provideDeviceItemDisplayPriority(
+            localBluetoothManager: LocalBluetoothManager?
+        ): List<DeviceItemType> = buildList {
+            add(DeviceItemType.ACTIVE_MEDIA_BLUETOOTH_DEVICE)
+            if (Flags.enableLeAudioSharing() && localBluetoothManager != null) {
+                add(DeviceItemType.AUDIO_SHARING_MEDIA_BLUETOOTH_DEVICE)
+                add(DeviceItemType.AVAILABLE_AUDIO_SHARING_MEDIA_BLUETOOTH_DEVICE)
+            }
+            add(DeviceItemType.AVAILABLE_MEDIA_BLUETOOTH_DEVICE)
+            add(DeviceItemType.CONNECTED_BLUETOOTH_DEVICE)
+            add(DeviceItemType.SAVED_BLUETOOTH_DEVICE)
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/AlternateBouncerInteractor.kt b/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/AlternateBouncerInteractor.kt
index 373671d0..0949ea4 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/AlternateBouncerInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/AlternateBouncerInteractor.kt
@@ -16,6 +16,7 @@
 
 package com.android.systemui.bouncer.domain.interactor
 
+import android.util.Log
 import com.android.keyguard.KeyguardUpdateMonitor
 import com.android.systemui.biometrics.data.repository.FingerprintPropertyRepository
 import com.android.systemui.bouncer.data.repository.KeyguardBouncerRepository
@@ -46,6 +47,7 @@
 import kotlinx.coroutines.flow.flatMapLatest
 import kotlinx.coroutines.flow.flowOf
 import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.onEach
 import kotlinx.coroutines.flow.stateIn
 
 /** Encapsulates business logic for interacting with the lock-screen alternate bouncer. */
@@ -137,6 +139,8 @@
                     flowOf(false)
                 }
             }
+            .distinctUntilChanged()
+            .onEach { Log.d(TAG, "canShowAlternateBouncer changed to $it") }
             .stateIn(
                 scope = scope,
                 started = WhileSubscribed(),
@@ -234,5 +238,7 @@
 
     companion object {
         private const val MIN_VISIBILITY_DURATION_UNTIL_TOUCHES_DISMISS_ALTERNATE_BOUNCER_MS = 200L
+
+        private const val TAG = "AlternateBouncerInteractor"
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/brightness/ui/compose/BrightnessSlider.kt b/packages/SystemUI/src/com/android/systemui/brightness/ui/compose/BrightnessSlider.kt
index 8270db1..4708079 100644
--- a/packages/SystemUI/src/com/android/systemui/brightness/ui/compose/BrightnessSlider.kt
+++ b/packages/SystemUI/src/com/android/systemui/brightness/ui/compose/BrightnessSlider.kt
@@ -18,6 +18,8 @@
 
 import androidx.compose.animation.core.animateFloatAsState
 import androidx.compose.foundation.clickable
+import androidx.compose.foundation.gestures.Orientation
+import androidx.compose.foundation.interaction.MutableInteractionSource
 import androidx.compose.foundation.layout.fillMaxWidth
 import androidx.compose.foundation.layout.size
 import androidx.compose.material3.MaterialTheme
@@ -33,12 +35,17 @@
 import androidx.compose.ui.unit.dp
 import androidx.lifecycle.compose.collectAsStateWithLifecycle
 import com.android.compose.PlatformSlider
+import com.android.systemui.Flags
 import com.android.systemui.brightness.shared.model.GammaBrightness
 import com.android.systemui.brightness.ui.viewmodel.BrightnessSliderViewModel
 import com.android.systemui.brightness.ui.viewmodel.Drag
 import com.android.systemui.common.shared.model.Icon
 import com.android.systemui.common.shared.model.Text
 import com.android.systemui.common.ui.compose.Icon
+import com.android.systemui.haptics.slider.SeekableSliderTrackerConfig
+import com.android.systemui.haptics.slider.SliderHapticFeedbackConfig
+import com.android.systemui.haptics.slider.compose.ui.SliderHapticsViewModel
+import com.android.systemui.lifecycle.rememberViewModel
 import com.android.systemui.utils.PolicyRestriction
 import kotlinx.coroutines.launch
 
@@ -54,12 +61,30 @@
     onStop: (Int) -> Unit,
     modifier: Modifier = Modifier,
     formatter: (Int) -> String = { "$it" },
+    hapticsViewModelFactory: SliderHapticsViewModel.Factory,
 ) {
     var value by remember(gammaValue) { mutableIntStateOf(gammaValue) }
     val animatedValue by
         animateFloatAsState(targetValue = value.toFloat(), label = "BrightnessSliderAnimatedValue")
     val floatValueRange = valueRange.first.toFloat()..valueRange.last.toFloat()
     val isRestricted = remember(restriction) { restriction is PolicyRestriction.Restricted }
+    val interactionSource = remember { MutableInteractionSource() }
+    val hapticsViewModel: SliderHapticsViewModel? =
+        if (Flags.hapticsForComposeSliders()) {
+            rememberViewModel(traceName = "SliderHapticsViewModel") {
+                hapticsViewModelFactory.create(
+                    interactionSource,
+                    floatValueRange,
+                    Orientation.Horizontal,
+                    SliderHapticFeedbackConfig(
+                        maxVelocityToScale = 1f /* slider progress(from 0 to 1) per sec */
+                    ),
+                    SeekableSliderTrackerConfig(),
+                )
+            }
+        } else {
+            null
+        }
 
     PlatformSlider(
         value = animatedValue,
@@ -67,19 +92,19 @@
         enabled = !isRestricted,
         onValueChange = {
             if (!isRestricted) {
+                hapticsViewModel?.onValueChange(it)
                 value = it.toInt()
                 onDrag(value)
             }
         },
         onValueChangeFinished = {
             if (!isRestricted) {
+                hapticsViewModel?.onValueChangeEnded()
                 onStop(value)
             }
         },
         modifier =
-            modifier.clickable(
-                enabled = isRestricted,
-            ) {
+            modifier.clickable(enabled = isRestricted) {
                 if (restriction is PolicyRestriction.Restricted) {
                     onRestrictedClick(restriction)
                 }
@@ -98,14 +123,12 @@
                 maxLines = 1,
             )
         },
+        interactionSource = interactionSource,
     )
 }
 
 @Composable
-fun BrightnessSliderContainer(
-    viewModel: BrightnessSliderViewModel,
-    modifier: Modifier = Modifier,
-) {
+fun BrightnessSliderContainer(viewModel: BrightnessSliderViewModel, modifier: Modifier = Modifier) {
     val state by viewModel.currentBrightness.collectAsStateWithLifecycle()
     val gamma = state.value
     val coroutineScope = rememberCoroutineScope()
@@ -125,5 +148,6 @@
         onStop = { coroutineScope.launch { viewModel.onDrag(Drag.Stopped(GammaBrightness(it))) } },
         modifier = modifier.fillMaxWidth(),
         formatter = viewModel::formatValue,
+        hapticsViewModelFactory = viewModel.hapticsViewModelFactory,
     )
 }
diff --git a/packages/SystemUI/src/com/android/systemui/brightness/ui/viewmodel/BrightnessSliderViewModel.kt b/packages/SystemUI/src/com/android/systemui/brightness/ui/viewmodel/BrightnessSliderViewModel.kt
index 16a1dcc..074ac50 100644
--- a/packages/SystemUI/src/com/android/systemui/brightness/ui/viewmodel/BrightnessSliderViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/brightness/ui/viewmodel/BrightnessSliderViewModel.kt
@@ -24,6 +24,7 @@
 import com.android.systemui.common.shared.model.Text
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.haptics.slider.compose.ui.SliderHapticsViewModel
 import com.android.systemui.res.R
 import com.android.systemui.utils.PolicyRestriction
 import javax.inject.Inject
@@ -38,12 +39,13 @@
     private val screenBrightnessInteractor: ScreenBrightnessInteractor,
     private val brightnessPolicyEnforcementInteractor: BrightnessPolicyEnforcementInteractor,
     @Application private val applicationScope: CoroutineScope,
+    val hapticsViewModelFactory: SliderHapticsViewModel.Factory,
 ) {
     val currentBrightness =
         screenBrightnessInteractor.gammaBrightness.stateIn(
             applicationScope,
             SharingStarted.WhileSubscribed(),
-            GammaBrightness(0)
+            GammaBrightness(0),
         )
 
     val maxBrightness = screenBrightnessInteractor.maxGammaBrightness
@@ -85,6 +87,8 @@
 /** Represents a drag event in a brightness slider. */
 sealed interface Drag {
     val brightness: GammaBrightness
+
     @JvmInline value class Dragging(override val brightness: GammaBrightness) : Drag
+
     @JvmInline value class Stopped(override val brightness: GammaBrightness) : Drag
 }
diff --git a/packages/SystemUI/src/com/android/systemui/communal/data/db/CommunalWidgetDao.kt b/packages/SystemUI/src/com/android/systemui/communal/data/db/CommunalWidgetDao.kt
index 5dd4c1c..02bf9db 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/data/db/CommunalWidgetDao.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/data/db/CommunalWidgetDao.kt
@@ -23,6 +23,7 @@
 import androidx.room.Query
 import androidx.room.RoomDatabase
 import androidx.room.Transaction
+import androidx.room.Update
 import androidx.sqlite.db.SupportSQLiteDatabase
 import com.android.systemui.communal.nano.CommunalHubState
 import com.android.systemui.communal.shared.model.CommunalContentSize
@@ -171,8 +172,7 @@
     @Query("UPDATE communal_item_rank_table SET rank = :order WHERE uid = :itemUid")
     fun updateItemRank(itemUid: Long, order: Int)
 
-    @Query("UPDATE communal_widget_table SET span_y = :spanY WHERE widget_id = :widgetId")
-    fun updateWidgetSpanY(widgetId: Int, spanY: Int)
+    @Update fun updateWidget(widget: CommunalWidgetItem)
 
     @Query("DELETE FROM communal_widget_table") fun clearCommunalWidgetsTable()
 
@@ -189,6 +189,15 @@
     }
 
     @Transaction
+    fun resizeWidget(appWidgetId: Int, spanY: Int, widgetIdToRankMap: Map<Int, Int>) {
+        val widget = getWidgetByIdNow(appWidgetId)
+        if (widget != null) {
+            updateWidget(widget.copy(spanY = spanY))
+        }
+        updateWidgetOrder(widgetIdToRankMap)
+    }
+
+    @Transaction
     fun addWidget(
         widgetId: Int,
         provider: ComponentName,
diff --git a/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalWidgetRepository.kt b/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalWidgetRepository.kt
index 3312f3c..0e94289 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalWidgetRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalWidgetRepository.kt
@@ -21,6 +21,7 @@
 import android.content.ComponentName
 import android.os.UserHandle
 import android.os.UserManager
+import com.android.systemui.Flags.communalWidgetResizing
 import com.android.systemui.common.data.repository.PackageChangeRepository
 import com.android.systemui.common.shared.model.PackageInstallSession
 import com.android.systemui.communal.data.backup.CommunalBackupUtils
@@ -82,7 +83,7 @@
      *
      * @param widgetIdToRankMap mapping of the widget ids to the rank of the widget.
      */
-    fun updateWidgetOrder(widgetIdToRankMap: Map<Int, Int>) {}
+    fun updateWidgetOrder(widgetIdToRankMap: Map<Int, Int>)
 
     /**
      * Restores the database by reading a state file from disk and updating the widget ids according
@@ -96,10 +97,13 @@
     /**
      * Update the spanY of a widget in the database.
      *
-     * @param widgetId id of the widget to update.
+     * @param appWidgetId id of the widget to update.
      * @param spanY new spanY value for the widget.
+     * @param widgetIdToRankMap mapping of the widget ids to its rank. Allows re-ordering widgets
+     *   alongside the resize, in case resizing also requires re-ordering. This ensures the
+     *   re-ordering is done in the same database transaction as the resize.
      */
-    fun updateWidgetSpanY(widgetId: Int, spanY: Int)
+    fun resizeWidget(appWidgetId: Int, spanY: Int, widgetIdToRankMap: Map<Int, Int>)
 }
 
 @SysUISingleton
@@ -135,15 +139,17 @@
                     componentName = widget.componentName,
                     rank = rank.rank,
                     providerInfo = providers[widget.widgetId],
+                    spanY = widget.spanY,
                 )
             }
         }
 
-    override fun updateWidgetSpanY(widgetId: Int, spanY: Int) {
+    override fun resizeWidget(appWidgetId: Int, spanY: Int, widgetIdToRankMap: Map<Int, Int>) {
+        if (!communalWidgetResizing()) return
         bgScope.launch {
-            communalWidgetDao.updateWidgetSpanY(widgetId, spanY)
+            communalWidgetDao.resizeWidget(appWidgetId, spanY, widgetIdToRankMap)
             logger.i({ "Updated spanY of widget $int1 to $int2." }) {
-                int1 = widgetId
+                int1 = appWidgetId
                 int2 = spanY
             }
             backupManager.dataChanged()
@@ -445,7 +451,7 @@
         val appWidgetId: Int,
         val componentName: String,
         val rank: Int,
+        val spanY: Int,
         var providerInfo: AppWidgetProviderInfo? = null,
-        var spanY: Int = 3,
     )
 }
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 a687734..3a04d02 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
@@ -399,6 +399,10 @@
     fun updateWidgetOrder(widgetIdToRankMap: Map<Int, Int>) =
         widgetRepository.updateWidgetOrder(widgetIdToRankMap)
 
+    fun resizeWidget(appWidgetId: Int, spanY: Int, widgetIdToRankMap: Map<Int, Int>) {
+        widgetRepository.resizeWidget(appWidgetId, spanY, widgetIdToRankMap)
+    }
+
     /** Request to unpause work profile that is currently in quiet mode. */
     fun unpauseWorkProfile() {
         managedProfileController.setWorkModeEnabled(true)
@@ -449,6 +453,7 @@
                             providerInfo = widget.providerInfo,
                             appWidgetHost = appWidgetHost,
                             inQuietMode = isQuietModeEnabled(widget.providerInfo.profile),
+                            size = CommunalContentSize.toSize(widget.spanY),
                         )
                     }
                     is CommunalWidgetContentModel.Pending -> {
@@ -457,6 +462,7 @@
                             rank = widget.rank,
                             componentName = widget.componentName,
                             icon = widget.icon,
+                            size = CommunalContentSize.toSize(widget.spanY),
                         )
                     }
                 }
diff --git a/packages/SystemUI/src/com/android/systemui/communal/domain/model/CommunalContentModel.kt b/packages/SystemUI/src/com/android/systemui/communal/domain/model/CommunalContentModel.kt
index c2f6e85..4c2c094 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/domain/model/CommunalContentModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/domain/model/CommunalContentModel.kt
@@ -62,11 +62,10 @@
             val providerInfo: AppWidgetProviderInfo,
             val appWidgetHost: CommunalAppWidgetHost,
             val inQuietMode: Boolean,
+            override val size: CommunalContentSize,
         ) : WidgetContent {
             override val key = KEY.widget(appWidgetId)
             override val componentName: ComponentName = providerInfo.provider
-            // Widget size is always half.
-            override val size = CommunalContentSize.HALF
 
             /** Whether this widget can be reconfigured after it has already been added. */
             val reconfigurable: Boolean
@@ -79,11 +78,10 @@
             override val appWidgetId: Int,
             override val rank: Int,
             val providerInfo: AppWidgetProviderInfo,
+            override val size: CommunalContentSize,
         ) : WidgetContent {
             override val key = KEY.disabledWidget(appWidgetId)
             override val componentName: ComponentName = providerInfo.provider
-            // Widget size is always half.
-            override val size = CommunalContentSize.HALF
 
             val appInfo: ApplicationInfo?
                 get() = providerInfo.providerInfo?.applicationInfo
@@ -93,11 +91,10 @@
             override val appWidgetId: Int,
             override val rank: Int,
             override val componentName: ComponentName,
+            override val size: CommunalContentSize,
             val icon: Bitmap? = null,
         ) : WidgetContent {
             override val key = KEY.pendingWidget(appWidgetId)
-            // Widget size is always half.
-            override val size = CommunalContentSize.HALF
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/communal/shared/model/CommunalWidgetContentModel.kt b/packages/SystemUI/src/com/android/systemui/communal/shared/model/CommunalWidgetContentModel.kt
index bcbc8f6..0c9ea78 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/shared/model/CommunalWidgetContentModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/shared/model/CommunalWidgetContentModel.kt
@@ -25,13 +25,14 @@
 sealed interface CommunalWidgetContentModel {
     val appWidgetId: Int
     val rank: Int
+    val spanY: Int
 
     /** Widget is ready to display */
     data class Available(
         override val appWidgetId: Int,
         val providerInfo: AppWidgetProviderInfo,
         override val rank: Int,
-        val spanY: Int = 3,
+        override val spanY: Int,
     ) : CommunalWidgetContentModel
 
     /** Widget is pending installation */
@@ -41,6 +42,6 @@
         val componentName: ComponentName,
         val icon: Bitmap?,
         val user: UserHandle,
-        val spanY: Int = 3,
+        override val spanY: Int,
     ) : CommunalWidgetContentModel
 }
diff --git a/packages/SystemUI/src/com/android/systemui/communal/ui/binder/CommunalAppWidgetHostViewBinder.kt b/packages/SystemUI/src/com/android/systemui/communal/ui/binder/CommunalAppWidgetHostViewBinder.kt
index 5f421fd..ba96f4e 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/ui/binder/CommunalAppWidgetHostViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/ui/binder/CommunalAppWidgetHostViewBinder.kt
@@ -17,19 +17,30 @@
 package com.android.systemui.communal.ui.binder
 
 import android.content.Context
+import android.os.Bundle
 import android.util.SizeF
 import android.view.View
 import android.view.ViewGroup
 import android.widget.FrameLayout
+import androidx.compose.ui.unit.IntSize
 import androidx.core.view.doOnLayout
+import com.android.app.tracing.coroutines.flow.flowOn
 import com.android.app.tracing.coroutines.launch
+import com.android.systemui.Flags.communalWidgetResizing
+import com.android.systemui.common.ui.view.onLayoutChanged
 import com.android.systemui.communal.domain.model.CommunalContentModel
 import com.android.systemui.communal.util.WidgetViewFactory
 import com.android.systemui.util.kotlin.DisposableHandles
+import com.android.systemui.util.kotlin.toDp
+import com.android.systemui.utils.coroutines.flow.conflatedCallbackFlow
+import kotlin.coroutines.CoroutineContext
 import kotlin.coroutines.resume
 import kotlin.coroutines.suspendCoroutine
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.DisposableHandle
+import kotlinx.coroutines.channels.awaitClose
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.distinctUntilChanged
 
 object CommunalAppWidgetHostViewBinder {
     private const val TAG = "CommunalAppWidgetHostViewBinder"
@@ -37,9 +48,11 @@
     fun bind(
         context: Context,
         applicationScope: CoroutineScope,
+        mainContext: CoroutineContext,
+        backgroundContext: CoroutineContext,
         container: FrameLayout,
         model: CommunalContentModel.WidgetContent.Widget,
-        size: SizeF,
+        size: SizeF?,
         factory: WidgetViewFactory,
     ): DisposableHandle {
         val disposables = DisposableHandles()
@@ -49,6 +62,22 @@
                 val widget = factory.createWidget(context, model, size)
                 waitForLayout(container)
                 container.post { container.setView(widget) }
+                if (communalWidgetResizing()) {
+                    // Update the app widget size in the background.
+                    launch("$TAG#updateSize", backgroundContext) {
+                        container.sizeFlow().flowOn(mainContext).distinctUntilChanged().collect {
+                            (width, height) ->
+                            widget.updateAppWidgetSize(
+                                /* newOptions = */ Bundle(),
+                                /* minWidth = */ width,
+                                /* minHeight = */ height,
+                                /* maxWidth = */ width,
+                                /* maxHeight = */ height,
+                                /* ignorePadding = */ true,
+                            )
+                        }
+                    }
+                }
             }
 
         disposables += DisposableHandle { loadingJob.cancel() }
@@ -69,3 +98,13 @@
     (view.parent as? ViewGroup)?.removeView(view)
     addView(view)
 }
+
+private fun View.sizeAsDp(): IntSize = IntSize(width.toDp(context), height.toDp(context))
+
+private fun View.sizeFlow(): Flow<IntSize> = conflatedCallbackFlow {
+    if (isLaidOut && !isLayoutRequested) {
+        trySend(sizeAsDp())
+    }
+    val disposable = onLayoutChanged { trySend(sizeAsDp()) }
+    awaitClose { disposable.dispose() }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/ui/view/layout/sections/CommunalAppWidgetSection.kt b/packages/SystemUI/src/com/android/systemui/communal/ui/view/layout/sections/CommunalAppWidgetSection.kt
index 56b769e..2e12bad 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/ui/view/layout/sections/CommunalAppWidgetSection.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/ui/view/layout/sections/CommunalAppWidgetSection.kt
@@ -25,13 +25,17 @@
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.viewinterop.AndroidView
 import androidx.lifecycle.compose.collectAsStateWithLifecycle
+import com.android.systemui.Flags.communalWidgetResizing
 import com.android.systemui.communal.domain.model.CommunalContentModel
 import com.android.systemui.communal.ui.binder.CommunalAppWidgetHostViewBinder
 import com.android.systemui.communal.ui.viewmodel.BaseCommunalViewModel
 import com.android.systemui.communal.util.WidgetViewFactory
 import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.dagger.qualifiers.UiBackground
 import com.android.systemui.res.R
 import javax.inject.Inject
+import kotlin.coroutines.CoroutineContext
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.DisposableHandle
 
@@ -39,6 +43,8 @@
 @Inject
 constructor(
     @Application private val applicationScope: CoroutineScope,
+    @Main private val mainContext: CoroutineContext,
+    @UiBackground private val backgroundContext: CoroutineContext,
     private val factory: WidgetViewFactory,
 ) {
 
@@ -76,10 +82,12 @@
                             context = context,
                             container = this,
                             model = model,
-                            size = size,
+                            size = if (!communalWidgetResizing()) size else null,
                             factory = factory,
                             applicationScope = applicationScope,
-                        )
+                            mainContext = mainContext,
+                            backgroundContext = backgroundContext,
+                        ),
                     )
 
                     accessibilityDelegate = viewModel.widgetAccessibilityDelegate
diff --git a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/BaseCommunalViewModel.kt b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/BaseCommunalViewModel.kt
index 0929d3e..e25ea4c 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/BaseCommunalViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/BaseCommunalViewModel.kt
@@ -105,7 +105,7 @@
         scene: SceneKey,
         loggingReason: String,
         transitionKey: TransitionKey? = null,
-        keyguardState: KeyguardState? = null
+        keyguardState: KeyguardState? = null,
     ) {
         communalSceneInteractor.changeScene(scene, loggingReason, transitionKey, keyguardState)
     }
@@ -155,17 +155,10 @@
     ) {}
 
     /** Called as the UI requests deleting a widget. */
-    open fun onDeleteWidget(
-        id: Int,
-        componentName: ComponentName,
-        rank: Int,
-    ) {}
+    open fun onDeleteWidget(id: Int, componentName: ComponentName, rank: Int) {}
 
     /** Called as the UI detects a tap event on the widget. */
-    open fun onTapWidget(
-        componentName: ComponentName,
-        rank: Int,
-    ) {}
+    open fun onTapWidget(componentName: ComponentName, rank: Int) {}
 
     /**
      * Called as the UI requests reordering widgets.
@@ -176,10 +169,19 @@
      */
     open fun onReorderWidgets(widgetIdToRankMap: Map<Int, Int>) {}
 
+    /**
+     * Called as the UI requests resizing a widget.
+     *
+     * @param appWidgetId The id of the widget being resized.
+     * @param spanY The new size of the widget, in grid spans.
+     * @param widgetIdToRankMap Mapping of the widget ids to its rank. Allows re-ordering widgets
+     *   alongside the resize, in case resizing also requires re-ordering. This ensures the
+     *   re-ordering is done in the same database transaction as the resize.
+     */
+    open fun onResizeWidget(appWidgetId: Int, spanY: Int, widgetIdToRankMap: Map<Int, Int>) {}
+
     /** Called as the UI requests opening the widget editor with an optional preselected widget. */
-    open fun onOpenWidgetEditor(
-        shouldOpenWidgetPickerOnStart: Boolean = false,
-    ) {}
+    open fun onOpenWidgetEditor(shouldOpenWidgetPickerOnStart: Boolean = false) {}
 
     /** Called as the UI requests to dismiss the CTA tile. */
     open fun onDismissCtaTile() {}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalEditModeViewModel.kt b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalEditModeViewModel.kt
index 65f0679..6508e4b5 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalEditModeViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalEditModeViewModel.kt
@@ -27,7 +27,6 @@
 import android.util.Log
 import android.view.accessibility.AccessibilityEvent
 import android.view.accessibility.AccessibilityManager
-import androidx.activity.result.ActivityResultLauncher
 import com.android.internal.logging.UiEventLogger
 import com.android.systemui.communal.dagger.CommunalModule.Companion.LAUNCHER_PACKAGE
 import com.android.systemui.communal.data.model.CommunalWidgetCategories
@@ -107,9 +106,9 @@
         allOf(
                 keyguardTransitionInteractor.isFinishedIn(
                     scene = Scenes.Gone,
-                    stateWithoutSceneContainer = KeyguardState.GONE
+                    stateWithoutSceneContainer = KeyguardState.GONE,
                 ),
-                communalInteractor.editModeOpen
+                communalInteractor.editModeOpen,
             )
             .filter { it }
 
@@ -128,17 +127,13 @@
         componentName: ComponentName,
         user: UserHandle,
         rank: Int?,
-        configurator: WidgetConfigurator?
+        configurator: WidgetConfigurator?,
     ) {
         communalInteractor.addWidget(componentName, user, rank, configurator)
         metricsLogger.logAddWidget(componentName.flattenToString(), rank)
     }
 
-    override fun onDeleteWidget(
-        id: Int,
-        componentName: ComponentName,
-        rank: Int,
-    ) {
+    override fun onDeleteWidget(id: Int, componentName: ComponentName, rank: Int) {
         communalInteractor.deleteWidget(id)
         metricsLogger.logRemoveWidget(componentName.flattenToString(), rank)
     }
@@ -146,6 +141,10 @@
     override fun onReorderWidgets(widgetIdToRankMap: Map<Int, Int>) =
         communalInteractor.updateWidgetOrder(widgetIdToRankMap)
 
+    override fun onResizeWidget(appWidgetId: Int, spanY: Int, widgetIdToRankMap: Map<Int, Int>) {
+        communalInteractor.resizeWidget(appWidgetId, spanY, widgetIdToRankMap)
+    }
+
     override fun onReorderWidgetStart() {
         // Clear selection status
         setSelectedKey(null)
@@ -173,7 +172,7 @@
         val announcementText =
             context.getString(
                 R.string.accessibility_announcement_communal_widget_added,
-                widgetLabel
+                widgetLabel,
             )
         accessibilityManager.sendAccessibilityEvent(
             AccessibilityEvent(AccessibilityEvent.TYPE_ANNOUNCEMENT).apply {
@@ -184,10 +183,10 @@
 
     val isIdleOnCommunal: StateFlow<Boolean> = communalInteractor.isIdleOnCommunal
 
-    /** Launch the widget picker activity using the given {@link ActivityResultLauncher}. */
+    /** Launch the widget picker activity using the given startActivity method. */
     suspend fun onOpenWidgetPicker(
         resources: Resources,
-        activityLauncher: ActivityResultLauncher<Intent>
+        startActivity: (intent: Intent) -> Unit,
     ): Boolean =
         withContext(backgroundDispatcher) {
             val widgets = communalInteractor.widgetContent.first()
@@ -199,7 +198,7 @@
                 }
             getWidgetPickerActivityIntent(resources, excludeList)?.let {
                 try {
-                    activityLauncher.launch(it)
+                    startActivity(it)
                     return@withContext true
                 } catch (e: Exception) {
                     Log.e(TAG, "Failed to launch widget picker activity", e)
@@ -210,21 +209,21 @@
 
     private fun getWidgetPickerActivityIntent(
         resources: Resources,
-        excludeList: ArrayList<AppWidgetProviderInfo>
+        excludeList: ArrayList<AppWidgetProviderInfo>,
     ): Intent? {
         return Intent(Intent.ACTION_PICK).apply {
             setPackage(launcherPackage)
             putExtra(
                 EXTRA_DESIRED_WIDGET_WIDTH,
-                resources.getDimensionPixelSize(R.dimen.communal_widget_picker_desired_width)
+                resources.getDimensionPixelSize(R.dimen.communal_widget_picker_desired_width),
             )
             putExtra(
                 EXTRA_DESIRED_WIDGET_HEIGHT,
-                resources.getDimensionPixelSize(R.dimen.communal_widget_picker_desired_height)
+                resources.getDimensionPixelSize(R.dimen.communal_widget_picker_desired_height),
             )
             putExtra(
                 AppWidgetManager.EXTRA_CATEGORY_FILTER,
-                CommunalWidgetCategories.defaultCategories
+                CommunalWidgetCategories.defaultCategories,
             )
 
             communalSettingsInteractor.workProfileUserDisallowedByDevicePolicy.value?.let {
@@ -234,7 +233,7 @@
             putExtra(EXTRA_PICKER_TITLE, resources.getString(R.string.communal_widget_picker_title))
             putExtra(
                 EXTRA_PICKER_DESCRIPTION,
-                resources.getString(R.string.communal_widget_picker_description)
+                resources.getString(R.string.communal_widget_picker_description),
             )
             putParcelableArrayListExtra(EXTRA_ADDED_APP_WIDGETS_KEY, excludeList)
         }
diff --git a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/ResizeableItemFrameViewModel.kt b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/ResizeableItemFrameViewModel.kt
index 7aad33d..87fcdd7 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/ResizeableItemFrameViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/ResizeableItemFrameViewModel.kt
@@ -25,8 +25,7 @@
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.MutableStateFlow
 import kotlinx.coroutines.flow.distinctUntilChanged
-import kotlinx.coroutines.flow.dropWhile
-import kotlinx.coroutines.flow.filterNotNull
+import kotlinx.coroutines.flow.filter
 import kotlinx.coroutines.flow.launchIn
 import kotlinx.coroutines.flow.map
 import kotlinx.coroutines.flow.merge
@@ -45,7 +44,10 @@
     val spans: Int,
     /** The drag handle which was used to resize the element. */
     val fromHandle: DragHandle,
-)
+) {
+    /** Whether we are expanding. If false, then we are shrinking. */
+    val isExpanding = spans > 0
+}
 
 class ResizeableItemFrameViewModel : ExclusiveActivatable() {
     private data class GridLayoutInfo(
@@ -73,7 +75,7 @@
                 snapshotFlow { bottomDragState.settledValue }
                     .map { ResizeInfo(it, DragHandle.BOTTOM) },
             )
-            .dropWhile { it.spans == 0 }
+            .filter { it.spans != 0 }
             .distinctUntilChanged()
 
     /**
@@ -86,9 +88,13 @@
         viewportHeightPx: Int,
         maxItemSpan: Int,
         minItemSpan: Int,
-        currentRow: Int,
-        currentSpan: Int,
+        currentRow: Int?,
+        currentSpan: Int?,
     ) {
+        if (currentSpan == null || currentRow == null) {
+            gridLayoutInfo.value = null
+            return
+        }
         require(maxItemSpan >= minItemSpan) {
             "Maximum item span of $maxItemSpan cannot be less than the minimum span of $minItemSpan"
         }
@@ -114,10 +120,10 @@
 
     private fun calculateAnchorsForHandle(
         handle: DragHandle,
-        layoutInfo: GridLayoutInfo,
+        layoutInfo: GridLayoutInfo?,
     ): DraggableAnchors<Int> {
 
-        if (!isDragAllowed(handle, layoutInfo)) {
+        if (layoutInfo == null || !isDragAllowed(handle, layoutInfo)) {
             return DraggableAnchors { 0 at 0f }
         }
 
@@ -188,7 +194,6 @@
     override suspend fun onActivated(): Nothing {
         coroutineScope("ResizeableItemFrameViewModel.onActivated") {
             gridLayoutInfo
-                .filterNotNull()
                 .onEach { layoutInfo ->
                     topDragState.updateAnchors(
                         calculateAnchorsForHandle(DragHandle.TOP, layoutInfo)
diff --git a/packages/SystemUI/src/com/android/systemui/communal/util/WidgetViewFactory.kt b/packages/SystemUI/src/com/android/systemui/communal/util/WidgetViewFactory.kt
index cafa74f..07a7c7cb 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/util/WidgetViewFactory.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/util/WidgetViewFactory.kt
@@ -43,7 +43,7 @@
     suspend fun createWidget(
         context: Context,
         model: CommunalContentModel.WidgetContent.Widget,
-        size: SizeF,
+        size: SizeF?,
     ): CommunalAppWidgetHostView =
         withContext("$TAG#createWidget", uiBgContext) {
             val view =
@@ -54,14 +54,16 @@
             // Instead of setting the view as the listener directly, we wrap the view in a delegate
             // which ensures the callbacks always get called on the main thread.
             appWidgetHost.setListener(model.appWidgetId, listenerFactory.create(view))
-            view.updateAppWidgetSize(
-                /* newOptions = */ Bundle(),
-                /* minWidth = */ size.width.toInt(),
-                /* minHeight = */ size.height.toInt(),
-                /* maxWidth = */ size.width.toInt(),
-                /* maxHeight = */ size.height.toInt(),
-                /* ignorePadding = */ true,
-            )
+            if (size != null) {
+                view.updateAppWidgetSize(
+                    /* newOptions = */ Bundle(),
+                    /* minWidth = */ size.width.toInt(),
+                    /* minHeight = */ size.height.toInt(),
+                    /* maxWidth = */ size.width.toInt(),
+                    /* maxHeight = */ size.height.toInt(),
+                    /* ignorePadding = */ true,
+                )
+            }
             view
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/communal/widgets/EditWidgetsActivity.kt b/packages/SystemUI/src/com/android/systemui/communal/widgets/EditWidgetsActivity.kt
index 13b4aa9..8c14d63 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/widgets/EditWidgetsActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/widgets/EditWidgetsActivity.kt
@@ -27,14 +27,12 @@
 import android.view.WindowInsets
 import androidx.activity.ComponentActivity
 import androidx.activity.compose.setContent
-import androidx.activity.result.ActivityResultLauncher
-import androidx.activity.result.contract.ActivityResultContracts.StartActivityForResult
 import androidx.compose.foundation.background
 import androidx.compose.foundation.layout.Box
 import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.material3.MaterialTheme
 import androidx.compose.ui.Modifier
 import androidx.lifecycle.lifecycleScope
-import com.android.compose.theme.LocalAndroidColorScheme
 import com.android.compose.theme.PlatformTheme
 import com.android.internal.logging.UiEventLogger
 import com.android.systemui.Flags.communalEditWidgetsActivityFinishFix
@@ -51,6 +49,7 @@
 import com.android.systemui.log.core.Logger
 import com.android.systemui.log.dagger.CommunalLog
 import com.android.systemui.scene.shared.flag.SceneContainerFlag
+import com.android.systemui.settings.UserTracker
 import javax.inject.Inject
 import kotlinx.coroutines.flow.first
 import kotlinx.coroutines.launch
@@ -64,12 +63,15 @@
     private val uiEventLogger: UiEventLogger,
     private val widgetConfiguratorFactory: WidgetConfigurationController.Factory,
     private val widgetSection: CommunalAppWidgetSection,
+    private val userTracker: UserTracker,
     @CommunalLog logBuffer: LogBuffer,
 ) : ComponentActivity() {
     companion object {
         private const val TAG = "EditWidgetsActivity"
         private const val EXTRA_IS_PENDING_WIDGET_DRAG = "is_pending_widget_drag"
         const val EXTRA_OPEN_WIDGET_PICKER_ON_START = "open_widget_picker_on_start"
+
+        private const val REQUEST_CODE_WIDGET_PICKER = 200
     }
 
     /**
@@ -110,7 +112,7 @@
                 object : ActivityLifecycleCallbacks {
                     override fun onActivityCreated(
                         activity: Activity,
-                        savedInstanceState: Bundle?
+                        savedInstanceState: Bundle?,
                     ) {
                         waitingForResult =
                             savedInstanceState?.getBoolean(STATE_EXTRA_IS_WAITING_FOR_RESULT)
@@ -172,41 +174,6 @@
         if (communalEditWidgetsActivityFinishFix()) ActivityControllerImpl(this)
         else NopActivityController()
 
-    private val addWidgetActivityLauncher: ActivityResultLauncher<Intent> =
-        registerForActivityResult(StartActivityForResult()) { result ->
-            when (result.resultCode) {
-                RESULT_OK -> {
-                    uiEventLogger.log(CommunalUiEvent.COMMUNAL_HUB_WIDGET_PICKER_SHOWN)
-
-                    result.data?.let { intent ->
-                        val isPendingWidgetDrag =
-                            intent.getBooleanExtra(EXTRA_IS_PENDING_WIDGET_DRAG, false)
-                        // Nothing to do when a widget is being dragged & dropped. The drop
-                        // target in the communal grid will receive the widget to be added (if
-                        // the user drops it over).
-                        if (!isPendingWidgetDrag) {
-                            val (componentName, user) = getWidgetExtraFromIntent(intent)
-                            if (componentName != null && user != null) {
-                                // Add widget at the end.
-                                communalViewModel.onAddWidget(
-                                    componentName,
-                                    user,
-                                    configurator = widgetConfigurator,
-                                )
-                            } else {
-                                run { Log.w(TAG, "No AppWidgetProviderInfo found in result.") }
-                            }
-                        }
-                    } ?: run { Log.w(TAG, "No data in result.") }
-                }
-                else ->
-                    Log.w(
-                        TAG,
-                        "Failed to receive result from widget picker, code=${result.resultCode}"
-                    )
-            }
-        }
-
     override fun onCreate(savedInstanceState: Bundle?) {
         super.onCreate(savedInstanceState)
 
@@ -226,8 +193,7 @@
             PlatformTheme {
                 Box(
                     modifier =
-                        Modifier.fillMaxSize()
-                            .background(LocalAndroidColorScheme.current.surfaceDim),
+                        Modifier.fillMaxSize().background(MaterialTheme.colorScheme.surfaceDim)
                 ) {
                     CommunalHub(
                         viewModel = communalViewModel,
@@ -274,7 +240,13 @@
 
     private fun onOpenWidgetPicker() {
         lifecycleScope.launch {
-            communalViewModel.onOpenWidgetPicker(resources, addWidgetActivityLauncher)
+            communalViewModel.onOpenWidgetPicker(resources) { intent: Intent ->
+                startActivityForResultAsUser(
+                    intent,
+                    REQUEST_CODE_WIDGET_PICKER,
+                    userTracker.userHandle,
+                )
+            }
         }
     }
 
@@ -285,7 +257,7 @@
             communalViewModel.changeScene(
                 scene = CommunalScenes.Communal,
                 loggingReason = "edit mode closing",
-                transitionKey = CommunalTransitionKeys.FromEditMode
+                transitionKey = CommunalTransitionKeys.FromEditMode,
             )
 
             // Wait for the current scene to be idle on communal.
@@ -309,7 +281,7 @@
         flagsMask: Int,
         flagsValues: Int,
         extraFlags: Int,
-        options: Bundle?
+        options: Bundle?,
     ) {
         activityController.onWaitingForResult(true)
         super.startIntentSenderForResult(
@@ -319,15 +291,46 @@
             flagsMask,
             flagsValues,
             extraFlags,
-            options
+            options,
         )
     }
 
     override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
         activityController.onWaitingForResult(false)
         super.onActivityResult(requestCode, resultCode, data)
-        if (requestCode == WidgetConfigurationController.REQUEST_CODE) {
-            widgetConfigurator.setConfigurationResult(resultCode)
+
+        when (requestCode) {
+            WidgetConfigurationController.REQUEST_CODE ->
+                widgetConfigurator.setConfigurationResult(resultCode)
+            REQUEST_CODE_WIDGET_PICKER -> {
+                if (resultCode != RESULT_OK) {
+                    Log.w(TAG, "Failed to receive result from widget picker, code=$resultCode")
+                    return
+                }
+
+                uiEventLogger.log(CommunalUiEvent.COMMUNAL_HUB_WIDGET_PICKER_SHOWN)
+
+                data?.let { intent ->
+                    val isPendingWidgetDrag =
+                        intent.getBooleanExtra(EXTRA_IS_PENDING_WIDGET_DRAG, false)
+                    // Nothing to do when a widget is being dragged & dropped. The drop
+                    // target in the communal grid will receive the widget to be added (if
+                    // the user drops it over).
+                    if (!isPendingWidgetDrag) {
+                        val (componentName, user) = getWidgetExtraFromIntent(intent)
+                        if (componentName != null && user != null) {
+                            // Add widget at the end.
+                            communalViewModel.onAddWidget(
+                                componentName,
+                                user,
+                                configurator = widgetConfigurator,
+                            )
+                        } else {
+                            run { Log.w(TAG, "No AppWidgetProviderInfo found in result.") }
+                        }
+                    }
+                } ?: run { Log.w(TAG, "No data in result.") }
+            }
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/SystemUIDeviceEntryFaceAuthInteractor.kt b/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/SystemUIDeviceEntryFaceAuthInteractor.kt
index 3b5d5a8..b19b2d9 100644
--- a/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/SystemUIDeviceEntryFaceAuthInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/SystemUIDeviceEntryFaceAuthInteractor.kt
@@ -114,7 +114,7 @@
                 faceAuthenticationLogger.bouncerVisibilityChanged()
                 runFaceAuth(
                     FaceAuthUiEvent.FACE_AUTH_UPDATED_PRIMARY_BOUNCER_SHOWN,
-                    fallbackToDetect = false
+                    fallbackToDetect = false,
                 )
             }
             .launchIn(applicationScope)
@@ -125,7 +125,7 @@
                 faceAuthenticationLogger.alternateBouncerVisibilityChanged()
                 runFaceAuth(
                     FaceAuthUiEvent.FACE_AUTH_TRIGGERED_ALTERNATE_BIOMETRIC_BOUNCER_SHOWN,
-                    fallbackToDetect = false
+                    fallbackToDetect = false,
                 )
             }
             .launchIn(applicationScope)
@@ -153,7 +153,7 @@
                     it.lastWakeReason.powerManagerWakeReason
                 runFaceAuth(
                     FaceAuthUiEvent.FACE_AUTH_UPDATED_KEYGUARD_VISIBILITY_CHANGED,
-                    fallbackToDetect = true
+                    fallbackToDetect = true,
                 )
             }
             .launchIn(applicationScope)
@@ -193,13 +193,16 @@
             .map { (_, curr) -> curr.userInfo.id }
             .sample(isBouncerVisible, ::Pair)
             .onEach { (userId, isBouncerCurrentlyVisible) ->
+                if (!isFaceAuthEnabledAndEnrolled()) {
+                    return@onEach
+                }
                 resetLockedOutState(userId)
                 yield()
                 runFaceAuth(
                     FaceAuthUiEvent.FACE_AUTH_UPDATED_USER_SWITCHING,
                     // Fallback to detection if bouncer is not showing so that we can detect a
                     // face and then show the bouncer to the user if face auth can't run
-                    fallbackToDetect = !isBouncerCurrentlyVisible
+                    fallbackToDetect = !isBouncerCurrentlyVisible,
                 )
             }
             .launchIn(applicationScope)
@@ -210,7 +213,7 @@
                     repository.cancel()
                     runFaceAuth(
                         FaceAuthUiEvent.FACE_AUTH_CAMERA_AVAILABLE_CHANGED,
-                        fallbackToDetect = true
+                        fallbackToDetect = true,
                     )
                 }
             }
@@ -321,7 +324,7 @@
             faceAuthenticationStatusOverride.value =
                 ErrorFaceAuthenticationStatus(
                     BiometricFaceConstants.FACE_ERROR_LOCKOUT_PERMANENT,
-                    context.resources.getString(R.string.keyguard_face_unlock_unavailable)
+                    context.resources.getString(R.string.keyguard_face_unlock_unavailable),
                 )
         } else {
             faceAuthenticationStatusOverride.value = null
diff --git a/packages/SystemUI/src/com/android/systemui/display/DisplayModule.kt b/packages/SystemUI/src/com/android/systemui/display/DisplayModule.kt
index 462e820..589dbf9 100644
--- a/packages/SystemUI/src/com/android/systemui/display/DisplayModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/display/DisplayModule.kt
@@ -16,16 +16,27 @@
 
 package com.android.systemui.display
 
+import com.android.systemui.CoreStartable
+import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.display.data.repository.DeviceStateRepository
 import com.android.systemui.display.data.repository.DeviceStateRepositoryImpl
 import com.android.systemui.display.data.repository.DisplayRepository
 import com.android.systemui.display.data.repository.DisplayRepositoryImpl
+import com.android.systemui.display.data.repository.DisplayScopeRepository
+import com.android.systemui.display.data.repository.DisplayScopeRepositoryImpl
+import com.android.systemui.display.data.repository.DisplayWindowPropertiesRepository
+import com.android.systemui.display.data.repository.DisplayWindowPropertiesRepositoryImpl
 import com.android.systemui.display.data.repository.FocusedDisplayRepository
 import com.android.systemui.display.data.repository.FocusedDisplayRepositoryImpl
 import com.android.systemui.display.domain.interactor.ConnectedDisplayInteractor
 import com.android.systemui.display.domain.interactor.ConnectedDisplayInteractorImpl
+import com.android.systemui.statusbar.core.StatusBarConnectedDisplays
 import dagger.Binds
+import dagger.Lazy
 import dagger.Module
+import dagger.Provides
+import dagger.multibindings.ClassKey
+import dagger.multibindings.IntoMap
 
 /** Module binding display related classes. */
 @Module
@@ -46,4 +57,41 @@
     fun bindsFocusedDisplayRepository(
         focusedDisplayRepository: FocusedDisplayRepositoryImpl
     ): FocusedDisplayRepository
+
+    @Binds fun displayScopeRepository(impl: DisplayScopeRepositoryImpl): DisplayScopeRepository
+
+    @Binds
+    fun displayWindowPropertiesRepository(
+        impl: DisplayWindowPropertiesRepositoryImpl
+    ): DisplayWindowPropertiesRepository
+
+    companion object {
+        @Provides
+        @SysUISingleton
+        @IntoMap
+        @ClassKey(DisplayScopeRepositoryImpl::class)
+        fun displayScopeRepoCoreStartable(
+            repoImplLazy: Lazy<DisplayScopeRepositoryImpl>
+        ): CoreStartable {
+            return if (StatusBarConnectedDisplays.isEnabled) {
+                repoImplLazy.get()
+            } else {
+                CoreStartable.NOP
+            }
+        }
+
+        @Provides
+        @SysUISingleton
+        @IntoMap
+        @ClassKey(DisplayWindowPropertiesRepository::class)
+        fun displayWindowPropertiesRepoAsCoreStartable(
+            repoLazy: Lazy<DisplayWindowPropertiesRepositoryImpl>
+        ): CoreStartable {
+            return if (StatusBarConnectedDisplays.isEnabled) {
+                return repoLazy.get()
+            } else {
+                CoreStartable.NOP
+            }
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayRepository.kt b/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayRepository.kt
index e68aba5..6a69136 100644
--- a/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayRepository.kt
@@ -61,8 +61,11 @@
     /** Display addition event indicating a new display has been added. */
     val displayAdditionEvent: Flow<Display?>
 
+    /** Display removal event indicating a display has been removed. */
+    val displayRemovalEvent: Flow<Int>
+
     /** Provides the current set of displays. */
-    val displays: Flow<Set<Display>>
+    val displays: StateFlow<Set<Display>>
 
     /**
      * Pending display id that can be enabled/disabled.
@@ -79,8 +82,8 @@
      *
      * This method is guaranteed to not result in any binder call.
      */
-    suspend fun getDisplay(displayId: Int): Display? =
-        displays.first().firstOrNull { it.displayId == displayId }
+    fun getDisplay(displayId: Int): Display? =
+        displays.value.firstOrNull { it.displayId == displayId }
 
     /** Represents a connected display that has not been enabled yet. */
     interface PendingDisplay {
@@ -148,6 +151,9 @@
             getDisplayFromDisplayManager(it.displayId)
         }
 
+    override val displayRemovalEvent: Flow<Int> =
+        allDisplayEvents.filterIsInstance<DisplayEvent.Removed>().map { it.displayId }
+
     // This is necessary because there might be multiple displays, and we could
     // have missed events for those added before this process or flow started.
     // Note it causes a binder call from the main thread (it's traced).
@@ -180,7 +186,7 @@
      *
      * Those are commonly the ones provided by [DisplayManager.getDisplays] by default.
      */
-    private val enabledDisplays: Flow<Set<Display>> =
+    private val enabledDisplays: StateFlow<Set<Display>> =
         enabledDisplayIds
             .mapElementsLazily { displayId -> getDisplayFromDisplayManager(displayId) }
             .onEach {
@@ -204,7 +210,7 @@
      *
      * Those are commonly the ones provided by [DisplayManager.getDisplays] by default.
      */
-    override val displays: Flow<Set<Display>> = enabledDisplays
+    override val displays: StateFlow<Set<Display>> = enabledDisplays
 
     val _ignoredDisplayIds = MutableStateFlow<Set<Int>>(emptySet())
     private val ignoredDisplayIds: Flow<Set<Int>> = _ignoredDisplayIds.debugLog("ignoredDisplayIds")
diff --git a/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayScopeRepository.kt b/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayScopeRepository.kt
new file mode 100644
index 0000000..3062475
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayScopeRepository.kt
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.display.data.repository
+
+import android.view.Display
+import com.android.app.tracing.coroutines.createCoroutineTracingContext
+import com.android.systemui.CoreStartable
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.statusbar.core.StatusBarConnectedDisplays
+import java.util.concurrent.ConcurrentHashMap
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.cancel
+import kotlinx.coroutines.launch
+
+/**
+ * Provides per display instances of [CoroutineScope]. These will remain active as long as the
+ * display is connected, and automatically cancelled when the display is removed.
+ */
+interface DisplayScopeRepository {
+    fun scopeForDisplay(displayId: Int): CoroutineScope
+}
+
+@SysUISingleton
+class DisplayScopeRepositoryImpl
+@Inject
+constructor(
+    @Background private val backgroundApplicationScope: CoroutineScope,
+    @Background private val backgroundDispatcher: CoroutineDispatcher,
+    private val displayRepository: DisplayRepository,
+) : DisplayScopeRepository, CoreStartable {
+
+    private val perDisplayScopes = ConcurrentHashMap<Int, CoroutineScope>()
+
+    override fun scopeForDisplay(displayId: Int): CoroutineScope {
+        return perDisplayScopes.computeIfAbsent(displayId) { createScopeForDisplay(displayId) }
+    }
+
+    override fun start() {
+        StatusBarConnectedDisplays.assertInNewMode()
+        backgroundApplicationScope.launch {
+            displayRepository.displayRemovalEvent.collect { displayId ->
+                val scope = perDisplayScopes.remove(displayId)
+                scope?.cancel("Display $displayId has been removed.")
+            }
+        }
+    }
+
+    private fun createScopeForDisplay(displayId: Int): CoroutineScope {
+        return if (displayId == Display.DEFAULT_DISPLAY) {
+            // The default display is connected all the time, therefore we can optimise by reusing
+            // the application scope, and don't need to create a new scope.
+            backgroundApplicationScope
+        } else {
+            CoroutineScope(
+                backgroundDispatcher + createCoroutineTracingContext("DisplayScope$displayId")
+            )
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayWindowPropertiesRepository.kt b/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayWindowPropertiesRepository.kt
new file mode 100644
index 0000000..88d3a28
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayWindowPropertiesRepository.kt
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.display.data.repository
+
+import android.annotation.SuppressLint
+import android.content.Context
+import android.view.Display
+import android.view.WindowManager
+import com.android.systemui.CoreStartable
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.display.shared.model.DisplayWindowProperties
+import com.android.systemui.res.R
+import com.android.systemui.statusbar.core.StatusBarConnectedDisplays
+import com.google.common.collect.HashBasedTable
+import com.google.common.collect.Table
+import java.io.PrintWriter
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineName
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.launch
+
+/** Provides per display instances of [DisplayWindowProperties]. */
+interface DisplayWindowPropertiesRepository {
+
+    /**
+     * Returns a [DisplayWindowProperties] instance for a given display id and window type.
+     *
+     * @throws IllegalArgumentException if no display with the given display id exists.
+     */
+    fun get(
+        displayId: Int,
+        @WindowManager.LayoutParams.WindowType windowType: Int,
+    ): DisplayWindowProperties
+}
+
+@SysUISingleton
+class DisplayWindowPropertiesRepositoryImpl
+@Inject
+constructor(
+    @Background private val backgroundApplicationScope: CoroutineScope,
+    private val globalContext: Context,
+    private val globalWindowManager: WindowManager,
+    private val displayRepository: DisplayRepository,
+) : DisplayWindowPropertiesRepository, CoreStartable {
+
+    init {
+        StatusBarConnectedDisplays.assertInNewMode()
+    }
+
+    private val properties: Table<Int, Int, DisplayWindowProperties> = HashBasedTable.create()
+
+    override fun get(
+        displayId: Int,
+        @WindowManager.LayoutParams.WindowType windowType: Int,
+    ): DisplayWindowProperties {
+        val display =
+            displayRepository.getDisplay(displayId)
+                ?: throw IllegalArgumentException("Display with id $displayId doesn't exist")
+        return properties.get(displayId, windowType)
+            ?: create(display, windowType).also { properties.put(displayId, windowType, it) }
+    }
+
+    override fun start() {
+        backgroundApplicationScope.launch(
+            CoroutineName("DisplayWindowPropertiesRepositoryImpl#start")
+        ) {
+            displayRepository.displayRemovalEvent.collect { removedDisplayId ->
+                properties.row(removedDisplayId).clear()
+            }
+        }
+    }
+
+    private fun create(display: Display, windowType: Int): DisplayWindowProperties {
+        val displayId = display.displayId
+        return if (displayId == Display.DEFAULT_DISPLAY) {
+            // For the default display, we can just reuse the global/application properties.
+            // Creating a window context is expensive, therefore we avoid it.
+            DisplayWindowProperties(
+                displayId = displayId,
+                windowType = windowType,
+                context = globalContext,
+                windowManager = globalWindowManager,
+            )
+        } else {
+            val context = createWindowContext(display, windowType)
+            @SuppressLint("NonInjectedService") // Need to manually get the service
+            val windowManager = context.getSystemService(WindowManager::class.java) as WindowManager
+            DisplayWindowProperties(displayId, windowType, context, windowManager)
+        }
+    }
+
+    private fun createWindowContext(display: Display, windowType: Int): Context =
+        globalContext.createWindowContext(display, windowType, /* options= */ null).also {
+            it.setTheme(R.style.Theme_SystemUI)
+        }
+
+    override fun dump(pw: PrintWriter, args: Array<out String>) {
+        pw.write("perDisplayContexts: $properties")
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/display/shared/model/DisplayWindowProperties.kt b/packages/SystemUI/src/com/android/systemui/display/shared/model/DisplayWindowProperties.kt
new file mode 100644
index 0000000..6acc296
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/display/shared/model/DisplayWindowProperties.kt
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.display.shared.model
+
+import android.content.Context
+import android.view.WindowManager
+
+/** Represents a display specific group of window related properties. */
+data class DisplayWindowProperties(
+    /** The id of the display associated with this instance. */
+    val displayId: Int,
+    /**
+     * The window type that was used to create the [Context] in this instance, using
+     * [Context.createWindowContext]. This is the window type that can be used when adding views to
+     * the [WindowManager] associated with this instance.
+     */
+    @WindowManager.LayoutParams.WindowType val windowType: Int,
+    /**
+     * The display specific [Context] created using [Context.createWindowContext] with window type
+     * associated with this instance.
+     */
+    val context: Context,
+
+    /**
+     * The display specific [WindowManager] instance to be used when adding windows of the type
+     * associated with this instance.
+     */
+    val windowManager: WindowManager,
+)
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayCallbackController.kt b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayCallbackController.kt
index d5ff8f2..2b61752 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayCallbackController.kt
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayCallbackController.kt
@@ -39,8 +39,10 @@
     }
 
     fun onWakeUp() {
-        isDreaming = false
-        callbacks.forEach { it.onWakeUp() }
+        if (isDreaming) {
+            isDreaming = false
+            callbacks.forEach { it.onWakeUp() }
+        }
     }
 
     fun onStartDream() {
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java
index 83f86a7..7a6ca08 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java
@@ -297,6 +297,8 @@
             mStateController.setLowLightActive(false);
             mStateController.setEntryAnimationsFinished(false);
 
+            mDreamOverlayCallbackController.onWakeUp();
+
             if (mDreamOverlayContainerViewController != null) {
                 mDreamOverlayContainerViewController.destroy();
                 mDreamOverlayContainerViewController = null;
diff --git a/packages/SystemUI/src/com/android/systemui/education/domain/interactor/KeyboardTouchpadEduStatsInteractor.kt b/packages/SystemUI/src/com/android/systemui/education/domain/interactor/KeyboardTouchpadEduStatsInteractor.kt
index 0e2d9b6..43e39cf 100644
--- a/packages/SystemUI/src/com/android/systemui/education/domain/interactor/KeyboardTouchpadEduStatsInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/education/domain/interactor/KeyboardTouchpadEduStatsInteractor.kt
@@ -30,7 +30,7 @@
 import java.time.Clock
 import javax.inject.Inject
 import kotlin.time.Duration
-import kotlin.time.Duration.Companion.hours
+import kotlin.time.Duration.Companion.days
 import kotlin.time.DurationUnit
 import kotlin.time.toDuration
 import kotlinx.coroutines.CoroutineScope
@@ -64,7 +64,7 @@
             get() =
                 SystemProperties.getLong(
                         "persist.contextual_edu.initial_delay_sec",
-                        /* defaultValue= */ 72.hours.inWholeSeconds
+                        /* defaultValue= */ 7.days.inWholeSeconds,
                     )
                     .toDuration(DurationUnit.SECONDS)
     }
diff --git a/packages/SystemUI/src/com/android/systemui/education/ui/view/ContextualEduDialog.kt b/packages/SystemUI/src/com/android/systemui/education/ui/view/ContextualEduDialog.kt
index 287e85c..ca92953 100644
--- a/packages/SystemUI/src/com/android/systemui/education/ui/view/ContextualEduDialog.kt
+++ b/packages/SystemUI/src/com/android/systemui/education/ui/view/ContextualEduDialog.kt
@@ -16,32 +16,40 @@
 
 package com.android.systemui.education.ui.view
 
-import android.app.AlertDialog
+import android.app.Dialog
 import android.content.Context
 import android.os.Bundle
 import android.view.Gravity
+import android.view.Window
 import android.view.WindowManager
-import android.widget.ToastPresenter
+import android.widget.ImageView
+import android.widget.TextView
 import com.android.systemui.education.ui.viewmodel.ContextualEduToastViewModel
 import com.android.systemui.res.R
 
 class ContextualEduDialog(context: Context, private val model: ContextualEduToastViewModel) :
-    AlertDialog(context, R.style.ContextualEduDialog) {
+    Dialog(context) {
     override fun onCreate(savedInstanceState: Bundle?) {
         setUpWindowProperties()
         setWindowPosition()
         // title is used for a11y announcement
         window?.setTitle(context.getString(R.string.contextual_education_dialog_title))
-        // TODO: b/369791926 - replace the below toast view with a custom dialog view
-        val toastView = ToastPresenter.getTextToastView(context, model.message)
-        setView(toastView)
+        setContentView(R.layout.contextual_edu_dialog)
+        setContent()
         super.onCreate(savedInstanceState)
     }
 
+    private fun setContent() {
+        findViewById<TextView>(R.id.edu_message)?.let { it.text = model.message }
+        findViewById<ImageView>(R.id.edu_icon)?.let { it.setImageResource(model.icon) }
+    }
+
     private fun setUpWindowProperties() {
         window?.apply {
+            requestFeature(Window.FEATURE_NO_TITLE)
             setType(WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG)
             clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND)
+            setBackgroundDrawableResource(android.R.color.transparent)
         }
         setCanceledOnTouchOutside(false)
     }
diff --git a/packages/SystemUI/src/com/android/systemui/education/ui/viewmodel/ContextualEduContentViewModel.kt b/packages/SystemUI/src/com/android/systemui/education/ui/viewmodel/ContextualEduContentViewModel.kt
index 632b250..5a02cda 100644
--- a/packages/SystemUI/src/com/android/systemui/education/ui/viewmodel/ContextualEduContentViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/education/ui/viewmodel/ContextualEduContentViewModel.kt
@@ -21,8 +21,11 @@
 data class ContextualEduNotificationViewModel(
     val title: String,
     val message: String,
-    override val userId: Int
+    override val userId: Int,
 ) : ContextualEduContentViewModel(userId)
 
-data class ContextualEduToastViewModel(val message: String, override val userId: Int) :
-    ContextualEduContentViewModel(userId)
+data class ContextualEduToastViewModel(
+    val message: String,
+    val icon: Int,
+    override val userId: Int,
+) : ContextualEduContentViewModel(userId)
diff --git a/packages/SystemUI/src/com/android/systemui/education/ui/viewmodel/ContextualEduViewModel.kt b/packages/SystemUI/src/com/android/systemui/education/ui/viewmodel/ContextualEduViewModel.kt
index 5563969..7417a70 100644
--- a/packages/SystemUI/src/com/android/systemui/education/ui/viewmodel/ContextualEduViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/education/ui/viewmodel/ContextualEduViewModel.kt
@@ -71,7 +71,7 @@
                         it.userId,
                     )
                 } else {
-                    ContextualEduToastViewModel(getEduContent(it), it.userId)
+                    ContextualEduToastViewModel(getEduContent(it), getEduIcon(it), it.userId)
                 }
             }
             .timeout(timeoutMillis, emitAfterTimeout = null)
@@ -118,4 +118,13 @@
 
         return resources.getString(resourceId)
     }
+
+    private fun getEduIcon(educationInfo: EducationInfo): Int {
+        return when (educationInfo.gestureType) {
+            BACK -> R.drawable.contextual_edu_swipe_back
+            HOME,
+            OVERVIEW -> R.drawable.contextual_edu_swipe_up
+            ALL_APPS -> R.drawable.contextual_edu_all_apps
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/haptics/msdl/MSDLCoreStartable.kt b/packages/SystemUI/src/com/android/systemui/haptics/msdl/MSDLCoreStartable.kt
index 58736c60..0c9fadd 100644
--- a/packages/SystemUI/src/com/android/systemui/haptics/msdl/MSDLCoreStartable.kt
+++ b/packages/SystemUI/src/com/android/systemui/haptics/msdl/MSDLCoreStartable.kt
@@ -28,7 +28,8 @@
     override fun start() {}
 
     override fun dump(pw: PrintWriter, args: Array<out String>) {
-        pw.println("MSDLPlayer history of the last ${MSDLHistoryLogger.HISTORY_SIZE} events:")
+        pw.println(msdlPlayer)
+        pw.println("MSDL player history of the last ${MSDLHistoryLogger.HISTORY_SIZE} events:")
         msdlPlayer.getHistory().forEach { event -> pw.println("$event") }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/haptics/msdl/dagger/MSDLModule.kt b/packages/SystemUI/src/com/android/systemui/haptics/msdl/dagger/MSDLModule.kt
index d2dc8c1..108d5b1 100644
--- a/packages/SystemUI/src/com/android/systemui/haptics/msdl/dagger/MSDLModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/haptics/msdl/dagger/MSDLModule.kt
@@ -17,10 +17,8 @@
 package com.android.systemui.haptics.msdl.dagger
 
 import android.annotation.SuppressLint
-import android.content.Context
-import android.os.VibratorManager
+import android.os.Vibrator
 import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.dagger.qualifiers.Application
 import com.google.android.msdl.domain.MSDLPlayer
 import dagger.Module
 import dagger.Provides
@@ -30,9 +28,5 @@
     @SuppressLint("NonInjectedService")
     @Provides
     @SysUISingleton
-    fun provideMSDLPlayer(@Application context: Context): MSDLPlayer {
-        val vibratorManager =
-            context.getSystemService(Context.VIBRATOR_MANAGER_SERVICE) as VibratorManager
-        return MSDLPlayer.createPlayer(vibratorManager.defaultVibrator)
-    }
+    fun provideMSDLPlayer(vibrator: Vibrator?): MSDLPlayer = MSDLPlayer.createPlayer(vibrator)
 }
diff --git a/packages/SystemUI/src/com/android/systemui/haptics/slider/SeekbarHapticPlugin.kt b/packages/SystemUI/src/com/android/systemui/haptics/slider/SeekbarHapticPlugin.kt
index 2007db34..932e5af 100644
--- a/packages/SystemUI/src/com/android/systemui/haptics/slider/SeekbarHapticPlugin.kt
+++ b/packages/SystemUI/src/com/android/systemui/haptics/slider/SeekbarHapticPlugin.kt
@@ -46,12 +46,24 @@
 
     private val velocityTracker = VelocityTracker.obtain()
 
+    private val dragVelocityProvider = SliderDragVelocityProvider {
+        velocityTracker.computeCurrentVelocity(
+            UNITS_SECOND,
+            sliderHapticFeedbackConfig.maxVelocityToScale,
+        )
+        if (velocityTracker.isAxisSupported(sliderHapticFeedbackConfig.velocityAxis)) {
+            velocityTracker.getAxisVelocity(sliderHapticFeedbackConfig.velocityAxis)
+        } else {
+            0f
+        }
+    }
+
     private val sliderEventProducer = SliderStateProducer()
 
     private val sliderHapticFeedbackProvider =
         SliderHapticFeedbackProvider(
             vibratorHelper,
-            velocityTracker,
+            dragVelocityProvider,
             sliderHapticFeedbackConfig,
             systemClock,
         )
@@ -188,5 +200,6 @@
 
     companion object {
         const val KEY_UP_TIMEOUT = 60L
+        private const val UNITS_SECOND = 1000
     }
 }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/FixedColumnsSizeInteractorKosmos.kt b/packages/SystemUI/src/com/android/systemui/haptics/slider/SliderDragVelocityProvider.kt
similarity index 63%
copy from packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/FixedColumnsSizeInteractorKosmos.kt
copy to packages/SystemUI/src/com/android/systemui/haptics/slider/SliderDragVelocityProvider.kt
index f4d281d..6829326 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/FixedColumnsSizeInteractorKosmos.kt
+++ b/packages/SystemUI/src/com/android/systemui/haptics/slider/SliderDragVelocityProvider.kt
@@ -14,10 +14,15 @@
  * limitations under the License.
  */
 
-package com.android.systemui.qs.panels.domain.interactor
+package com.android.systemui.haptics.slider
 
-import com.android.systemui.kosmos.Kosmos
-import com.android.systemui.qs.panels.data.repository.fixedColumnsRepository
+/** A provider of the velocity at which a slider is being dragged */
+fun interface SliderDragVelocityProvider {
 
-val Kosmos.fixedColumnsSizeInteractor by
-    Kosmos.Fixture { FixedColumnsSizeInteractor(fixedColumnsRepository) }
+    /**
+     * Get the velocity of the slider at the time this function is called.
+     *
+     * @return the velocity of the drag in pixels/sec
+     */
+    fun getTrackedVelocity(): Float
+}
diff --git a/packages/SystemUI/src/com/android/systemui/haptics/slider/SliderHapticFeedbackConfig.kt b/packages/SystemUI/src/com/android/systemui/haptics/slider/SliderHapticFeedbackConfig.kt
index 89bfd96..24dd04d 100644
--- a/packages/SystemUI/src/com/android/systemui/haptics/slider/SliderHapticFeedbackConfig.kt
+++ b/packages/SystemUI/src/com/android/systemui/haptics/slider/SliderHapticFeedbackConfig.kt
@@ -38,7 +38,7 @@
     /** Number of low ticks in a drag texture composition. This is not expected to change */
     val numberOfLowTicks: Int = 5,
     /** Maximum velocity allowed for vibration scaling. This is not expected to change. */
-    val maxVelocityToScale: Float = 2000f, /* In pixels/sec */
+    val maxVelocityToScale: Float = 2000f, /* In units/sec. The default units are pixels */
     /** Axis to use when computing velocity. Must be the same as the slider's axis of movement */
     val velocityAxis: Int = MotionEvent.AXIS_X,
     /** Vibration scale at the upper bookend of the slider */
diff --git a/packages/SystemUI/src/com/android/systemui/haptics/slider/SliderHapticFeedbackProvider.kt b/packages/SystemUI/src/com/android/systemui/haptics/slider/SliderHapticFeedbackProvider.kt
index 6f28ab7..06428b7 100644
--- a/packages/SystemUI/src/com/android/systemui/haptics/slider/SliderHapticFeedbackProvider.kt
+++ b/packages/SystemUI/src/com/android/systemui/haptics/slider/SliderHapticFeedbackProvider.kt
@@ -38,7 +38,7 @@
  */
 class SliderHapticFeedbackProvider(
     private val vibratorHelper: VibratorHelper,
-    private val velocityTracker: VelocityTracker,
+    private val velocityProvider: SliderDragVelocityProvider,
     private val config: SliderHapticFeedbackConfig = SliderHapticFeedbackConfig(),
     private val clock: com.android.systemui.util.time.SystemClock,
 ) : SliderStateListener {
@@ -50,6 +50,7 @@
     private var dragTextureLastTime = clock.elapsedRealtime()
     var dragTextureLastProgress = -1f
         private set
+
     private val lowTickDurationMs =
         vibratorHelper.getPrimitiveDurations(VibrationEffect.Composition.PRIMITIVE_LOW_TICK)[0]
     private var hasVibratedAtLowerBookend = false
@@ -99,7 +100,7 @@
      */
     private fun vibrateDragTexture(
         absoluteVelocity: Float,
-        @FloatRange(from = 0.0, to = 1.0) normalizedSliderProgress: Float
+        @FloatRange(from = 0.0, to = 1.0) normalizedSliderProgress: Float,
     ) {
         // Check if its time to vibrate
         val currentTime = clock.elapsedRealtime()
@@ -132,7 +133,7 @@
     @VisibleForTesting
     fun scaleOnDragTexture(
         absoluteVelocity: Float,
-        @FloatRange(from = 0.0, to = 1.0) normalizedSliderProgress: Float
+        @FloatRange(from = 0.0, to = 1.0) normalizedSliderProgress: Float,
     ): Float {
         val velocityInterpolated =
             velocityAccelerateInterpolator.getInterpolation(
@@ -162,33 +163,24 @@
 
     override fun onLowerBookend() {
         if (!hasVibratedAtLowerBookend) {
-            vibrateOnEdgeCollision(abs(getTrackedVelocity()))
+            vibrateOnEdgeCollision(abs(velocityProvider.getTrackedVelocity()))
             hasVibratedAtLowerBookend = true
         }
     }
 
     override fun onUpperBookend() {
         if (!hasVibratedAtUpperBookend) {
-            vibrateOnEdgeCollision(abs(getTrackedVelocity()))
+            vibrateOnEdgeCollision(abs(velocityProvider.getTrackedVelocity()))
             hasVibratedAtUpperBookend = true
         }
     }
 
     override fun onProgress(@FloatRange(from = 0.0, to = 1.0) progress: Float) {
-        vibrateDragTexture(abs(getTrackedVelocity()), progress)
+        vibrateDragTexture(abs(velocityProvider.getTrackedVelocity()), progress)
         hasVibratedAtUpperBookend = false
         hasVibratedAtLowerBookend = false
     }
 
-    private fun getTrackedVelocity(): Float {
-        velocityTracker.computeCurrentVelocity(UNITS_SECOND, config.maxVelocityToScale)
-        return if (velocityTracker.isAxisSupported(config.velocityAxis)) {
-            velocityTracker.getAxisVelocity(config.velocityAxis)
-        } else {
-            0f
-        }
-    }
-
     override fun onProgressJump(@FloatRange(from = 0.0, to = 1.0) progress: Float) {}
 
     override fun onSelectAndArrow(@FloatRange(from = 0.0, to = 1.0) progress: Float) {}
@@ -199,6 +191,5 @@
                 .setUsage(VibrationAttributes.USAGE_TOUCH)
                 .setFlags(VibrationAttributes.FLAG_PIPELINED_EFFECT)
                 .build()
-        private const val UNITS_SECOND = 1000
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/haptics/slider/compose/ui/SliderHapticsViewModel.kt b/packages/SystemUI/src/com/android/systemui/haptics/slider/compose/ui/SliderHapticsViewModel.kt
new file mode 100644
index 0000000..e396767
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/haptics/slider/compose/ui/SliderHapticsViewModel.kt
@@ -0,0 +1,193 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.haptics.slider.compose.ui
+
+import androidx.compose.foundation.gestures.Orientation
+import androidx.compose.foundation.interaction.DragInteraction
+import androidx.compose.foundation.interaction.InteractionSource
+import androidx.compose.ui.geometry.Offset
+import androidx.compose.ui.input.pointer.util.VelocityTracker
+import androidx.compose.ui.unit.Velocity
+import com.android.app.tracing.coroutines.launch
+import com.android.systemui.haptics.slider.SeekableSliderTrackerConfig
+import com.android.systemui.haptics.slider.SliderDragVelocityProvider
+import com.android.systemui.haptics.slider.SliderEventType
+import com.android.systemui.haptics.slider.SliderHapticFeedbackConfig
+import com.android.systemui.haptics.slider.SliderHapticFeedbackProvider
+import com.android.systemui.haptics.slider.SliderStateProducer
+import com.android.systemui.haptics.slider.SliderStateTracker
+import com.android.systemui.lifecycle.ExclusiveActivatable
+import com.android.systemui.statusbar.VibratorHelper
+import com.android.systemui.util.time.SystemClock
+import dagger.assisted.Assisted
+import dagger.assisted.AssistedFactory
+import dagger.assisted.AssistedInject
+import kotlin.math.abs
+import kotlinx.coroutines.Job
+import kotlinx.coroutines.awaitCancellation
+import kotlinx.coroutines.coroutineScope
+
+class SliderHapticsViewModel
+@AssistedInject
+constructor(
+    @Assisted private val interactionSource: InteractionSource,
+    @Assisted private val sliderRange: ClosedFloatingPointRange<Float>,
+    @Assisted private val orientation: Orientation,
+    @Assisted private val sliderHapticFeedbackConfig: SliderHapticFeedbackConfig,
+    @Assisted private val sliderTrackerConfig: SeekableSliderTrackerConfig,
+    vibratorHelper: VibratorHelper,
+    systemClock: SystemClock,
+) : ExclusiveActivatable() {
+
+    var currentSliderEventType = SliderEventType.NOTHING
+        private set
+
+    private val velocityTracker = VelocityTracker()
+    private val maxVelocity =
+        Velocity(
+            sliderHapticFeedbackConfig.maxVelocityToScale,
+            sliderHapticFeedbackConfig.maxVelocityToScale,
+        )
+    private val dragVelocityProvider = SliderDragVelocityProvider {
+        val velocity =
+            when (orientation) {
+                Orientation.Horizontal -> velocityTracker.calculateVelocity(maxVelocity).x
+                Orientation.Vertical -> velocityTracker.calculateVelocity(maxVelocity).y
+            }
+        abs(velocity)
+    }
+
+    private var startingProgress = 0f
+
+    // Haptic slider stack of components
+    private val sliderStateProducer = SliderStateProducer()
+    private val sliderHapticFeedbackProvider =
+        SliderHapticFeedbackProvider(
+            vibratorHelper,
+            dragVelocityProvider,
+            sliderHapticFeedbackConfig,
+            systemClock,
+        )
+    private var sliderTracker: SliderStateTracker? = null
+
+    private var trackerJob: Job? = null
+
+    val isRunning: Boolean
+        get() = trackerJob?.isActive == true && sliderTracker?.isTracking == true
+
+    override suspend fun onActivated(): Nothing {
+        coroutineScope {
+            trackerJob =
+                launch("SliderHapticsViewModel#SliderStateTracker") {
+                    try {
+                        sliderTracker =
+                            SliderStateTracker(
+                                sliderHapticFeedbackProvider,
+                                sliderStateProducer,
+                                this,
+                                sliderTrackerConfig,
+                            )
+                        sliderTracker?.startTracking()
+                        awaitCancellation()
+                    } finally {
+                        sliderTracker?.stopTracking()
+                        sliderTracker = null
+                        velocityTracker.resetTracking()
+                    }
+                }
+
+            launch("SliderHapticsViewModel#InteractionSource") {
+                interactionSource.interactions.collect { interaction ->
+                    if (interaction is DragInteraction.Start) {
+                        currentSliderEventType = SliderEventType.STARTED_TRACKING_TOUCH
+                        sliderStateProducer.onStartTracking(true)
+                    }
+                }
+            }
+            awaitCancellation()
+        }
+    }
+
+    /**
+     * React to a value change in the slider.
+     *
+     * @param[value] latest value of the slider inside the [sliderRange] provided to the class
+     *   constructor.
+     */
+    fun onValueChange(value: Float) {
+        val normalized = value.normalize()
+        when (currentSliderEventType) {
+            SliderEventType.NOTHING -> {
+                currentSliderEventType = SliderEventType.STARTED_TRACKING_PROGRAM
+                startingProgress = normalized
+                sliderStateProducer.resetWithProgress(normalized)
+                sliderStateProducer.onStartTracking(false)
+            }
+            SliderEventType.STARTED_TRACKING_TOUCH -> {
+                startingProgress = normalized
+                currentSliderEventType = SliderEventType.PROGRESS_CHANGE_BY_USER
+            }
+            SliderEventType.PROGRESS_CHANGE_BY_USER -> {
+                velocityTracker.addPosition(System.currentTimeMillis(), normalized.toOffset())
+                currentSliderEventType = SliderEventType.PROGRESS_CHANGE_BY_USER
+                sliderStateProducer.onProgressChanged(true, normalized)
+            }
+            SliderEventType.STARTED_TRACKING_PROGRAM -> {
+                startingProgress = normalized
+                currentSliderEventType = SliderEventType.PROGRESS_CHANGE_BY_PROGRAM
+            }
+            SliderEventType.PROGRESS_CHANGE_BY_PROGRAM -> {
+                velocityTracker.addPosition(System.currentTimeMillis(), normalized.toOffset())
+                currentSliderEventType = SliderEventType.PROGRESS_CHANGE_BY_PROGRAM
+                sliderStateProducer.onProgressChanged(false, normalized)
+            }
+            else -> {}
+        }
+    }
+
+    fun onValueChangeEnded() {
+        when (currentSliderEventType) {
+            SliderEventType.STARTED_TRACKING_PROGRAM,
+            SliderEventType.PROGRESS_CHANGE_BY_PROGRAM -> sliderStateProducer.onStopTracking(false)
+            SliderEventType.STARTED_TRACKING_TOUCH,
+            SliderEventType.PROGRESS_CHANGE_BY_USER -> sliderStateProducer.onStopTracking(true)
+            else -> {}
+        }
+        currentSliderEventType = SliderEventType.NOTHING
+        velocityTracker.resetTracking()
+    }
+
+    private fun Float.normalize(): Float =
+        (this / (sliderRange.endInclusive - sliderRange.start)).coerceIn(0f, 1f)
+
+    private fun Float.toOffset(): Offset =
+        when (orientation) {
+            Orientation.Horizontal -> Offset(x = this - startingProgress, y = 0f)
+            Orientation.Vertical -> Offset(x = 0f, y = this - startingProgress)
+        }
+
+    @AssistedFactory
+    interface Factory {
+        fun create(
+            interactionSource: InteractionSource,
+            sliderRange: ClosedFloatingPointRange<Float>,
+            orientation: Orientation,
+            sliderHapticFeedbackConfig: SliderHapticFeedbackConfig,
+            sliderTrackerConfig: SeekableSliderTrackerConfig,
+        ): SliderHapticsViewModel
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/ui/composable/ActionKeyTutorialScreen.kt b/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/ui/composable/ActionKeyTutorialScreen.kt
index 1aa5ee0..4142be3 100644
--- a/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/ui/composable/ActionKeyTutorialScreen.kt
+++ b/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/ui/composable/ActionKeyTutorialScreen.kt
@@ -37,25 +37,22 @@
 import androidx.compose.ui.input.key.type
 import com.airbnb.lottie.compose.rememberLottieDynamicProperties
 import com.android.compose.theme.LocalAndroidColorScheme
-import com.android.systemui.inputdevice.tutorial.ui.composable.TutorialActionState.FINISHED
-import com.android.systemui.inputdevice.tutorial.ui.composable.TutorialActionState.NOT_STARTED
+import com.android.systemui.inputdevice.tutorial.ui.composable.TutorialActionState.Finished
+import com.android.systemui.inputdevice.tutorial.ui.composable.TutorialActionState.NotStarted
 import com.android.systemui.res.R
 
 @Composable
-fun ActionKeyTutorialScreen(
-    onDoneButtonClicked: () -> Unit,
-    onBack: () -> Unit,
-) {
+fun ActionKeyTutorialScreen(onDoneButtonClicked: () -> Unit, onBack: () -> Unit) {
     BackHandler(onBack = onBack)
     val screenConfig = buildScreenConfig()
-    var actionState by remember { mutableStateOf(NOT_STARTED) }
+    var actionState: TutorialActionState by remember { mutableStateOf(NotStarted) }
     val focusRequester = remember { FocusRequester() }
     Box(
         modifier =
             Modifier.fillMaxSize()
                 .onKeyEvent { keyEvent: KeyEvent ->
                     if (keyEvent.key == Key.MetaLeft && keyEvent.type == KeyEventType.KeyUp) {
-                        actionState = FINISHED
+                        actionState = Finished
                     }
                     true
                 }
@@ -81,13 +78,13 @@
                 titleResId = R.string.tutorial_action_key_title,
                 bodyResId = R.string.tutorial_action_key_guidance,
                 titleSuccessResId = R.string.tutorial_action_key_success_title,
-                bodySuccessResId = R.string.tutorial_action_key_success_body
+                bodySuccessResId = R.string.tutorial_action_key_success_body,
             ),
         animations =
             TutorialScreenConfig.Animations(
                 educationResId = R.raw.action_key_edu,
-                successResId = R.raw.action_key_success
-            )
+                successResId = R.raw.action_key_success,
+            ),
     )
 
 @Composable
@@ -101,7 +98,7 @@
             rememberColorFilterProperty(".primaryFixedDim", primaryFixedDim),
             rememberColorFilterProperty(".secondaryFixedDim", secondaryFixedDim),
             rememberColorFilterProperty(".onSecondaryFixed", onSecondaryFixed),
-            rememberColorFilterProperty(".onSecondaryFixedVariant", onSecondaryFixedVariant)
+            rememberColorFilterProperty(".onSecondaryFixedVariant", onSecondaryFixedVariant),
         )
     val screenColors =
         remember(dynamicProperties) {
diff --git a/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/ui/composable/ActionTutorialContent.kt b/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/ui/composable/ActionTutorialContent.kt
index f32c94b..73975a0 100644
--- a/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/ui/composable/ActionTutorialContent.kt
+++ b/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/ui/composable/ActionTutorialContent.kt
@@ -61,15 +61,16 @@
 import com.airbnb.lottie.compose.animateLottieCompositionAsState
 import com.airbnb.lottie.compose.rememberLottieComposition
 import com.airbnb.lottie.compose.rememberLottieDynamicProperty
-import com.android.compose.modifiers.background
-import com.android.systemui.inputdevice.tutorial.ui.composable.TutorialActionState.FINISHED
-import com.android.systemui.inputdevice.tutorial.ui.composable.TutorialActionState.IN_PROGRESS
-import com.android.systemui.inputdevice.tutorial.ui.composable.TutorialActionState.NOT_STARTED
+import com.android.systemui.inputdevice.tutorial.ui.composable.TutorialActionState.Finished
+import com.android.systemui.inputdevice.tutorial.ui.composable.TutorialActionState.InProgress
+import com.android.systemui.inputdevice.tutorial.ui.composable.TutorialActionState.NotStarted
 
-enum class TutorialActionState {
-    NOT_STARTED,
-    IN_PROGRESS,
-    FINISHED,
+sealed interface TutorialActionState {
+    data object NotStarted : TutorialActionState
+
+    data class InProgress(val progress: Float = 0f) : TutorialActionState
+
+    data object Finished : TutorialActionState
 }
 
 @Composable
@@ -89,11 +90,11 @@
         Row(modifier = Modifier.fillMaxWidth().weight(1f)) {
             TutorialDescription(
                 titleTextId =
-                    if (actionState == FINISHED) config.strings.titleSuccessResId
+                    if (actionState == Finished) config.strings.titleSuccessResId
                     else config.strings.titleResId,
                 titleColor = config.colors.title,
                 bodyTextId =
-                    if (actionState == FINISHED) config.strings.bodySuccessResId
+                    if (actionState == Finished) config.strings.bodySuccessResId
                     else config.strings.bodyResId,
                 modifier = Modifier.weight(1f),
             )
@@ -104,7 +105,7 @@
                 modifier = Modifier.weight(1f).padding(top = 8.dp),
             )
         }
-        AnimatedVisibility(visible = actionState == FINISHED, enter = fadeIn()) {
+        AnimatedVisibility(visible = actionState == Finished, enter = fadeIn()) {
             DoneButton(onDoneButtonClicked = onDoneButtonClicked)
         }
     }
@@ -142,7 +143,7 @@
         AnimatedContent(
             targetState = actionState,
             transitionSpec = {
-                if (initialState == NOT_STARTED) {
+                if (initialState == NotStarted) {
                     val transitionDurationMillis = 150
                     fadeIn(animationSpec = tween(transitionDurationMillis, easing = LinearEasing))
                         .togetherWith(
@@ -160,17 +161,17 @@
             },
         ) { state ->
             when (state) {
-                NOT_STARTED ->
+                NotStarted ->
                     EducationAnimation(
                         config.animations.educationResId,
                         config.colors.animationColors,
                     )
-                IN_PROGRESS ->
+                is InProgress ->
                     FrozenSuccessAnimation(
                         config.animations.successResId,
                         config.colors.animationColors,
                     )
-                FINISHED ->
+                Finished ->
                     SuccessAnimation(config.animations.successResId, config.colors.animationColors)
             }
         }
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutHelper.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutHelper.kt
index 5e05dab..3c8bb09 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutHelper.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutHelper.kt
@@ -24,6 +24,7 @@
 import androidx.compose.animation.core.animateFloatAsState
 import androidx.compose.foundation.Image
 import androidx.compose.foundation.background
+import androidx.compose.foundation.border
 import androidx.compose.foundation.focusable
 import androidx.compose.foundation.interaction.MutableInteractionSource
 import androidx.compose.foundation.interaction.collectIsFocusedAsState
@@ -47,6 +48,7 @@
 import androidx.compose.foundation.layout.width
 import androidx.compose.foundation.lazy.LazyColumn
 import androidx.compose.foundation.lazy.items
+import androidx.compose.foundation.lazy.rememberLazyListState
 import androidx.compose.foundation.rememberScrollState
 import androidx.compose.foundation.shape.CircleShape
 import androidx.compose.foundation.shape.RoundedCornerShape
@@ -80,25 +82,18 @@
 import androidx.compose.runtime.setValue
 import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
-import androidx.compose.ui.draw.drawWithContent
 import androidx.compose.ui.focus.FocusDirection
 import androidx.compose.ui.focus.FocusRequester
 import androidx.compose.ui.focus.focusRequester
-import androidx.compose.ui.geometry.CornerRadius
-import androidx.compose.ui.geometry.Offset
-import androidx.compose.ui.geometry.Rect
 import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.graphics.RectangleShape
 import androidx.compose.ui.graphics.Shape
-import androidx.compose.ui.graphics.drawscope.Stroke
 import androidx.compose.ui.graphics.graphicsLayer
 import androidx.compose.ui.input.key.Key
 import androidx.compose.ui.input.key.key
 import androidx.compose.ui.input.key.onKeyEvent
-import androidx.compose.ui.input.nestedscroll.nestedScroll
 import androidx.compose.ui.platform.LocalContext
 import androidx.compose.ui.platform.LocalFocusManager
-import androidx.compose.ui.platform.rememberNestedScrollInteropConnection
 import androidx.compose.ui.res.painterResource
 import androidx.compose.ui.res.stringResource
 import androidx.compose.ui.semantics.Role
@@ -113,9 +108,9 @@
 import androidx.compose.ui.util.fastFirstOrNull
 import androidx.compose.ui.util.fastForEach
 import androidx.compose.ui.util.fastForEachIndexed
-import androidx.compose.ui.zIndex
+import com.android.compose.modifiers.thenIf
 import com.android.compose.ui.graphics.painter.rememberDrawablePainter
-import com.android.systemui.keyboard.shortcut.shared.model.Shortcut
+import com.android.systemui.keyboard.shortcut.shared.model.Shortcut as ShortcutModel
 import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategory
 import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategoryType
 import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCommand
@@ -405,7 +400,7 @@
         if (index > 0) {
             HorizontalDivider(color = MaterialTheme.colorScheme.surfaceContainerHigh)
         }
-        ShortcutView(Modifier.padding(vertical = 24.dp), searchQuery, shortcut)
+        Shortcut(Modifier.padding(vertical = 24.dp), searchQuery, shortcut)
     }
 }
 
@@ -440,13 +435,15 @@
 
 @Composable
 private fun EndSidePanel(searchQuery: String, modifier: Modifier, category: ShortcutCategory?) {
+    val listState = rememberLazyListState()
+    LaunchedEffect(key1 = category) { if (category != null) listState.animateScrollToItem(0) }
     if (category == null) {
         NoSearchResultsText(horizontalPadding = 24.dp, fillHeight = false)
         return
     }
-    LazyColumn(modifier.nestedScroll(rememberNestedScrollInteropConnection())) {
-        items(items = category.subCategories, key = { item -> item.label }) {
-            SubCategoryContainerDualPane(searchQuery, it)
+    LazyColumn(modifier = modifier, state = listState) {
+        items(category.subCategories) { subcategory ->
+            SubCategoryContainerDualPane(searchQuery = searchQuery, subCategory = subcategory)
             Spacer(modifier = Modifier.height(8.dp))
         }
     }
@@ -477,14 +474,21 @@
         shape = RoundedCornerShape(28.dp),
         color = MaterialTheme.colorScheme.surfaceBright,
     ) {
-        Column(Modifier.padding(24.dp)) {
+        Column(Modifier.padding(16.dp)) {
             SubCategoryTitle(subCategory.label)
             Spacer(Modifier.height(8.dp))
             subCategory.shortcuts.fastForEachIndexed { index, shortcut ->
                 if (index > 0) {
-                    HorizontalDivider(color = MaterialTheme.colorScheme.surfaceContainerHigh)
+                    HorizontalDivider(
+                        modifier = Modifier.padding(horizontal = 8.dp),
+                        color = MaterialTheme.colorScheme.surfaceContainerHigh,
+                    )
                 }
-                ShortcutView(Modifier.padding(vertical = 16.dp), searchQuery, shortcut)
+                Shortcut(
+                    modifier = Modifier.padding(vertical = 8.dp),
+                    searchQuery = searchQuery,
+                    shortcut = shortcut,
+                )
             }
         }
     }
@@ -500,18 +504,17 @@
 }
 
 @Composable
-private fun ShortcutView(modifier: Modifier, searchQuery: String, shortcut: Shortcut) {
+private fun Shortcut(modifier: Modifier, searchQuery: String, shortcut: ShortcutModel) {
     val interactionSource = remember { MutableInteractionSource() }
     val isFocused by interactionSource.collectIsFocusedAsState()
+    val focusColor = MaterialTheme.colorScheme.secondary
     Row(
         modifier
+            .thenIf(isFocused) {
+                Modifier.border(width = 3.dp, color = focusColor, shape = RoundedCornerShape(16.dp))
+            }
             .focusable(interactionSource = interactionSource)
-            .outlineFocusModifier(
-                isFocused = isFocused,
-                focusColor = MaterialTheme.colorScheme.secondary,
-                padding = 8.dp,
-                cornerRadius = 16.dp,
-            )
+            .padding(8.dp)
     ) {
         Row(
             modifier = Modifier.width(128.dp).align(Alignment.CenterVertically),
@@ -523,7 +526,7 @@
             }
             ShortcutDescriptionText(searchQuery = searchQuery, shortcut = shortcut)
         }
-        Spacer(modifier = Modifier.width(16.dp))
+        Spacer(modifier = Modifier.width(24.dp))
         ShortcutKeyCombinations(modifier = Modifier.weight(1f), shortcut = shortcut)
     }
 }
@@ -548,7 +551,7 @@
 
 @OptIn(ExperimentalLayoutApi::class)
 @Composable
-private fun ShortcutKeyCombinations(modifier: Modifier = Modifier, shortcut: Shortcut) {
+private fun ShortcutKeyCombinations(modifier: Modifier = Modifier, shortcut: ShortcutModel) {
     FlowRow(
         modifier = modifier,
         verticalArrangement = Arrangement.spacedBy(8.dp),
@@ -628,7 +631,7 @@
 @Composable
 private fun ShortcutDescriptionText(
     searchQuery: String,
-    shortcut: Shortcut,
+    shortcut: ShortcutModel,
     modifier: Modifier = Modifier,
 ) {
     Text(
@@ -751,39 +754,6 @@
     }
 }
 
-private fun Modifier.outlineFocusModifier(
-    isFocused: Boolean,
-    focusColor: Color,
-    padding: Dp,
-    cornerRadius: Dp,
-): Modifier {
-    if (isFocused) {
-        return this.drawWithContent {
-                val focusOutline =
-                    Rect(Offset.Zero, size).let {
-                        if (padding > 0.dp) {
-                            it.inflate(padding.toPx())
-                        } else {
-                            it.deflate(padding.unaryMinus().toPx())
-                        }
-                    }
-                drawContent()
-                drawRoundRect(
-                    color = focusColor,
-                    style = Stroke(width = 3.dp.toPx()),
-                    topLeft = focusOutline.topLeft,
-                    size = focusOutline.size,
-                    cornerRadius = CornerRadius(cornerRadius.toPx()),
-                )
-            }
-            // Increasing Z-Index so focus outline is drawn on top of "selected" category
-            // background.
-            .zIndex(1f)
-    } else {
-        return this
-    }
-}
-
 @Composable
 @OptIn(ExperimentalMaterial3Api::class)
 private fun TitleBar() {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 9c7cc81..d28b08f 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -178,6 +178,7 @@
 import com.android.systemui.util.settings.SystemSettings;
 import com.android.systemui.util.time.SystemClock;
 import com.android.systemui.wallpapers.data.repository.WallpaperRepository;
+import com.android.window.flags.Flags;
 import com.android.wm.shell.keyguard.KeyguardTransitions;
 
 import dagger.Lazy;
@@ -236,6 +237,9 @@
  */
 public class KeyguardViewMediator implements CoreStartable, Dumpable,
         StatusBarStateController.StateListener {
+
+    private static final boolean ENABLE_NEW_KEYGUARD_SHELL_TRANSITIONS =
+            Flags.ensureKeyguardDoesTransitionStarting();
     private static final int KEYGUARD_DISPLAY_TIMEOUT_DELAY_DEFAULT = 30000;
     private static final long KEYGUARD_DONE_PENDING_TIMEOUT_MS = 3000;
 
@@ -2456,6 +2460,12 @@
             android.util.Log.i(TAG, "Ignoring request to dismiss (user switch in progress?)");
             return;
         }
+
+        if (mKeyguardStateController.isKeyguardGoingAway()) {
+            Log.i(TAG, "Ignoring dismiss because we're already going away.");
+            return;
+        }
+
         mHandler.obtainMessage(DISMISS, new DismissMessage(callback, message)).sendToTarget();
     }
 
@@ -2865,9 +2875,14 @@
                 return;
             }
 
-            try {
-                mActivityTaskManagerService.setLockScreenShown(showing, aodShowing);
-            } catch (RemoteException ignored) {
+            if (ENABLE_NEW_KEYGUARD_SHELL_TRANSITIONS) {
+                mKeyguardTransitions.startKeyguardTransition(showing, aodShowing);
+            } else {
+                try {
+
+                    mActivityTaskManagerService.setLockScreenShown(showing, aodShowing);
+                } catch (RemoteException ignored) {
+                }
             }
         });
     }
@@ -2998,18 +3013,23 @@
 
             // Handled in WmLockscreenVisibilityManager if flag is enabled.
             if (!KeyguardWmStateRefactor.isEnabled()) {
-                    // Don't actually hide the Keyguard at the moment, wait for window manager 
-                    // until it tells us it's safe to do so with startKeyguardExitAnimation.
-		    // Posting to mUiOffloadThread to ensure that calls to ActivityTaskManager 
-		    // will be in order.
-		    final int keyguardFlag = flags;
-		    mUiBgExecutor.execute(() -> {
-		        try {
-		            mActivityTaskManagerService.keyguardGoingAway(keyguardFlag);
-		        } catch (RemoteException e) {
-		            Log.e(TAG, "Error while calling WindowManager", e);
-		        }
-		    });
+                // Don't actually hide the Keyguard at the moment, wait for window manager
+                // until it tells us it's safe to do so with startKeyguardExitAnimation.
+                // Posting to mUiOffloadThread to ensure that calls to ActivityTaskManager
+                // will be in order.
+                final int keyguardFlag = flags;
+                mUiBgExecutor.execute(() -> {
+                    if (ENABLE_NEW_KEYGUARD_SHELL_TRANSITIONS) {
+                        mKeyguardTransitions.startKeyguardTransition(
+                                false /* keyguardShowing */, false /* aodShowing */);
+                        return;
+                    }
+                    try {
+                        mActivityTaskManagerService.keyguardGoingAway(keyguardFlag);
+                    } catch (RemoteException e) {
+                        Log.e(TAG, "Error while calling WindowManager", e);
+                    }
+                });
             }
 
             Trace.endSection();
@@ -3414,6 +3434,12 @@
             return;
         }
 
+        if (mIsKeyguardExitAnimationCanceled) {
+            Log.d(TAG, "Ignoring exitKeyguardAndFinishSurfaceBehindRemoteAnimation. "
+                    + "mIsKeyguardExitAnimationCanceled==true");
+            return;
+        }
+
         // Block the panel from expanding, in case we were doing a swipe to dismiss gesture.
         mKeyguardViewControllerLazy.get().blockPanelExpansionFromCurrentTouch();
         final boolean wasShowing = mShowing;
@@ -3464,6 +3490,12 @@
     public void showSurfaceBehindKeyguard() {
         mSurfaceBehindRemoteAnimationRequested = true;
 
+        if (ENABLE_NEW_KEYGUARD_SHELL_TRANSITIONS) {
+            mKeyguardTransitions.startKeyguardTransition(
+                    false /* keyguardShowing */, false /* aodShowing */);
+            return;
+        }
+
         try {
             int flags = KEYGUARD_GOING_AWAY_FLAG_NO_WINDOW_ANIMATIONS
                     | KEYGUARD_GOING_AWAY_FLAG_WITH_WALLPAPER;
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/WindowManagerLockscreenVisibilityManager.kt b/packages/SystemUI/src/com/android/systemui/keyguard/WindowManagerLockscreenVisibilityManager.kt
index e89594e..032af94 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/WindowManagerLockscreenVisibilityManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/WindowManagerLockscreenVisibilityManager.kt
@@ -26,6 +26,8 @@
 import com.android.systemui.keyguard.domain.interactor.KeyguardDismissTransitionInteractor
 import com.android.systemui.keyguard.ui.binder.KeyguardSurfaceBehindParamsApplier
 import com.android.systemui.statusbar.policy.KeyguardStateController
+import com.android.window.flags.Flags
+import com.android.wm.shell.keyguard.KeyguardTransitions
 import java.util.concurrent.Executor
 import javax.inject.Inject
 
@@ -42,6 +44,7 @@
     private val keyguardStateController: KeyguardStateController,
     private val keyguardSurfaceBehindAnimator: KeyguardSurfaceBehindParamsApplier,
     private val keyguardDismissTransitionInteractor: KeyguardDismissTransitionInteractor,
+    private val keyguardTransitions: KeyguardTransitions
 ) {
 
     /**
@@ -97,6 +100,9 @@
     /** Callback provided by WM to call once we're done with the going away animation. */
     private var goingAwayRemoteAnimationFinishedCallback: IRemoteAnimationFinishedCallback? = null
 
+    private val enableNewKeyguardShellTransitions: Boolean =
+        Flags.ensureKeyguardDoesTransitionStarting()
+
     /**
      * Set the visibility of the surface behind the keyguard, making the appropriate calls to Window
      * Manager to effect the change.
@@ -114,7 +120,14 @@
             return
         }
 
+
+
         if (visible) {
+            if (enableNewKeyguardShellTransitions) {
+                keyguardTransitions.startKeyguardTransition(false /* keyguardShowing */, false /* aodShowing */)
+                isKeyguardGoingAway = true
+                return
+            }
             // Make the surface visible behind the keyguard by calling keyguardGoingAway. The
             // lockscreen is still showing as well, allowing us to animate unlocked.
             Log.d(TAG, "ActivityTaskManagerService#keyguardGoingAway()")
@@ -220,7 +233,11 @@
                 "isLockscreenShowing=$lockscreenShowing, " +
                 "aodVisible=$aodVisible)."
         )
-        activityTaskManagerService.setLockScreenShown(lockscreenShowing, aodVisible)
+        if (enableNewKeyguardShellTransitions) {
+            keyguardTransitions.startKeyguardTransition(lockscreenShowing, aodVisible)
+        } else {
+            activityTaskManagerService.setLockScreenShown(lockscreenShowing, aodVisible)
+        }
         this.isLockscreenShowing = lockscreenShowing
         this.isAodVisible = aodVisible
     }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardClockRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardClockRepository.kt
index ec52055..95d1b5d 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardClockRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardClockRepository.kt
@@ -68,11 +68,16 @@
 
     val previewClock: Flow<ClockController>
 
+    /** top of notifications without bcsmartspace in small clock settings */
+    val notificationDefaultTop: StateFlow<Float>
+
     val clockEventController: ClockEventController
 
     val shouldForceSmallClock: Boolean
 
     fun setClockSize(size: ClockSize)
+
+    fun setNotificationDefaultTop(top: Float)
 }
 
 @SysUISingleton
@@ -108,7 +113,7 @@
             .stateIn(
                 scope = applicationScope,
                 started = SharingStarted.WhileSubscribed(),
-                initialValue = getClockSize()
+                initialValue = getClockSize(),
             )
 
     override val currentClockId: Flow<ClockId> =
@@ -138,7 +143,7 @@
             .stateIn(
                 scope = applicationScope,
                 started = SharingStarted.WhileSubscribed(),
-                initialValue = clockRegistry.createCurrentClock()
+                initialValue = clockRegistry.createCurrentClock(),
             )
 
     override val previewClock: Flow<ClockController> =
@@ -149,6 +154,14 @@
             clockRegistry.createCurrentClock()
         }
 
+    private val _notificationDefaultTop: MutableStateFlow<Float> = MutableStateFlow(0F)
+
+    override val notificationDefaultTop: StateFlow<Float> = _notificationDefaultTop.asStateFlow()
+
+    override fun setNotificationDefaultTop(top: Float) {
+        _notificationDefaultTop.value = top
+    }
+
     override val shouldForceSmallClock: Boolean
         get() =
             featureFlags.isEnabled(Flags.LOCKSCREEN_ENABLE_LANDSCAPE) &&
@@ -160,7 +173,7 @@
             secureSettings.getIntForUser(
                 Settings.Secure.LOCKSCREEN_USE_DOUBLE_LINE_CLOCK,
                 /* defaultValue= */ 1,
-                UserHandle.USER_CURRENT
+                UserHandle.USER_CURRENT,
             )
         )
     }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt
index 130242f..8210174 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt
@@ -269,6 +269,9 @@
      */
     val isEncryptedOrLockdown: Flow<Boolean>
 
+    /** The top of shortcut in screen, used by wallpaper to find remaining space in lockscreen */
+    val shortcutAbsoluteTop: StateFlow<Float>
+
     /**
      * Returns `true` if the keyguard is showing; `false` otherwise.
      *
@@ -339,6 +342,8 @@
      * otherwise.
      */
     fun isShowKeyguardWhenReenabled(): Boolean
+
+    fun setShortcutAbsoluteTop(top: Float)
 }
 
 /** Encapsulates application state for the keyguard. */
@@ -503,7 +508,7 @@
                 trySendWithFailureLogging(
                     statusBarStateController.dozeAmount,
                     TAG,
-                    "initial dozeAmount"
+                    "initial dozeAmount",
                 )
 
                 awaitClose { statusBarStateController.removeCallback(callback) }
@@ -521,7 +526,7 @@
             object : DozeTransitionCallback {
                 override fun onDozeTransition(
                     oldState: DozeMachine.State,
-                    newState: DozeMachine.State
+                    newState: DozeMachine.State,
                 ) {
                     trySendWithFailureLogging(
                         DozeTransitionModel(
@@ -529,7 +534,7 @@
                             to = dozeMachineStateToModel(newState),
                         ),
                         TAG,
-                        "doze transition model"
+                        "doze transition model",
                     )
                 }
             }
@@ -541,7 +546,7 @@
                 to = dozeMachineStateToModel(dozeTransitionListener.newState),
             ),
             TAG,
-            "initial doze transition model"
+            "initial doze transition model",
         )
 
         awaitClose { dozeTransitionListener.removeCallback(callback) }
@@ -579,7 +584,7 @@
                             trySendWithFailureLogging(
                                 statusBarStateIntToObject(state),
                                 TAG,
-                                "state"
+                                "state",
                             )
                         }
                     }
@@ -590,7 +595,7 @@
             .stateIn(
                 scope,
                 SharingStarted.Eagerly,
-                statusBarStateIntToObject(statusBarStateController.state)
+                statusBarStateIntToObject(statusBarStateController.state),
             )
 
     private val _biometricUnlockState: MutableStateFlow<BiometricUnlockModel> =
@@ -610,7 +615,7 @@
             trySendWithFailureLogging(
                 authController.fingerprintSensorLocation,
                 TAG,
-                "AuthController.Callback#onFingerprintLocationChanged"
+                "AuthController.Callback#onFingerprintLocationChanged",
             )
         }
 
@@ -635,6 +640,9 @@
     private val _isActiveDreamLockscreenHosted = MutableStateFlow(false)
     override val isActiveDreamLockscreenHosted = _isActiveDreamLockscreenHosted.asStateFlow()
 
+    private val _shortcutAbsoluteTop = MutableStateFlow(0F)
+    override val shortcutAbsoluteTop = _shortcutAbsoluteTop.asStateFlow()
+
     init {
         val callback =
             object : KeyguardStateController.Callback {
@@ -721,6 +729,10 @@
         }
     }
 
+    override fun setShortcutAbsoluteTop(top: Float) {
+        _shortcutAbsoluteTop.value = top
+    }
+
     private fun dozeMachineStateToModel(state: DozeMachine.State): DozeStateModel {
         return when (state) {
             DozeMachine.State.UNINITIALIZED -> DozeStateModel.UNINITIALIZED
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardClockInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardClockInteractor.kt
index c0049d4..5b7eedd 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardClockInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardClockInteractor.kt
@@ -94,7 +94,7 @@
                 .stateIn(
                     scope = applicationScope,
                     started = SharingStarted.WhileSubscribed(),
-                    initialValue = ClockSize.LARGE
+                    initialValue = ClockSize.LARGE,
                 )
         } else {
             keyguardClockRepository.clockSize
@@ -152,4 +152,8 @@
             clock.largeClock.animations.fold(foldFraction)
         }
     }
+
+    fun setNotificationStackDefaultTop(top: Float) {
+        keyguardClockRepository.setNotificationDefaultTop(top)
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt
index e6ee112..d7f96b5 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt
@@ -526,6 +526,10 @@
         repository.showDismissibleKeyguard()
     }
 
+    fun setShortcutAbsoluteTop(top: Float) {
+        repository.setShortcutAbsoluteTop(top)
+    }
+
     companion object {
         private const val TAG = "KeyguardInteractor"
     }
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 65b42e6..fcf486b 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
@@ -23,6 +23,7 @@
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.keyevent.domain.interactor.SysUIKeyEventHandler.Companion.handleAction
 import com.android.systemui.media.controls.util.MediaSessionLegacyHelperWrapper
+import com.android.systemui.plugins.ActivityStarter.OnDismissAction
 import com.android.systemui.plugins.statusbar.StatusBarStateController
 import com.android.systemui.power.domain.interactor.PowerInteractor
 import com.android.systemui.shade.ShadeController
@@ -105,7 +106,15 @@
                 (statusBarStateController.state != StatusBarState.SHADE) &&
                 statusBarKeyguardViewManager.shouldDismissOnMenuPressed()
         if (shouldUnlockOnMenuPressed) {
-            shadeController.animateCollapseShadeForced()
+            statusBarKeyguardViewManager.dismissWithAction(
+                object : OnDismissAction {
+                    override fun onDismiss(): Boolean {
+                        return false
+                    }
+                },
+                null,
+                false,
+            )
             return true
         }
         return false
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt
index c4f231d..a0000f3 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt
@@ -19,6 +19,7 @@
 
 import android.annotation.SuppressLint
 import android.util.Log
+import com.android.compose.animation.scene.ObservableTransitionState
 import com.android.compose.animation.scene.SceneKey
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Application
@@ -37,15 +38,22 @@
 import javax.inject.Inject
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.Job
+import kotlinx.coroutines.cancelAndJoin
 import kotlinx.coroutines.channels.BufferOverflow
+import kotlinx.coroutines.coroutineScope
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.MutableSharedFlow
 import kotlinx.coroutines.flow.SharedFlow
 import kotlinx.coroutines.flow.SharingStarted
 import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.channelFlow
 import kotlinx.coroutines.flow.combine
 import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.emitAll
 import kotlinx.coroutines.flow.filter
+import kotlinx.coroutines.flow.flow
+import kotlinx.coroutines.flow.flowOf
 import kotlinx.coroutines.flow.map
 import kotlinx.coroutines.flow.mapLatest
 import kotlinx.coroutines.flow.onStart
@@ -206,44 +214,155 @@
                 )
             }
 
-        return if (SceneContainerFlag.isEnabled) {
-            flow.filter { step ->
-                val fromScene =
-                    when (edge) {
-                        is Edge.StateToState -> edge.from?.mapToSceneContainerScene()
-                        is Edge.StateToScene -> edge.from?.mapToSceneContainerScene()
-                        is Edge.SceneToState -> edge.from
+        if (!SceneContainerFlag.isEnabled) {
+            return flow
+        }
+        if (edge.isSceneWildcardEdge()) {
+            return simulateTransitionStepsForSceneTransitions(edge)
+        }
+        return flow.filter { step ->
+            val fromScene =
+                when (edge) {
+                    is Edge.StateToState -> edge.from?.mapToSceneContainerScene()
+                    is Edge.StateToScene -> edge.from?.mapToSceneContainerScene()
+                    is Edge.SceneToState -> edge.from
+                }
+
+            val toScene =
+                when (edge) {
+                    is Edge.StateToState -> edge.to?.mapToSceneContainerScene()
+                    is Edge.StateToScene -> edge.to
+                    is Edge.SceneToState -> edge.to?.mapToSceneContainerScene()
+                }
+
+            val isTransitioningBetweenLockscreenStates =
+                fromScene.isLockscreenOrNull() && toScene.isLockscreenOrNull()
+            val isTransitioningBetweenDesiredScenes =
+                sceneInteractor.transitionState.value.isTransitioning(fromScene, toScene)
+
+            // We can't compare the terminal step with the current sceneTransition because
+            // a) STL has no guarantee that it will settle in Idle() when finished/canceled
+            // b) Comparing to Idle(toScene) would make any other FINISHED step settling in
+            //    toScene pass as well
+            val terminalStepBelongsToPreviousTransition =
+                (step.transitionState == TransitionState.FINISHED ||
+                    step.transitionState == TransitionState.CANCELED) &&
+                    sceneTransitionPair.value.previousValue.isTransitioning(fromScene, toScene)
+
+            return@filter isTransitioningBetweenLockscreenStates ||
+                isTransitioningBetweenDesiredScenes ||
+                terminalStepBelongsToPreviousTransition
+        }
+    }
+
+    private fun SceneKey?.isLockscreenOrNull() = this == Scenes.Lockscreen || this == null
+
+    /**
+     * This function will return a flow that simulates TransitionSteps based on STL movements
+     * filtered by [edge].
+     *
+     * STL transitions outside of Lockscreen Transitions are not tracked in KTI. This is an issue
+     * for wildcard edges, as this means that Scenes.Bouncer -> Scenes.Gone would not appear while
+     * AOD -> Scenes.Bouncer would appear.
+     *
+     * This function will track STL transitions only when a wildcard edge is provided and emit a
+     * RUNNING step for each update to [Transition.progress]. It will also emit a STARTED and
+     * FINISHED step when the transitions starts and finishes.
+     *
+     * All TransitionSteps will have UNDEFINED as to and from state even when one of them is the
+     * Lockscreen Scene. It indicates that both are scenes but it should not be relevant to
+     * consumers of the [transition] API as usually all viewModels are just interested in the
+     * progress value. The correct filtering based on the provided [edge] is always the
+     * responsibility of KTI and therefore only proper [TransitionStep]s are emitted. The filter is
+     * applied within this function.
+     */
+    private fun simulateTransitionStepsForSceneTransitions(edge: Edge) =
+        sceneInteractor.transitionState.flatMapLatestWithFinished {
+            when (it) {
+                is ObservableTransitionState.Idle -> {
+                    flowOf()
+                }
+                is ObservableTransitionState.Transition -> {
+                    val isMatchingTransition =
+                        when (edge) {
+                            is Edge.StateToState ->
+                                throw IllegalStateException("Should not be reachable.")
+                            is Edge.SceneToState -> it.isTransitioning(from = edge.from)
+                            is Edge.StateToScene -> it.isTransitioning(to = edge.to)
+                        }
+                    if (!isMatchingTransition) {
+                        return@flatMapLatestWithFinished flowOf()
                     }
-
-                val toScene =
-                    when (edge) {
-                        is Edge.StateToState -> edge.to?.mapToSceneContainerScene()
-                        is Edge.StateToScene -> edge.to
-                        is Edge.SceneToState -> edge.to?.mapToSceneContainerScene()
+                    flow {
+                        emit(
+                            TransitionStep(
+                                from = UNDEFINED,
+                                to = UNDEFINED,
+                                value = 0f,
+                                transitionState = TransitionState.STARTED,
+                            )
+                        )
+                        emitAll(
+                            it.progress.map { progress ->
+                                TransitionStep(
+                                    from = UNDEFINED,
+                                    to = UNDEFINED,
+                                    value = progress,
+                                    transitionState = TransitionState.RUNNING,
+                                )
+                            }
+                        )
                     }
-
-                fun SceneKey?.isLockscreenOrNull() = this == Scenes.Lockscreen || this == null
-
-                val isTransitioningBetweenLockscreenStates =
-                    fromScene.isLockscreenOrNull() && toScene.isLockscreenOrNull()
-                val isTransitioningBetweenDesiredScenes =
-                    sceneInteractor.transitionState.value.isTransitioning(fromScene, toScene)
-
-                // We can't compare the terminal step with the current sceneTransition because
-                // a) STL has no guarantee that it will settle in Idle() when finished/canceled
-                // b) Comparing to Idle(toScene) would make any other FINISHED step settling in
-                //    toScene pass as well
-                val terminalStepBelongsToPreviousTransition =
-                    (step.transitionState == TransitionState.FINISHED ||
-                        step.transitionState == TransitionState.CANCELED) &&
-                        sceneTransitionPair.value.previousValue.isTransitioning(fromScene, toScene)
-
-                return@filter isTransitioningBetweenLockscreenStates ||
-                    isTransitioningBetweenDesiredScenes ||
-                    terminalStepBelongsToPreviousTransition
+                }
             }
-        } else {
-            flow
+        }
+
+    /**
+     * This function is similar to flatMapLatest but it will additionally emit a FINISHED
+     * TransitionStep whenever the flattened innerFlow emitted a STARTED step and is now being
+     * replaced by a new innerFlow.
+     *
+     * This is to make sure that every STARTED step will receive a corresponding FINISHED step.
+     *
+     * We can't simply write this into a flow {} block because Transition.progress doesn't complete.
+     * We also can't emit the FINISHED step simply when an Idle state is reached because a)
+     * Transitions are not guaranteed to finish in Idle and b) There can be multiple Idle
+     * transitions after another
+     */
+    private fun <T> Flow<T>.flatMapLatestWithFinished(
+        transform: suspend (T) -> Flow<TransitionStep>
+    ): Flow<TransitionStep> = channelFlow {
+        var job: Job? = null
+        var startedEmitted = false
+
+        coroutineScope {
+            collect { value ->
+                job?.cancelAndJoin()
+
+                job = launch {
+                    val innerFlow = transform(value)
+                    try {
+                        innerFlow.collect { step ->
+                            if (step.transitionState == TransitionState.STARTED) {
+                                startedEmitted = true
+                            }
+                            send(step)
+                        }
+                    } finally {
+                        if (startedEmitted) {
+                            send(
+                                TransitionStep(
+                                    from = UNDEFINED,
+                                    to = UNDEFINED,
+                                    value = 1f,
+                                    transitionState = TransitionState.FINISHED,
+                                )
+                            )
+                            startedEmitted = false
+                        }
+                    }
+                }
+            }
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSection.kt
index a1c963b..d745522 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSection.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSection.kt
@@ -44,6 +44,7 @@
 import com.android.systemui.plugins.clocks.ClockController
 import com.android.systemui.plugins.clocks.ClockFaceLayout
 import com.android.systemui.res.R
+import com.android.systemui.shade.LargeScreenHeaderHelper
 import com.android.systemui.shared.R as sharedR
 import com.android.systemui.util.ui.value
 import dagger.Lazy
@@ -53,6 +54,9 @@
 internal fun ConstraintSet.setVisibility(views: Iterable<View>, visibility: Int) =
     views.forEach { view -> this.setVisibility(view.id, visibility) }
 
+internal fun ConstraintSet.setAlpha(views: Iterable<View>, alpha: Float) =
+    views.forEach { view -> this.setAlpha(view.id, alpha) }
+
 internal fun ConstraintSet.setScaleX(views: Iterable<View>, scaleX: Float) =
     views.forEach { view -> this.setScaleX(view.id, scaleX) }
 
@@ -70,6 +74,7 @@
     val blueprintInteractor: Lazy<KeyguardBlueprintInteractor>,
     private val rootViewModel: KeyguardRootViewModel,
     private val aodBurnInViewModel: AodBurnInViewModel,
+    private val largeScreenHeaderHelperLazy: Lazy<LargeScreenHeaderHelper>,
 ) : KeyguardSection() {
     private var disposableHandle: DisposableHandle? = null
 
@@ -123,6 +128,8 @@
         return constraintSet.apply {
             setVisibility(getTargetClockFace(clock).views, VISIBLE)
             setVisibility(getNonTargetClockFace(clock).views, GONE)
+            setAlpha(getTargetClockFace(clock).views, 1F)
+            setAlpha(getNonTargetClockFace(clock).views, 0F)
             if (!keyguardClockViewModel.isLargeClockVisible.value) {
                 connect(sharedR.id.bc_smartspace_view, TOP, sharedR.id.date_smartspace_view, BOTTOM)
             } else {
@@ -172,7 +179,7 @@
         }
     }
 
-    open fun applyDefaultConstraints(constraints: ConstraintSet) {
+    fun applyDefaultConstraints(constraints: ConstraintSet) {
         val guideline =
             if (keyguardClockViewModel.clockShouldBeCentered.value) PARENT_ID
             else R.id.split_shade_guideline
@@ -211,6 +218,28 @@
 
             // Explicitly clear pivot to force recalculate pivot instead of using legacy value
             setTransformPivot(R.id.lockscreen_clock_view_large, Float.NaN, Float.NaN)
+
+            val smallClockBottom =
+                keyguardClockViewModel.getSmallClockTopMargin() +
+                    context.resources.getDimensionPixelSize(
+                        com.android.systemui.customization.R.dimen.small_clock_height
+                    )
+            val dateWeatherSmartspaceHeight = getDimen(context, DATE_WEATHER_VIEW_HEIGHT).toFloat()
+            val marginBetweenSmartspaceAndNotification =
+                context.resources.getDimensionPixelSize(
+                    R.dimen.keyguard_status_view_bottom_margin
+                ) +
+                    if (context.resources.getBoolean(R.bool.config_use_large_screen_shade_header)) {
+                        largeScreenHeaderHelperLazy.get().getLargeScreenHeaderHeight()
+                    } else {
+                        0
+                    }
+
+            clockInteractor.setNotificationStackDefaultTop(
+                smallClockBottom +
+                    dateWeatherSmartspaceHeight +
+                    marginBetweenSmartspaceAndNotification
+            )
         }
 
         constrainWeatherClockDateIconsBarrier(constraints)
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultShortcutsSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultShortcutsSection.kt
index 6c6e14c..d3895de 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultShortcutsSection.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultShortcutsSection.kt
@@ -30,6 +30,7 @@
 import com.android.systemui.dagger.qualifiers.Main
 import com.android.systemui.keyguard.KeyguardBottomAreaRefactor
 import com.android.systemui.keyguard.domain.interactor.KeyguardBlueprintInteractor
+import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
 import com.android.systemui.keyguard.ui.binder.KeyguardQuickAffordanceViewBinder
 import com.android.systemui.keyguard.ui.view.layout.blueprints.transitions.IntraBlueprintTransition
 import com.android.systemui.keyguard.ui.viewmodel.KeyguardQuickAffordancesCombinedViewModel
@@ -52,6 +53,7 @@
     private val indicationController: KeyguardIndicationController,
     private val keyguardBlueprintInteractor: Lazy<KeyguardBlueprintInteractor>,
     private val keyguardQuickAffordanceViewBinder: KeyguardQuickAffordanceViewBinder,
+    private val keyguardInteractor: KeyguardInteractor,
 ) : BaseShortcutSection() {
 
     // Amount to increase the bottom margin by to avoid colliding with inset
@@ -117,7 +119,7 @@
                 BOTTOM,
                 PARENT_ID,
                 BOTTOM,
-                verticalOffsetMargin + safeInsetBottom
+                verticalOffsetMargin + safeInsetBottom,
             )
 
             constrainWidth(R.id.end_button, width)
@@ -128,7 +130,7 @@
                 BOTTOM,
                 PARENT_ID,
                 BOTTOM,
-                verticalOffsetMargin + safeInsetBottom
+                verticalOffsetMargin + safeInsetBottom,
             )
 
             // The constraint set visibility for start and end button are default visible, set to
@@ -136,5 +138,13 @@
             setVisibilityMode(R.id.start_button, VISIBILITY_MODE_IGNORE)
             setVisibilityMode(R.id.end_button, VISIBILITY_MODE_IGNORE)
         }
+
+        val shortcutAbsoluteTopInScreen =
+            (resources.displayMetrics.heightPixels -
+                    (verticalOffsetMargin + safeInsetBottom) -
+                    height)
+                .toFloat()
+
+        keyguardInteractor.setShortcutAbsoluteTop(shortcutAbsoluteTopInScreen)
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryBackgroundViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryBackgroundViewModel.kt
index ca1a800..68244d8 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryBackgroundViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryBackgroundViewModel.kt
@@ -60,6 +60,7 @@
     primaryBouncerToAodTransitionViewModel: PrimaryBouncerToAodTransitionViewModel,
     primaryBouncerToDozingTransitionViewModel: PrimaryBouncerToDozingTransitionViewModel,
     primaryBouncerToLockscreenTransitionViewModel: PrimaryBouncerToLockscreenTransitionViewModel,
+    lockscreenToDozingTransitionViewModel: LockscreenToDozingTransitionViewModel,
 ) {
     val color: Flow<Int> =
         deviceEntryIconViewModel.useBackgroundProtection.flatMapLatest { useBackground ->
@@ -103,7 +104,9 @@
                         offToLockscreenTransitionViewModel.deviceEntryBackgroundViewAlpha,
                         primaryBouncerToAodTransitionViewModel.deviceEntryBackgroundViewAlpha,
                         primaryBouncerToDozingTransitionViewModel.deviceEntryBackgroundViewAlpha,
-                        primaryBouncerToLockscreenTransitionViewModel.deviceEntryBackgroundViewAlpha,
+                        primaryBouncerToLockscreenTransitionViewModel
+                            .deviceEntryBackgroundViewAlpha,
+                        lockscreenToDozingTransitionViewModel.deviceEntryBackgroundViewAlpha,
                     )
                     .merge()
                     .onStart {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt
index 3705c2c..40d4193 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt
@@ -347,12 +347,8 @@
                             when {
                                 // If there are no notification icons to show, then it can be hidden
                                 !hasAodIcons -> false
-                                // If we're bypassing, then we're visible
-                                isBypassEnabled -> true
                                 // If we are pulsing (and not bypassing), then we are hidden
                                 isPulseExpanding -> false
-                                // Besides bypass above, they should not be visible on lockscreen
-                                isOnLockscreen -> false
                                 // If notifs are fully gone, then we're visible
                                 areNotifsFullyHidden -> true
                                 // Otherwise, we're hidden
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDozingTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDozingTransitionViewModel.kt
index d3eefca..7abf35d 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDozingTransitionViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDozingTransitionViewModel.kt
@@ -55,16 +55,16 @@
             onCancel = { 1f },
         )
 
+    val deviceEntryBackgroundViewAlpha: Flow<Float> =
+        transitionAnimation.immediatelyTransitionTo(0f)
+
     override val deviceEntryParentViewAlpha: Flow<Float> =
         deviceEntryUdfpsInteractor.isUdfpsEnrolledAndEnabled.flatMapLatest {
             isUdfpsEnrolledAndEnabled ->
             if (isUdfpsEnrolledAndEnabled) {
                 transitionAnimation.immediatelyTransitionTo(1f)
             } else {
-                transitionAnimation.sharedFlow(
-                    duration = 250.milliseconds,
-                    onStep = { 1f - it },
-                )
+                transitionAnimation.sharedFlow(duration = 250.milliseconds, onStep = { 1f - it })
             }
         }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java b/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
index 4e975ff..4c21da5 100644
--- a/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
@@ -369,7 +369,7 @@
     @SysUISingleton
     @MediaCarouselControllerLog
     public static LogBuffer provideMediaCarouselControllerBuffer(LogBufferFactory factory) {
-        return factory.create("MediaCarouselCtlrLog", 20);
+        return factory.create("MediaCarouselCtlrLog", 100);
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaCarouselControllerLogger.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaCarouselControllerLogger.kt
index 1be25a7..9b443f5 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaCarouselControllerLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaCarouselControllerLogger.kt
@@ -39,7 +39,7 @@
             {
                 "Potential memory leak: " +
                     "Removing control panel for $str1 from map without calling #onDestroy"
-            }
+            },
         )
 
     fun logMediaLoaded(key: String, active: Boolean) =
@@ -50,7 +50,7 @@
                 str1 = key
                 bool1 = active
             },
-            { "add player $str1, active: $bool1" }
+            { "add player $str1, active: $bool1" },
         )
 
     fun logMediaRemoved(key: String, userInitiated: Boolean) =
@@ -61,7 +61,7 @@
                 str1 = key
                 bool1 = userInitiated
             },
-            { "removing player $str1, by user $bool1" }
+            { "removing player $str1, by user $bool1" },
         )
 
     fun logRecommendationLoaded(key: String, isActive: Boolean) =
@@ -72,7 +72,7 @@
                 str1 = key
                 bool1 = isActive
             },
-            { "add recommendation $str1, active $bool1" }
+            { "add recommendation $str1, active $bool1" },
         )
 
     fun logRecommendationRemoved(key: String, immediately: Boolean) =
@@ -83,12 +83,24 @@
                 str1 = key
                 bool1 = immediately
             },
-            { "removing recommendation $str1, immediate=$bool1" }
+            { "removing recommendation $str1, immediate=$bool1" },
         )
 
     fun logCarouselHidden() = buffer.log(TAG, LogLevel.DEBUG, {}, { "hiding carousel" })
 
     fun logCarouselVisible() = buffer.log(TAG, LogLevel.DEBUG, {}, { "showing carousel" })
+
+    fun logMediaHostVisibility(location: Int, visible: Boolean) {
+        buffer.log(
+            TAG,
+            LogLevel.DEBUG,
+            {
+                int1 = location
+                bool1 = visible
+            },
+            { "media host visibility changed location=$location, visible:$visible" },
+        )
+    }
 }
 
 private const val TAG = "MediaCarouselCtlrLog"
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/view/MediaHost.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/view/MediaHost.kt
index 5ddc347..11251cd 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/view/MediaHost.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/view/MediaHost.kt
@@ -25,6 +25,7 @@
 import com.android.systemui.media.controls.shared.model.MediaData
 import com.android.systemui.media.controls.shared.model.SmartspaceMediaData
 import com.android.systemui.media.controls.ui.controller.MediaCarouselController
+import com.android.systemui.media.controls.ui.controller.MediaCarouselControllerLogger
 import com.android.systemui.media.controls.ui.controller.MediaHierarchyManager
 import com.android.systemui.media.controls.ui.controller.MediaHostStatesManager
 import com.android.systemui.media.controls.ui.controller.MediaLocation
@@ -41,6 +42,7 @@
     private val mediaDataManager: MediaDataManager,
     private val mediaHostStatesManager: MediaHostStatesManager,
     private val mediaCarouselController: MediaCarouselController,
+    private val debugLogger: MediaCarouselControllerLogger,
 ) : MediaHostState by state {
     lateinit var hostView: UniqueObjectHostView
     var location: Int = -1
@@ -217,6 +219,7 @@
         val newVisibility = if (visible) View.VISIBLE else View.GONE
         if (newVisibility != hostView.visibility) {
             hostView.visibility = newVisibility
+            debugLogger.logMediaHostVisibility(location, visible)
             visibleChangedListeners.forEach { it.invoke(visible) }
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/media/dagger/MediaModule.java b/packages/SystemUI/src/com/android/systemui/media/dagger/MediaModule.java
index 59b98b2..36a9fb3 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dagger/MediaModule.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dagger/MediaModule.java
@@ -22,6 +22,7 @@
 import com.android.systemui.media.controls.domain.MediaDomainModule;
 import com.android.systemui.media.controls.domain.pipeline.MediaDataManager;
 import com.android.systemui.media.controls.ui.controller.MediaCarouselController;
+import com.android.systemui.media.controls.ui.controller.MediaCarouselControllerLogger;
 import com.android.systemui.media.controls.ui.controller.MediaHierarchyManager;
 import com.android.systemui.media.controls.ui.controller.MediaHostStatesManager;
 import com.android.systemui.media.controls.ui.view.MediaHost;
@@ -60,9 +61,10 @@
     @Named(QS_PANEL)
     static MediaHost providesQSMediaHost(MediaHost.MediaHostStateHolder stateHolder,
             MediaHierarchyManager hierarchyManager, MediaDataManager dataManager,
-            MediaHostStatesManager statesManager, MediaCarouselController carouselController) {
+            MediaHostStatesManager statesManager, MediaCarouselController carouselController,
+            MediaCarouselControllerLogger logger) {
         return new MediaHost(stateHolder, hierarchyManager, dataManager, statesManager,
-                carouselController);
+                carouselController, logger);
     }
 
     /** */
@@ -71,9 +73,10 @@
     @Named(QUICK_QS_PANEL)
     static MediaHost providesQuickQSMediaHost(MediaHost.MediaHostStateHolder stateHolder,
             MediaHierarchyManager hierarchyManager, MediaDataManager dataManager,
-            MediaHostStatesManager statesManager, MediaCarouselController carouselController) {
+            MediaHostStatesManager statesManager, MediaCarouselController carouselController,
+            MediaCarouselControllerLogger logger) {
         return new MediaHost(stateHolder, hierarchyManager, dataManager, statesManager,
-                carouselController);
+                carouselController, logger);
     }
 
     /** */
@@ -82,9 +85,10 @@
     @Named(KEYGUARD)
     static MediaHost providesKeyguardMediaHost(MediaHost.MediaHostStateHolder stateHolder,
             MediaHierarchyManager hierarchyManager, MediaDataManager dataManager,
-            MediaHostStatesManager statesManager, MediaCarouselController carouselController) {
+            MediaHostStatesManager statesManager, MediaCarouselController carouselController,
+            MediaCarouselControllerLogger logger) {
         return new MediaHost(stateHolder, hierarchyManager, dataManager, statesManager,
-                carouselController);
+                carouselController, logger);
     }
 
     /** */
@@ -93,9 +97,10 @@
     @Named(DREAM)
     static MediaHost providesDreamMediaHost(MediaHost.MediaHostStateHolder stateHolder,
             MediaHierarchyManager hierarchyManager, MediaDataManager dataManager,
-            MediaHostStatesManager statesManager, MediaCarouselController carouselController) {
+            MediaHostStatesManager statesManager, MediaCarouselController carouselController,
+            MediaCarouselControllerLogger logger) {
         return new MediaHost(stateHolder, hierarchyManager, dataManager, statesManager,
-                carouselController);
+                carouselController, logger);
     }
 
     /** */
@@ -104,9 +109,10 @@
     @Named(COMMUNAL_HUB)
     static MediaHost providesCommunalMediaHost(MediaHost.MediaHostStateHolder stateHolder,
             MediaHierarchyManager hierarchyManager, MediaDataManager dataManager,
-            MediaHostStatesManager statesManager, MediaCarouselController carouselController) {
+            MediaHostStatesManager statesManager, MediaCarouselController carouselController,
+            MediaCarouselControllerLogger logger) {
         return new MediaHost(stateHolder, hierarchyManager, dataManager, statesManager,
-                carouselController);
+                carouselController, logger);
     }
 
     /** Provides a logging buffer related to the media tap-to-transfer chip on the sender device. */
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
index 5048a5d..b3463bd 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
@@ -64,7 +64,6 @@
 import android.view.KeyEvent;
 import android.view.MotionEvent;
 import android.view.Surface;
-import android.view.VelocityTracker;
 import android.view.ViewConfiguration;
 import android.view.WindowInsets;
 import android.view.WindowManager;
@@ -191,7 +190,6 @@
                 }
             };
 
-    private final VelocityTracker mVelocityTracker = VelocityTracker.obtain();
     private final Context mContext;
     private final UserTracker mUserTracker;
     private final OverviewProxyService mOverviewProxyService;
@@ -1042,10 +1040,6 @@
 
             mIsTrackpadThreeFingerSwipe = isTrackpadThreeFingerSwipe(ev);
 
-            // 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();
-
             // Verify if this is in within the touch region and we aren't in immersive mode, and
             // either the bouncer is showing or the notification panel is hidden
             mInputEventReceiver.setBatchingEnabled(false);
@@ -1194,28 +1188,9 @@
 
     private void dispatchToBackAnimation(MotionEvent event) {
         if (mBackAnimation != null) {
-            mVelocityTracker.addMovement(event);
-
-            final float velocityX;
-            final float velocityY;
-            if (event.getAction() == MotionEvent.ACTION_UP) {
-                // Compute the current velocity is expensive (see computeCurrentVelocity), so we
-                // are only doing it when the user completes the gesture.
-                int unitPixelPerSecond = 1000;
-                int maxVelocity = mViewConfiguration.getScaledMaximumFlingVelocity();
-                mVelocityTracker.computeCurrentVelocity(unitPixelPerSecond, maxVelocity);
-                velocityX = mVelocityTracker.getXVelocity();
-                velocityY = mVelocityTracker.getYVelocity();
-            } else {
-                velocityX = Float.NaN;
-                velocityY = Float.NaN;
-            }
-
             mBackAnimation.onBackMotion(
                     /* touchX = */ event.getX(),
                     /* touchY = */ event.getY(),
-                    /* velocityX = */ velocityX,
-                    /* velocityY = */ velocityY,
                     /* keyAction = */ event.getActionMasked(),
                     /* swipeEdge = */ mIsOnLeftEdge ? BackEvent.EDGE_LEFT : BackEvent.EDGE_RIGHT);
         }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
index 1511f31..fa987dd 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
@@ -255,7 +255,8 @@
      * @return size in pixels of QQS
      */
     public int getQqsHeight() {
-        return mHeader.getHeight();
+        SceneContainerFlag.assertInNewMode();
+        return mHeader.getMeasuredHeight();
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTileIcon.kt b/packages/SystemUI/src/com/android/systemui/qs/QSTileIcon.kt
index ef7e7eb..62694ce 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSTileIcon.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTileIcon.kt
@@ -22,13 +22,18 @@
 
 /**
  * Creates a [QSTile.Icon] from an [Icon].
- * * [Icon.Loaded] -> [QSTileImpl.DrawableIcon]
+ * * [Icon.Loaded] && [resId] null -> [QSTileImpl.DrawableIcon]
+ * * [Icon.Loaded] && [resId] available -> [QSTileImpl.DrawableIconWithRes]
  * * [Icon.Resource] -> [QSTileImpl.ResourceIcon]
  */
-fun Icon.asQSTileIcon(): QSTile.Icon {
+fun Icon.asQSTileIcon(resId: Int?): QSTile.Icon {
     return when (this) {
         is Icon.Loaded -> {
-            QSTileImpl.DrawableIcon(this.drawable)
+            if (resId != null) {
+                QSTileImpl.DrawableIconWithRes(this.drawable, resId)
+            } else {
+                QSTileImpl.DrawableIcon(this.drawable)
+            }
         }
         is Icon.Resource -> {
             QSTileImpl.ResourceIcon.get(this.res)
diff --git a/packages/SystemUI/src/com/android/systemui/qs/composefragment/QSFragmentCompose.kt b/packages/SystemUI/src/com/android/systemui/qs/composefragment/QSFragmentCompose.kt
index 65c29b8..9c5231d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/composefragment/QSFragmentCompose.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/composefragment/QSFragmentCompose.kt
@@ -92,6 +92,7 @@
 import com.android.systemui.qs.composefragment.SceneKeys.QuickQuickSettings
 import com.android.systemui.qs.composefragment.SceneKeys.QuickSettings
 import com.android.systemui.qs.composefragment.SceneKeys.toIdleSceneKey
+import com.android.systemui.qs.composefragment.ui.NotificationScrimClipParams
 import com.android.systemui.qs.composefragment.ui.notificationScrimClip
 import com.android.systemui.qs.composefragment.ui.quickQuickSettingsToQuickSettings
 import com.android.systemui.qs.composefragment.viewmodel.QSFragmentComposeViewModel
@@ -149,20 +150,12 @@
     private val notificationScrimClippingParams =
         object {
             var isEnabled by mutableStateOf(false)
-            var leftInset by mutableStateOf(0)
-            var rightInset by mutableStateOf(0)
-            var top by mutableStateOf(0)
-            var bottom by mutableStateOf(0)
-            var radius by mutableStateOf(0)
+            var params by mutableStateOf(NotificationScrimClipParams())
 
             fun dump(pw: IndentingPrintWriter) {
                 pw.printSection("NotificationScrimClippingParams") {
                     pw.println("isEnabled", isEnabled)
-                    pw.println("leftInset", "${leftInset}px")
-                    pw.println("rightInset", "${rightInset}px")
-                    pw.println("top", "${top}px")
-                    pw.println("bottom", "${bottom}px")
-                    pw.println("radius", "${radius}px")
+                    pw.println("params", params)
                 }
             }
         }
@@ -216,7 +209,7 @@
             FrameLayoutTouchPassthrough(
                 context,
                 { notificationScrimClippingParams.isEnabled },
-                { notificationScrimClippingParams.top },
+                { notificationScrimClippingParams.params.top },
             )
         frame.addView(
             composeView,
@@ -237,13 +230,7 @@
                     Modifier.windowInsetsPadding(WindowInsets.navigationBars).thenIf(
                         notificationScrimClippingParams.isEnabled
                     ) {
-                        Modifier.notificationScrimClip(
-                            notificationScrimClippingParams.leftInset,
-                            notificationScrimClippingParams.top,
-                            notificationScrimClippingParams.rightInset,
-                            notificationScrimClippingParams.bottom,
-                            notificationScrimClippingParams.radius,
-                        )
+                        Modifier.notificationScrimClip { notificationScrimClippingParams.params }
                     },
             ) {
                 val isEditing by
@@ -445,13 +432,14 @@
         fullWidth: Boolean,
     ) {
         notificationScrimClippingParams.isEnabled = visible
-        notificationScrimClippingParams.top = top
-        notificationScrimClippingParams.bottom = bottom
-        // Full width means that QS will show in the entire width allocated to it (for example
-        // phone) vs. showing in a narrower column (for example, tablet portrait).
-        notificationScrimClippingParams.leftInset = if (fullWidth) 0 else leftInset
-        notificationScrimClippingParams.rightInset = if (fullWidth) 0 else rightInset
-        notificationScrimClippingParams.radius = cornerRadius
+        notificationScrimClippingParams.params =
+            NotificationScrimClipParams(
+                top,
+                bottom,
+                if (fullWidth) 0 else leftInset,
+                if (fullWidth) 0 else rightInset,
+                cornerRadius,
+            )
     }
 
     override fun isFullyCollapsed(): Boolean {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/composefragment/ui/NotificationScrimClip.kt b/packages/SystemUI/src/com/android/systemui/qs/composefragment/ui/NotificationScrimClip.kt
index 93c6445..c912bd5 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/composefragment/ui/NotificationScrimClip.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/composefragment/ui/NotificationScrimClip.kt
@@ -31,87 +31,73 @@
  * ([ClipOp.Difference]) a `RoundRect(-leftInset, top, width + rightInset, bottom, radius, radius)`
  * from the QS container.
  */
-fun Modifier.notificationScrimClip(
-    leftInset: Int,
-    top: Int,
-    rightInset: Int,
-    bottom: Int,
-    radius: Int
-): Modifier {
-    return this then NotificationScrimClipElement(leftInset, top, rightInset, bottom, radius)
+fun Modifier.notificationScrimClip(clipParams: () -> NotificationScrimClipParams): Modifier {
+    return this then NotificationScrimClipElement(clipParams)
 }
 
-private class NotificationScrimClipNode(
-    var leftInset: Float,
-    var top: Float,
-    var rightInset: Float,
-    var bottom: Float,
-    var radius: Float,
-) : DrawModifierNode, Modifier.Node() {
+private class NotificationScrimClipNode(var clipParams: () -> NotificationScrimClipParams) :
+    DrawModifierNode, Modifier.Node() {
     private val path = Path()
 
-    var invalidated = true
+    private var lastClipParams = NotificationScrimClipParams()
 
     override fun ContentDrawScope.draw() {
-        if (invalidated) {
+        val newClipParams = clipParams()
+        if (newClipParams != lastClipParams) {
+            lastClipParams = newClipParams
+            applyClipParams(path, lastClipParams)
+        }
+        clipPath(path, ClipOp.Difference) { this@draw.drawContent() }
+    }
+
+    private fun ContentDrawScope.applyClipParams(
+        path: Path,
+        clipParams: NotificationScrimClipParams,
+    ) {
+        with(clipParams) {
             path.rewind()
             path
                 .asAndroidPath()
                 .addRoundRect(
-                    -leftInset,
-                    top,
+                    -leftInset.toFloat(),
+                    top.toFloat(),
                     size.width + rightInset,
-                    bottom,
-                    radius,
-                    radius,
-                    android.graphics.Path.Direction.CW
+                    bottom.toFloat(),
+                    radius.toFloat(),
+                    radius.toFloat(),
+                    android.graphics.Path.Direction.CW,
                 )
-            invalidated = false
         }
-        clipPath(path, ClipOp.Difference) { this@draw.drawContent() }
     }
 }
 
-private data class NotificationScrimClipElement(
-    val leftInset: Int,
-    val top: Int,
-    val rightInset: Int,
-    val bottom: Int,
-    val radius: Int,
-) : ModifierNodeElement<NotificationScrimClipNode>() {
+private data class NotificationScrimClipElement(val clipParams: () -> NotificationScrimClipParams) :
+    ModifierNodeElement<NotificationScrimClipNode>() {
     override fun create(): NotificationScrimClipNode {
-        return NotificationScrimClipNode(
-            leftInset.toFloat(),
-            top.toFloat(),
-            rightInset.toFloat(),
-            bottom.toFloat(),
-            radius.toFloat(),
-        )
+        return NotificationScrimClipNode(clipParams)
     }
 
     override fun update(node: NotificationScrimClipNode) {
-        val changed =
-            node.leftInset != leftInset.toFloat() ||
-                node.top != top.toFloat() ||
-                node.rightInset != rightInset.toFloat() ||
-                node.bottom != bottom.toFloat() ||
-                node.radius != radius.toFloat()
-        if (changed) {
-            node.leftInset = leftInset.toFloat()
-            node.top = top.toFloat()
-            node.rightInset = rightInset.toFloat()
-            node.bottom = bottom.toFloat()
-            node.radius = radius.toFloat()
-            node.invalidated = true
-        }
+        node.clipParams = clipParams
     }
 
     override fun InspectorInfo.inspectableProperties() {
         name = "notificationScrimClip"
-        properties["leftInset"] = leftInset
-        properties["top"] = top
-        properties["rightInset"] = rightInset
-        properties["bottom"] = bottom
-        properties["radius"] = radius
+        with(clipParams()) {
+            properties["leftInset"] = leftInset
+            properties["top"] = top
+            properties["rightInset"] = rightInset
+            properties["bottom"] = bottom
+            properties["radius"] = radius
+        }
     }
 }
+
+/** Params for [notificationScrimClip]. */
+data class NotificationScrimClipParams(
+    val top: Int = 0,
+    val bottom: Int = 0,
+    val leftInset: Int = 0,
+    val rightInset: Int = 0,
+    val radius: Int = 0,
+)
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/dagger/PanelsModule.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/dagger/PanelsModule.kt
index 1fe54e4..31e867e 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/dagger/PanelsModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/dagger/PanelsModule.kt
@@ -31,12 +31,12 @@
 import com.android.systemui.qs.panels.ui.compose.PaginatableGridLayout
 import com.android.systemui.qs.panels.ui.compose.PaginatedGridLayout
 import com.android.systemui.qs.panels.ui.compose.infinitegrid.InfiniteGridLayout
-import com.android.systemui.qs.panels.ui.viewmodel.FixedColumnsSizeViewModel
-import com.android.systemui.qs.panels.ui.viewmodel.FixedColumnsSizeViewModelImpl
 import com.android.systemui.qs.panels.ui.viewmodel.IconLabelVisibilityViewModel
 import com.android.systemui.qs.panels.ui.viewmodel.IconLabelVisibilityViewModelImpl
 import com.android.systemui.qs.panels.ui.viewmodel.IconTilesViewModel
 import com.android.systemui.qs.panels.ui.viewmodel.IconTilesViewModelImpl
+import com.android.systemui.qs.panels.ui.viewmodel.QSColumnsSizeViewModelImpl
+import com.android.systemui.qs.panels.ui.viewmodel.QSColumnsViewModel
 import dagger.Binds
 import dagger.Module
 import dagger.Provides
@@ -55,7 +55,7 @@
 
     @Binds fun bindIconTilesViewModel(impl: IconTilesViewModelImpl): IconTilesViewModel
 
-    @Binds fun bindGridSizeViewModel(impl: FixedColumnsSizeViewModelImpl): FixedColumnsSizeViewModel
+    @Binds fun bindQSColumnsViewModel(impl: QSColumnsSizeViewModelImpl): QSColumnsViewModel
 
     @Binds
     fun bindIconLabelVisibilityViewModel(
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/data/repository/FixedColumnsRepository.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/data/repository/FixedColumnsRepository.kt
deleted file mode 100644
index 32ce973..0000000
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/data/repository/FixedColumnsRepository.kt
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright (C) 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES 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.panels.data.repository
-
-import com.android.systemui.dagger.SysUISingleton
-import javax.inject.Inject
-import kotlinx.coroutines.flow.MutableStateFlow
-import kotlinx.coroutines.flow.StateFlow
-import kotlinx.coroutines.flow.asStateFlow
-
-@SysUISingleton
-class FixedColumnsRepository @Inject constructor() {
-    // Number of columns in the narrowest state for consistency
-    private val _columns = MutableStateFlow(4)
-    val columns: StateFlow<Int> = _columns.asStateFlow()
-}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/data/repository/QSColumnsRepository.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/data/repository/QSColumnsRepository.kt
new file mode 100644
index 0000000..082f622
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/data/repository/QSColumnsRepository.kt
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.panels.data.repository
+
+import android.content.res.Resources
+import com.android.systemui.common.ui.data.repository.ConfigurationRepository
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.res.R
+import com.android.systemui.shade.shared.flag.DualShade
+import com.android.systemui.util.kotlin.emitOnStart
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.flowOf
+import kotlinx.coroutines.flow.mapLatest
+import kotlinx.coroutines.flow.stateIn
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@SysUISingleton
+class QSColumnsRepository
+@Inject
+constructor(
+    @Application scope: CoroutineScope,
+    @Main private val resources: Resources,
+    configurationRepository: ConfigurationRepository,
+) {
+    val columns: StateFlow<Int> =
+        if (DualShade.isEnabled) {
+                flowOf(resources.getInteger(R.integer.quick_settings_dual_shade_num_columns))
+            } else {
+                configurationRepository.onConfigurationChange.emitOnStart().mapLatest {
+                    resources.getInteger(R.integer.quick_settings_infinite_grid_num_columns)
+                }
+            }
+            .stateIn(
+                scope,
+                SharingStarted.WhileSubscribed(),
+                resources.getInteger(R.integer.quick_settings_infinite_grid_num_columns),
+            )
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/domain/interactor/FixedColumnsSizeInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/domain/interactor/QSColumnsInteractor.kt
similarity index 84%
rename from packages/SystemUI/src/com/android/systemui/qs/panels/domain/interactor/FixedColumnsSizeInteractor.kt
rename to packages/SystemUI/src/com/android/systemui/qs/panels/domain/interactor/QSColumnsInteractor.kt
index 9591002..9b45c56 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/domain/interactor/FixedColumnsSizeInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/domain/interactor/QSColumnsInteractor.kt
@@ -17,11 +17,11 @@
 package com.android.systemui.qs.panels.domain.interactor
 
 import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.qs.panels.data.repository.FixedColumnsRepository
+import com.android.systemui.qs.panels.data.repository.QSColumnsRepository
 import javax.inject.Inject
 import kotlinx.coroutines.flow.StateFlow
 
 @SysUISingleton
-class FixedColumnsSizeInteractor @Inject constructor(repo: FixedColumnsRepository) {
+class QSColumnsInteractor @Inject constructor(repo: QSColumnsRepository) {
     val columns: StateFlow<Int> = repo.columns
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/PagerDots.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/PagerDots.kt
index 331aabb..0dedfe1 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/PagerDots.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/PagerDots.kt
@@ -46,6 +46,8 @@
 import kotlin.math.absoluteValue
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.launch
+import platform.test.motion.compose.values.MotionTestValueKey
+import platform.test.motion.compose.values.motionTestValues
 
 @Composable
 fun PagerDots(
@@ -93,13 +95,22 @@
     }
 
     Row(
-        modifier = modifier.wrapContentWidth().pagerDotsSemantics(pagerState, coroutineScope),
+        modifier =
+            modifier
+                .motionTestValues { activeMarkerWidth exportAs PagerDotsMotionKeys.indicatorWidth }
+                .wrapContentWidth()
+                .pagerDotsSemantics(pagerState, coroutineScope),
         horizontalArrangement = spacedBy(spaceSize),
         verticalAlignment = Alignment.CenterVertically,
     ) {
         // This means that the active rounded rect has to be drawn between the current page
         // and the previous one (as we are animating back), or the current one if not transitioning
-        val withPrevious = pagerState.currentPageOffsetFraction <= 0 || pagerState.isOverscrolling()
+        val withPrevious by
+            remember(pagerState) {
+                derivedStateOf {
+                    pagerState.currentPageOffsetFraction <= 0 || pagerState.isOverscrolling()
+                }
+            }
         repeat(pagerState.pageCount) { page ->
             Canvas(Modifier.size(dotSize)) {
                 val rtl = layoutDirection == LayoutDirection.Rtl
@@ -127,6 +138,10 @@
     }
 }
 
+object PagerDotsMotionKeys {
+    val indicatorWidth = MotionTestValueKey<Dp>("indicatorWidth")
+}
+
 private fun Modifier.pagerDotsSemantics(
     pagerState: PagerState,
     coroutineScope: CoroutineScope,
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/InfiniteGridLayout.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/InfiniteGridLayout.kt
index 3ba49ad..6920e49 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/InfiniteGridLayout.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/InfiniteGridLayout.kt
@@ -31,8 +31,8 @@
 import com.android.systemui.qs.panels.ui.compose.PaginatableGridLayout
 import com.android.systemui.qs.panels.ui.compose.rememberEditListState
 import com.android.systemui.qs.panels.ui.viewmodel.EditTileViewModel
-import com.android.systemui.qs.panels.ui.viewmodel.FixedColumnsSizeViewModel
 import com.android.systemui.qs.panels.ui.viewmodel.IconTilesViewModel
+import com.android.systemui.qs.panels.ui.viewmodel.QSColumnsViewModel
 import com.android.systemui.qs.panels.ui.viewmodel.TileSquishinessViewModel
 import com.android.systemui.qs.panels.ui.viewmodel.TileViewModel
 import com.android.systemui.qs.pipeline.shared.TileSpec
@@ -45,7 +45,7 @@
 @Inject
 constructor(
     private val iconTilesViewModel: IconTilesViewModel,
-    private val gridSizeViewModel: FixedColumnsSizeViewModel,
+    private val gridSizeViewModel: QSColumnsViewModel,
     private val squishinessViewModel: TileSquishinessViewModel,
 ) : PaginatableGridLayout {
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/PaginatedGridViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/PaginatedGridViewModel.kt
index d4f8298..78212b2 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/PaginatedGridViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/PaginatedGridViewModel.kt
@@ -29,13 +29,13 @@
 @Inject
 constructor(
     iconTilesViewModel: IconTilesViewModel,
-    gridSizeViewModel: FixedColumnsSizeViewModel,
+    gridSizeViewModel: QSColumnsViewModel,
     iconLabelVisibilityViewModel: IconLabelVisibilityViewModel,
     paginatedGridInteractor: PaginatedGridInteractor,
     @Application applicationScope: CoroutineScope,
 ) :
     IconTilesViewModel by iconTilesViewModel,
-    FixedColumnsSizeViewModel by gridSizeViewModel,
+    QSColumnsViewModel by gridSizeViewModel,
     IconLabelVisibilityViewModel by iconLabelVisibilityViewModel {
     val rows =
         paginatedGridInteractor.rows.stateIn(
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/PartitionedGridViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/PartitionedGridViewModel.kt
deleted file mode 100644
index 2049edb..0000000
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/PartitionedGridViewModel.kt
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright (C) 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES 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.panels.ui.viewmodel
-
-import com.android.systemui.dagger.SysUISingleton
-import javax.inject.Inject
-
-@SysUISingleton
-class PartitionedGridViewModel
-@Inject
-constructor(
-    iconTilesViewModel: IconTilesViewModel,
-    gridSizeViewModel: FixedColumnsSizeViewModel,
-    iconLabelVisibilityViewModel: IconLabelVisibilityViewModel,
-) :
-    IconTilesViewModel by iconTilesViewModel,
-    FixedColumnsSizeViewModel by gridSizeViewModel,
-    IconLabelVisibilityViewModel by iconLabelVisibilityViewModel
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/FixedColumnsSizeViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/QSColumnsViewModel.kt
similarity index 78%
rename from packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/FixedColumnsSizeViewModel.kt
rename to packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/QSColumnsViewModel.kt
index 865c86b..0f1c77e 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/FixedColumnsSizeViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/QSColumnsViewModel.kt
@@ -17,16 +17,16 @@
 package com.android.systemui.qs.panels.ui.viewmodel
 
 import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.qs.panels.domain.interactor.FixedColumnsSizeInteractor
+import com.android.systemui.qs.panels.domain.interactor.QSColumnsInteractor
 import javax.inject.Inject
 import kotlinx.coroutines.flow.StateFlow
 
-interface FixedColumnsSizeViewModel {
+interface QSColumnsViewModel {
     val columns: StateFlow<Int>
 }
 
 @SysUISingleton
-class FixedColumnsSizeViewModelImpl @Inject constructor(interactor: FixedColumnsSizeInteractor) :
-    FixedColumnsSizeViewModel {
+class QSColumnsSizeViewModelImpl @Inject constructor(interactor: QSColumnsInteractor) :
+    QSColumnsViewModel {
     override val columns: StateFlow<Int> = interactor.columns
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/QuickQuickSettingsViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/QuickQuickSettingsViewModel.kt
index 88e3019..72b586a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/QuickQuickSettingsViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/QuickQuickSettingsViewModel.kt
@@ -40,14 +40,14 @@
 @Inject
 constructor(
     tilesInteractor: CurrentTilesInteractor,
-    fixedColumnsSizeViewModel: FixedColumnsSizeViewModel,
+    qsColumnsViewModel: QSColumnsViewModel,
     quickQuickSettingsRowInteractor: QuickQuickSettingsRowInteractor,
     val squishinessViewModel: TileSquishinessViewModel,
     private val iconTilesViewModel: IconTilesViewModel,
     @Application private val applicationScope: CoroutineScope,
 ) {
 
-    val columns = fixedColumnsSizeViewModel.columns
+    val columns = qsColumnsViewModel.columns
 
     private val rows =
         quickQuickSettingsRowInteractor.rows.stateIn(
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/ModesTile.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/ModesTile.kt
index cf2db6c..3bbe624 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/ModesTile.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/ModesTile.kt
@@ -121,7 +121,7 @@
         state?.apply {
             this.state = tileState.activationState.legacyState
             val tileStateIcon = tileState.icon()
-            icon = tileStateIcon?.asQSTileIcon() ?: ResourceIcon.get(ICON_RES_ID)
+            icon = tileStateIcon?.asQSTileIcon(tileState.iconRes) ?: ResourceIcon.get(ICON_RES_ID)
             label = tileLabel
             secondaryLabel = tileState.secondaryLabel
             contentDescription = tileState.contentDescription
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/RecordIssueTile.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/RecordIssueTile.kt
index d89e73d..fb406d4 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/RecordIssueTile.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/RecordIssueTile.kt
@@ -45,10 +45,11 @@
 import com.android.systemui.qs.tileimpl.QSTileImpl
 import com.android.systemui.recordissue.IssueRecordingService.Companion.getStartIntent
 import com.android.systemui.recordissue.IssueRecordingService.Companion.getStopIntent
+import com.android.systemui.recordissue.IssueRecordingServiceConnection
 import com.android.systemui.recordissue.IssueRecordingState
 import com.android.systemui.recordissue.RecordIssueDialogDelegate
 import com.android.systemui.recordissue.RecordIssueModule.Companion.TILE_SPEC
-import com.android.systemui.recordissue.TraceurMessageSender
+import com.android.systemui.recordissue.TraceurConnection
 import com.android.systemui.res.R
 import com.android.systemui.screenrecord.RecordingController
 import com.android.systemui.screenrecord.RecordingService
@@ -66,7 +67,7 @@
 constructor(
     host: QSHost,
     uiEventLogger: QsEventLogger,
-    @Background backgroundLooper: Looper,
+    @Background private val backgroundLooper: Looper,
     @Main mainHandler: Handler,
     falsingManager: FalsingManager,
     metricsLogger: MetricsLogger,
@@ -78,7 +79,8 @@
     private val dialogTransitionAnimator: DialogTransitionAnimator,
     private val panelInteractor: PanelInteractor,
     private val userContextProvider: UserContextProvider,
-    private val traceurMessageSender: TraceurMessageSender,
+    irsConnProvider: IssueRecordingServiceConnection.Provider,
+    traceurConnProvider: TraceurConnection.Provider,
     @Background private val bgExecutor: Executor,
     private val issueRecordingState: IssueRecordingState,
     private val delegateFactory: RecordIssueDialogDelegate.Factory,
@@ -93,11 +95,20 @@
         metricsLogger,
         statusBarStateController,
         activityStarter,
-        qsLogger
+        qsLogger,
     ) {
 
     private val onRecordingChangeListener = Runnable { refreshState() }
 
+    private val irsConnection: IssueRecordingServiceConnection = irsConnProvider.create()
+    private val traceurConnection =
+        traceurConnProvider.create().apply {
+            onBound.add {
+                getTags(issueRecordingState)
+                doUnBind()
+            }
+        }
+
     override fun handleSetListening(listening: Boolean) {
         super.handleSetListening(listening)
         if (listening) {
@@ -109,7 +120,7 @@
 
     override fun handleDestroy() {
         super.handleDestroy()
-        bgExecutor.execute { traceurMessageSender.unbindFromTraceur(mContext) }
+        bgExecutor.execute { irsConnection.doUnBind() }
     }
 
     override fun getTileLabel(): CharSequence = mContext.getString(R.string.qs_record_issue_label)
@@ -142,7 +153,7 @@
             DELAY_MS,
             INTERVAL_MS,
             pendingServiceIntent(getStartIntent(userContextProvider.userContext)),
-            pendingServiceIntent(getStopIntent(userContextProvider.userContext))
+            pendingServiceIntent(getStopIntent(userContextProvider.userContext)),
         )
 
     private fun stopIssueRecordingService() =
@@ -154,10 +165,19 @@
             userContextProvider.userContext,
             RecordingService.REQUEST_CODE,
             action,
-            PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
+            PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE,
         )
 
     private fun showPrompt(expandable: Expandable?) {
+        bgExecutor.execute {
+            // We only want to get the tags once per session, as this is not likely to change, if at
+            // all on a month to month basis. Using onBound's size is a way to verify if the tag
+            // retrieval has already happened or not.
+            if (traceurConnection.onBound.isNotEmpty()) {
+                traceurConnection.doBind()
+            }
+            irsConnection.doBind()
+        }
         val dialog: AlertDialog =
             delegateFactory
                 .create {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/modes/domain/interactor/ModesTileDataInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/modes/domain/interactor/ModesTileDataInteractor.kt
index 5d44ead..40591bf 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/modes/domain/interactor/ModesTileDataInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/modes/domain/interactor/ModesTileDataInteractor.kt
@@ -76,14 +76,14 @@
         } else {
             return ModesTileModel(
                 isActivated = activeModes.isAnyActive(),
-                icon = context.getDrawable(ModesTile.ICON_RES_ID)!!.asIcon(),
+                icon = Icon.Resource(ModesTile.ICON_RES_ID, null),
                 iconResId = ModesTile.ICON_RES_ID,
                 activeModes = activeModes.modeNames,
             )
         }
     }
 
-    private data class TileIcon(val icon: Icon.Loaded, val resId: Int?)
+    private data class TileIcon(val icon: Icon, val resId: Int?)
 
     private fun getTileIcon(activeMode: ZenModeInfo?): TileIcon {
         return if (activeMode != null) {
@@ -94,7 +94,7 @@
                 TileIcon(activeMode.icon.drawable.asIcon(), null)
             }
         } else {
-            TileIcon(context.getDrawable(ModesTile.ICON_RES_ID)!!.asIcon(), ModesTile.ICON_RES_ID)
+            TileIcon(Icon.Resource(ModesTile.ICON_RES_ID, null), ModesTile.ICON_RES_ID)
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/modes/domain/model/ModesTileModel.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/modes/domain/model/ModesTileModel.kt
index db48123..9c31e32 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/modes/domain/model/ModesTileModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/modes/domain/model/ModesTileModel.kt
@@ -21,12 +21,12 @@
 data class ModesTileModel(
     val isActivated: Boolean,
     val activeModes: List<String>,
-    val icon: Icon.Loaded,
+    val icon: Icon,
 
     /**
      * Resource id corresponding to [icon]. Will only be present if it's know to correspond to a
      * resource with a known id in SystemUI (such as resources from `android.R`,
      * `com.android.internal.R`, or `com.android.systemui.res` itself).
      */
-    val iconResId: Int? = null
+    val iconResId: Int? = null,
 )
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/modes/ui/ModesTileMapper.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/modes/ui/ModesTileMapper.kt
index 69da313..801a0ce 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/modes/ui/ModesTileMapper.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/modes/ui/ModesTileMapper.kt
@@ -18,7 +18,9 @@
 
 import android.content.res.Resources
 import android.icu.text.MessageFormat
+import android.util.Log
 import android.widget.Button
+import com.android.systemui.common.shared.model.Icon
 import com.android.systemui.dagger.qualifiers.Main
 import com.android.systemui.qs.tiles.base.interactor.QSTileDataToStateMapper
 import com.android.systemui.qs.tiles.impl.modes.domain.model.ModesTileModel
@@ -30,14 +32,30 @@
 
 class ModesTileMapper
 @Inject
-constructor(
-    @Main private val resources: Resources,
-    val theme: Resources.Theme,
-) : QSTileDataToStateMapper<ModesTileModel> {
+constructor(@Main private val resources: Resources, val theme: Resources.Theme) :
+    QSTileDataToStateMapper<ModesTileModel> {
     override fun map(config: QSTileConfig, data: ModesTileModel): QSTileState =
         QSTileState.build(resources, theme, config.uiConfig) {
-            iconRes = data.iconResId
-            icon = { data.icon }
+            val loadedIcon: Icon.Loaded =
+                when (val dataIcon = data.icon) {
+                    is Icon.Resource -> {
+                        if (iconRes != dataIcon.res) {
+                            Log.wtf(
+                                "ModesTileMapper",
+                                "Icon.Resource.res & iconResId are not identical",
+                            )
+                        }
+                        iconRes = dataIcon.res
+                        Icon.Loaded(resources.getDrawable(dataIcon.res, theme), null)
+                    }
+                    is Icon.Loaded -> {
+                        iconRes = data.iconResId
+                        dataIcon
+                    }
+                }
+
+            icon = { loadedIcon }
+
             activationState =
                 if (data.isActivated) {
                     QSTileState.ActivationState.ACTIVE
@@ -47,10 +65,7 @@
             secondaryLabel = getModesStatus(data, resources)
             contentDescription = "$label. $secondaryLabel"
             supportedActions =
-                setOf(
-                    QSTileState.UserAction.CLICK,
-                    QSTileState.UserAction.LONG_CLICK,
-                )
+                setOf(QSTileState.UserAction.CLICK, QSTileState.UserAction.LONG_CLICK)
             sideViewIcon = QSTileState.SideViewIcon.Chevron
             expandedAccessibilityClass = Button::class
         }
diff --git a/packages/SystemUI/src/com/android/systemui/recordissue/IssueRecordingService.kt b/packages/SystemUI/src/com/android/systemui/recordissue/IssueRecordingService.kt
index 4d2bc91..3f875bc 100644
--- a/packages/SystemUI/src/com/android/systemui/recordissue/IssueRecordingService.kt
+++ b/packages/SystemUI/src/com/android/systemui/recordissue/IssueRecordingService.kt
@@ -23,9 +23,12 @@
 import android.content.res.Resources
 import android.net.Uri
 import android.os.Handler
+import android.os.IBinder
+import android.os.Looper
 import android.util.Log
 import com.android.internal.logging.UiEventLogger
 import com.android.systemui.animation.DialogTransitionAnimator
+import com.android.systemui.dagger.qualifiers.Background
 import com.android.systemui.dagger.qualifiers.LongRunning
 import com.android.systemui.dagger.qualifiers.Main
 import com.android.systemui.qs.pipeline.domain.interactor.PanelInteractor
@@ -42,6 +45,7 @@
 @Inject
 constructor(
     controller: RecordingController,
+    @Background private val bgLooper: Looper,
     @LongRunning private val bgExecutor: Executor,
     @Main handler: Handler,
     uiEventLogger: UiEventLogger,
@@ -50,8 +54,8 @@
     keyguardDismissUtil: KeyguardDismissUtil,
     dialogTransitionAnimator: DialogTransitionAnimator,
     panelInteractor: PanelInteractor,
-    traceurMessageSender: TraceurMessageSender,
     private val issueRecordingState: IssueRecordingState,
+    traceurConnectionProvider: TraceurConnection.Provider,
     iActivityManager: IActivityManager,
 ) :
     RecordingService(
@@ -64,18 +68,37 @@
         keyguardDismissUtil,
     ) {
 
+    private val traceurConnection: TraceurConnection = traceurConnectionProvider.create()
+
     private val session =
         IssueRecordingServiceSession(
             bgExecutor,
             dialogTransitionAnimator,
             panelInteractor,
-            traceurMessageSender,
+            traceurConnection,
             issueRecordingState,
             iActivityManager,
             notificationManager,
             userContextProvider,
         )
 
+    /**
+     * It is necessary to bind to IssueRecordingService from the Record Issue Tile because there are
+     * instances where this service is not created in the same user profile as the record issue tile
+     * aka, headless system user mode. In those instances, the TraceurConnection will be considered
+     * a leak in between notification actions unless the tile is bound to this service to keep it
+     * alive.
+     */
+    override fun onBind(intent: Intent): IBinder? {
+        traceurConnection.doBind()
+        return super.onBind(intent)
+    }
+
+    override fun onUnbind(intent: Intent?): Boolean {
+        traceurConnection.doUnBind()
+        return super.onUnbind(intent)
+    }
+
     override fun getTag(): String = TAG
 
     override fun getChannelId(): String = CHANNEL_ID
@@ -99,7 +122,6 @@
                 session.share(
                     intent.getIntExtra(EXTRA_NOTIFICATION_ID, mNotificationId),
                     intent.getParcelableExtra(EXTRA_PATH, Uri::class.java),
-                    this,
                 )
                 // Unlike all other actions, action_share has different behavior for the screen
                 // recording qs tile than it does for the record issue qs tile. Return sticky to
diff --git a/packages/SystemUI/src/com/android/systemui/recordissue/IssueRecordingServiceConnection.kt b/packages/SystemUI/src/com/android/systemui/recordissue/IssueRecordingServiceConnection.kt
new file mode 100644
index 0000000..85a5805
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recordissue/IssueRecordingServiceConnection.kt
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.recordissue
+
+import android.content.Intent
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.settings.UserContextProvider
+import com.android.traceur.MessageConstants.SYSTEM_UI_PACKAGE_NAME
+import javax.inject.Inject
+
+/**
+ * It is necessary to bind to IssueRecordingService from the Record Issue Tile because there are
+ * instances where this service is not created in the same user profile as the record issue tile
+ * aka, headless system user mode. In those instances, the TraceurConnection will be considered a
+ * leak in between notification actions unless the tile is bound to this service to keep it alive.
+ */
+class IssueRecordingServiceConnection(userContextProvider: UserContextProvider) :
+    UserAwareConnection(
+        userContextProvider,
+        Intent().setClassName(SYSTEM_UI_PACKAGE_NAME, IssueRecordingService::class.java.name),
+    ) {
+    @SysUISingleton
+    class Provider @Inject constructor(private val userContextProvider: UserContextProvider) {
+        fun create() = IssueRecordingServiceConnection(userContextProvider)
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recordissue/IssueRecordingServiceSession.kt b/packages/SystemUI/src/com/android/systemui/recordissue/IssueRecordingServiceSession.kt
index e4d3e6c..ad9b4fe 100644
--- a/packages/SystemUI/src/com/android/systemui/recordissue/IssueRecordingServiceSession.kt
+++ b/packages/SystemUI/src/com/android/systemui/recordissue/IssueRecordingServiceSession.kt
@@ -19,7 +19,6 @@
 import android.app.IActivityManager
 import android.app.NotificationManager
 import android.content.ContentResolver
-import android.content.Context
 import android.net.Uri
 import android.os.UserHandle
 import android.provider.Settings
@@ -42,7 +41,7 @@
     private val bgExecutor: Executor,
     private val dialogTransitionAnimator: DialogTransitionAnimator,
     private val panelInteractor: PanelInteractor,
-    private val traceurMessageSender: TraceurMessageSender,
+    private val traceurConnection: TraceurConnection,
     private val issueRecordingState: IssueRecordingState,
     private val iActivityManager: IActivityManager,
     private val notificationManager: NotificationManager,
@@ -50,7 +49,7 @@
 ) {
 
     fun start() {
-        bgExecutor.execute { traceurMessageSender.startTracing(issueRecordingState.traceConfig) }
+        bgExecutor.execute { traceurConnection.startTracing(issueRecordingState.traceConfig) }
         issueRecordingState.isRecording = true
     }
 
@@ -59,12 +58,12 @@
             if (issueRecordingState.traceConfig.longTrace) {
                 Settings.Global.putInt(contentResolver, NOTIFY_SESSION_ENDED_SETTING, DISABLED)
             }
-            traceurMessageSender.stopTracing()
+            traceurConnection.stopTracing()
         }
         issueRecordingState.isRecording = false
     }
 
-    fun share(notificationId: Int, screenRecording: Uri?, context: Context) {
+    fun share(notificationId: Int, screenRecording: Uri?) {
         bgExecutor.execute {
             notificationManager.cancelAsUser(
                 null,
@@ -75,7 +74,7 @@
             if (issueRecordingState.takeBugreport) {
                 iActivityManager.requestBugReportWithExtraAttachment(screenRecording)
             } else {
-                traceurMessageSender.shareTraces(context, screenRecording)
+                traceurConnection.shareTraces(screenRecording)
             }
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/recordissue/RecordIssueDialogDelegate.kt b/packages/SystemUI/src/com/android/systemui/recordissue/RecordIssueDialogDelegate.kt
index ed67e64..6758c3b 100644
--- a/packages/SystemUI/src/com/android/systemui/recordissue/RecordIssueDialogDelegate.kt
+++ b/packages/SystemUI/src/com/android/systemui/recordissue/RecordIssueDialogDelegate.kt
@@ -64,7 +64,6 @@
     private val mediaProjectionMetricsLogger: MediaProjectionMetricsLogger,
     private val screenCaptureDisabledDialogDelegate: ScreenCaptureDisabledDialogDelegate,
     private val state: IssueRecordingState,
-    private val traceurMessageSender: TraceurMessageSender,
     @Assisted private val onStarted: Runnable,
 ) : SystemUIDialog.Delegate {
 
@@ -87,10 +86,6 @@
             setNegativeButton(R.string.cancel) { _, _ -> }
             setPositiveButton(R.string.qs_record_issue_start) { _, _ -> onStarted.run() }
         }
-        bgExecutor.execute {
-            traceurMessageSender.onBoundToTraceur.add { traceurMessageSender.getTags(state) }
-            traceurMessageSender.bindToTraceur(dialog.context)
-        }
     }
 
     override fun createDialog(): SystemUIDialog = factory.create(this)
@@ -151,7 +146,7 @@
 
         mediaProjectionMetricsLogger.notifyProjectionInitiated(
             userTracker.userId,
-            SessionCreationSource.SYSTEM_UI_SCREEN_RECORDER
+            SessionCreationSource.SYSTEM_UI_SCREEN_RECORDER,
         )
 
         if (!state.hasUserApprovedScreenRecording) {
@@ -189,7 +184,7 @@
                         CustomTraceSettingsDialogDelegate(
                                 factory,
                                 state.customTraceState,
-                                state.tagTitles
+                                state.tagTitles,
                             ) {
                                 onMenuItemClickListener.onMenuItemClick(it)
                             }
diff --git a/packages/SystemUI/src/com/android/systemui/recordissue/TraceurConnection.kt b/packages/SystemUI/src/com/android/systemui/recordissue/TraceurConnection.kt
new file mode 100644
index 0000000..81529b3
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recordissue/TraceurConnection.kt
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.recordissue
+
+import android.content.ComponentName
+import android.content.Intent
+import android.net.Uri
+import android.os.Bundle
+import android.os.Handler
+import android.os.IBinder
+import android.os.Looper
+import android.os.Message
+import android.os.Messenger
+import android.util.Log
+import androidx.annotation.WorkerThread
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.recordissue.IssueRecordingState.Companion.TAG_TITLE_DELIMITER
+import com.android.systemui.settings.UserContextProvider
+import com.android.traceur.FileSender
+import com.android.traceur.MessageConstants
+import com.android.traceur.MessageConstants.TRACING_APP_ACTIVITY
+import com.android.traceur.MessageConstants.TRACING_APP_PACKAGE_NAME
+import com.android.traceur.TraceConfig
+import java.util.concurrent.CopyOnWriteArrayList
+import javax.inject.Inject
+
+private const val TAG = "TraceurConnection"
+
+class TraceurConnection
+private constructor(userContextProvider: UserContextProvider, private val bgLooper: Looper) :
+    UserAwareConnection(
+        userContextProvider,
+        Intent().setClassName(TRACING_APP_PACKAGE_NAME, TRACING_APP_ACTIVITY),
+    ) {
+
+    @SysUISingleton
+    class Provider
+    @Inject
+    constructor(
+        private val userContextProvider: UserContextProvider,
+        @Background private val bgLooper: Looper,
+    ) {
+        fun create() = TraceurConnection(userContextProvider, bgLooper)
+    }
+
+    val onBound: MutableList<Runnable> = CopyOnWriteArrayList(mutableListOf())
+
+    override fun onServiceConnected(className: ComponentName, service: IBinder) {
+        super.onServiceConnected(className, service)
+        onBound.forEach(Runnable::run)
+        onBound.clear()
+    }
+
+    @WorkerThread
+    fun startTracing(traceType: TraceConfig) {
+        val data =
+            Bundle().apply { putParcelable(MessageConstants.INTENT_EXTRA_TRACE_TYPE, traceType) }
+        sendMessage(MessageConstants.START_WHAT, data)
+    }
+
+    @WorkerThread fun stopTracing() = sendMessage(MessageConstants.STOP_WHAT)
+
+    @WorkerThread
+    fun shareTraces(screenRecord: Uri?) {
+        val replyHandler = Messenger(ShareFilesHandler(screenRecord, userContextProvider, bgLooper))
+        sendMessage(MessageConstants.SHARE_WHAT, replyTo = replyHandler)
+    }
+
+    @WorkerThread
+    fun getTags(state: IssueRecordingState) =
+        sendMessage(MessageConstants.TAGS_WHAT, replyTo = Messenger(TagsHandler(bgLooper, state)))
+
+    @WorkerThread
+    private fun sendMessage(what: Int, data: Bundle = Bundle(), replyTo: Messenger? = null) =
+        try {
+            val msg =
+                Message.obtain().apply {
+                    this.what = what
+                    this.data = data
+                    this.replyTo = replyTo
+                }
+            binder?.send(msg) ?: onBound.add { binder!!.send(msg) }
+        } catch (e: Exception) {
+            Log.e(TAG, "failed to notify Traceur", e)
+        }
+}
+
+private class ShareFilesHandler(
+    private val screenRecord: Uri?,
+    private val userContextProvider: UserContextProvider,
+    looper: Looper,
+) : Handler(looper) {
+
+    override fun handleMessage(msg: Message) {
+        if (MessageConstants.SHARE_WHAT == msg.what) {
+            shareTraces(
+                msg.data.getParcelable(MessageConstants.EXTRA_PERFETTO, Uri::class.java),
+                msg.data.getParcelable(MessageConstants.EXTRA_WINSCOPE, Uri::class.java),
+            )
+        } else {
+            throw IllegalArgumentException("received unknown msg.what: " + msg.what)
+        }
+    }
+
+    private fun shareTraces(perfetto: Uri?, winscope: Uri?) {
+        val uris: ArrayList<Uri> =
+            ArrayList<Uri>().apply {
+                perfetto?.let { add(it) }
+                winscope?.let { add(it) }
+                screenRecord?.let { add(it) }
+            }
+        val fileSharingIntent =
+            FileSender.buildSendIntent(userContextProvider.userContext, uris)
+                .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT)
+        userContextProvider.userContext.startActivity(fileSharingIntent)
+    }
+}
+
+private class TagsHandler(looper: Looper, private val state: IssueRecordingState) :
+    Handler(looper) {
+
+    override fun handleMessage(msg: Message) {
+        if (MessageConstants.TAGS_WHAT == msg.what) {
+            val keys = msg.data.getStringArrayList(MessageConstants.BUNDLE_KEY_TAGS)
+            val values = msg.data.getStringArrayList(MessageConstants.BUNDLE_KEY_TAG_DESCRIPTIONS)
+            if (keys == null || values == null) {
+                throw IllegalArgumentException(
+                    "Neither keys: $keys, nor values: $values can be null"
+                )
+            }
+            state.tagTitles =
+                keys.zip(values).map { it.first + TAG_TITLE_DELIMITER + it.second }.toSet()
+        } else {
+            throw IllegalArgumentException("received unknown msg.what: " + msg.what)
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recordissue/TraceurMessageSender.kt b/packages/SystemUI/src/com/android/systemui/recordissue/TraceurMessageSender.kt
deleted file mode 100644
index 8bfd14a..0000000
--- a/packages/SystemUI/src/com/android/systemui/recordissue/TraceurMessageSender.kt
+++ /dev/null
@@ -1,189 +0,0 @@
-/*
- * Copyright (C) 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES 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.recordissue
-
-import android.annotation.SuppressLint
-import android.content.ComponentName
-import android.content.Context
-import android.content.Intent
-import android.content.ServiceConnection
-import android.content.pm.PackageManager
-import android.net.Uri
-import android.os.Bundle
-import android.os.Handler
-import android.os.IBinder
-import android.os.Looper
-import android.os.Message
-import android.os.Messenger
-import android.util.Log
-import androidx.annotation.WorkerThread
-import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.dagger.qualifiers.Background
-import com.android.systemui.recordissue.IssueRecordingState.Companion.TAG_TITLE_DELIMITER
-import com.android.traceur.FileSender
-import com.android.traceur.MessageConstants
-import com.android.traceur.TraceConfig
-import javax.inject.Inject
-
-private const val TAG = "TraceurMessageSender"
-
-@SysUISingleton
-class TraceurMessageSender @Inject constructor(@Background private val backgroundLooper: Looper) {
-    private var binder: Messenger? = null
-    private var isBound: Boolean = false
-
-    val onBoundToTraceur = mutableListOf<Runnable>()
-
-    private val traceurConnection =
-        object : ServiceConnection {
-            override fun onServiceConnected(className: ComponentName, service: IBinder) {
-                binder = Messenger(service)
-                isBound = true
-                onBoundToTraceur.forEach(Runnable::run)
-                onBoundToTraceur.clear()
-            }
-
-            override fun onServiceDisconnected(className: ComponentName) {
-                binder = null
-                isBound = false
-            }
-        }
-
-    @SuppressLint("WrongConstant")
-    @WorkerThread
-    fun bindToTraceur(context: Context) {
-        if (isBound) {
-            // Binding needs to happen after the phone has been unlocked. The RecordIssueTile is
-            // initialized before this happens though, so binding is placed at a later time, during
-            // normal operations that can be repeated. This check avoids calling "bindService" 2x+
-            return
-        }
-        try {
-            val info =
-                context.packageManager.getPackageInfo(
-                    MessageConstants.TRACING_APP_PACKAGE_NAME,
-                    PackageManager.MATCH_SYSTEM_ONLY
-                )
-            val intent =
-                Intent().setClassName(info.packageName, MessageConstants.TRACING_APP_ACTIVITY)
-            val flags =
-                Context.BIND_AUTO_CREATE or
-                    Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE or
-                    Context.BIND_WAIVE_PRIORITY
-            context.bindService(intent, traceurConnection, flags)
-        } catch (e: Exception) {
-            Log.e(TAG, "failed to bind to Traceur's service", e)
-        }
-    }
-
-    @WorkerThread
-    fun unbindFromTraceur(context: Context) {
-        if (isBound) {
-            context.unbindService(traceurConnection)
-        }
-    }
-
-    @WorkerThread
-    fun startTracing(traceType: TraceConfig) {
-        val data =
-            Bundle().apply { putParcelable(MessageConstants.INTENT_EXTRA_TRACE_TYPE, traceType) }
-        notifyTraceur(MessageConstants.START_WHAT, data)
-    }
-
-    @WorkerThread fun stopTracing() = notifyTraceur(MessageConstants.STOP_WHAT)
-
-    @WorkerThread
-    fun shareTraces(context: Context, screenRecord: Uri?) {
-        val replyHandler = Messenger(ShareFilesHandler(context, screenRecord, backgroundLooper))
-        notifyTraceur(MessageConstants.SHARE_WHAT, replyTo = replyHandler)
-    }
-
-    @WorkerThread
-    fun getTags(state: IssueRecordingState) {
-        val replyHandler = Messenger(TagsHandler(backgroundLooper, state))
-        notifyTraceur(MessageConstants.TAGS_WHAT, replyTo = replyHandler)
-    }
-
-    @WorkerThread
-    private fun notifyTraceur(what: Int, data: Bundle = Bundle(), replyTo: Messenger? = null) {
-        try {
-            binder!!.send(
-                Message.obtain().apply {
-                    this.what = what
-                    this.data = data
-                    this.replyTo = replyTo
-                }
-            )
-        } catch (e: Exception) {
-            Log.e(TAG, "failed to notify Traceur", e)
-        }
-    }
-
-    private class ShareFilesHandler(
-        private val context: Context,
-        private val screenRecord: Uri?,
-        looper: Looper,
-    ) : Handler(looper) {
-
-        override fun handleMessage(msg: Message) {
-            if (MessageConstants.SHARE_WHAT == msg.what) {
-                shareTraces(
-                    msg.data.getParcelable(MessageConstants.EXTRA_PERFETTO, Uri::class.java),
-                    msg.data.getParcelable(MessageConstants.EXTRA_WINSCOPE, Uri::class.java)
-                )
-            } else {
-                throw IllegalArgumentException("received unknown msg.what: " + msg.what)
-            }
-        }
-
-        private fun shareTraces(perfetto: Uri?, winscope: Uri?) {
-            val uris: List<Uri> =
-                mutableListOf<Uri>().apply {
-                    perfetto?.let { add(it) }
-                    winscope?.let { add(it) }
-                    screenRecord?.let { add(it) }
-                }
-            val fileSharingIntent =
-                FileSender.buildSendIntent(context, uris)
-                    .addFlags(
-                        Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT
-                    )
-            context.startActivity(fileSharingIntent)
-        }
-    }
-
-    private class TagsHandler(looper: Looper, private val state: IssueRecordingState) :
-        Handler(looper) {
-
-        override fun handleMessage(msg: Message) {
-            if (MessageConstants.TAGS_WHAT == msg.what) {
-                val keys = msg.data.getStringArrayList(MessageConstants.BUNDLE_KEY_TAGS)
-                val values =
-                    msg.data.getStringArrayList(MessageConstants.BUNDLE_KEY_TAG_DESCRIPTIONS)
-                if (keys == null || values == null) {
-                    throw IllegalArgumentException(
-                        "Neither keys: $keys, nor values: $values can be null"
-                    )
-                }
-                state.tagTitles =
-                    keys.zip(values).map { it.first + TAG_TITLE_DELIMITER + it.second }.toSet()
-            } else {
-                throw IllegalArgumentException("received unknown msg.what: " + msg.what)
-            }
-        }
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/recordissue/UserAwareConnection.kt b/packages/SystemUI/src/com/android/systemui/recordissue/UserAwareConnection.kt
new file mode 100644
index 0000000..6aaa27d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recordissue/UserAwareConnection.kt
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.recordissue
+
+import android.annotation.SuppressLint
+import android.content.ComponentName
+import android.content.Context
+import android.content.Intent
+import android.content.ServiceConnection
+import android.os.IBinder
+import android.os.Messenger
+import android.util.Log
+import androidx.annotation.VisibleForTesting
+import androidx.annotation.WorkerThread
+import com.android.systemui.settings.UserContextProvider
+
+private const val TAG = "UserAwareConnection"
+private const val BIND_FLAGS =
+    Context.BIND_AUTO_CREATE or
+        Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE or
+        Context.BIND_WAIVE_PRIORITY
+
+/** ServiceConnection class that can be used to keep an IntentService alive. */
+open class UserAwareConnection(
+    protected val userContextProvider: UserContextProvider,
+    private val intent: Intent,
+) : ServiceConnection {
+    @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED) var binder: Messenger? = null
+    private var shouldUnBind = false
+
+    override fun onServiceConnected(className: ComponentName, service: IBinder) {
+        binder = Messenger(service)
+    }
+
+    override fun onServiceDisconnected(className: ComponentName) {
+        binder = null
+    }
+
+    @SuppressLint("WrongConstant")
+    @WorkerThread
+    fun doBind() {
+        if (shouldUnBind) {
+            // Binding needs to happen after the phone has been unlocked. The RecordIssueTile is
+            // initialized before this happens though, so binding is placed at a later time, during
+            // normal operations that can be repeated. This check avoids calling "bindService" 2x+
+            return
+        }
+        try {
+            shouldUnBind = userContextProvider.userContext.bindService(intent, this, BIND_FLAGS)
+        } catch (e: Exception) {
+            Log.e(TAG, "failed to bind to the service", e)
+        }
+    }
+
+    @WorkerThread
+    fun doUnBind() {
+        if (shouldUnBind) {
+            userContextProvider.userContext.unbindService(this)
+            shouldUnBind = false
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/scene/ui/view/SceneWindowRootView.kt b/packages/SystemUI/src/com/android/systemui/scene/ui/view/SceneWindowRootView.kt
index 8a2e274..cd38ca6 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/ui/view/SceneWindowRootView.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/ui/view/SceneWindowRootView.kt
@@ -6,6 +6,7 @@
 import android.view.View
 import android.view.WindowInsets
 import com.android.systemui.keyguard.ui.viewmodel.AlternateBouncerDependencies
+import com.android.systemui.qs.ui.adapter.QSSceneAdapter
 import com.android.systemui.scene.shared.model.SceneContainerConfig
 import com.android.systemui.scene.shared.model.SceneDataSourceDelegator
 import com.android.systemui.scene.ui.composable.Overlay
@@ -13,19 +14,13 @@
 import com.android.systemui.scene.ui.viewmodel.SceneContainerViewModel
 import com.android.systemui.shade.TouchLogger
 import com.android.systemui.statusbar.notification.stack.ui.view.SharedNotificationContainer
+import javax.inject.Provider
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.flow.MutableStateFlow
 
 /** A root view of the main SysUI window that supports scenes. */
 @ExperimentalCoroutinesApi
-class SceneWindowRootView(
-    context: Context,
-    attrs: AttributeSet?,
-) :
-    WindowRootView(
-        context,
-        attrs,
-    ) {
+class SceneWindowRootView(context: Context, attrs: AttributeSet?) : WindowRootView(context, attrs) {
 
     private var motionEventHandler: SceneContainerViewModel.MotionEventHandler? = null
     // TODO(b/298525212): remove once Compose exposes window inset bounds.
@@ -39,6 +34,7 @@
         overlays: Set<Overlay>,
         layoutInsetController: LayoutInsetsController,
         sceneDataSourceDelegator: SceneDataSourceDelegator,
+        qsSceneAdapter: Provider<QSSceneAdapter>,
         alternateBouncerDependencies: AlternateBouncerDependencies,
     ) {
         setLayoutInsetsController(layoutInsetController)
@@ -57,6 +53,7 @@
                 super.setVisibility(if (isVisible) View.VISIBLE else View.INVISIBLE)
             },
             dataSourceDelegator = sceneDataSourceDelegator,
+            qsSceneAdapter = qsSceneAdapter,
             alternateBouncerDependencies = alternateBouncerDependencies,
         )
     }
diff --git a/packages/SystemUI/src/com/android/systemui/scene/ui/view/SceneWindowRootViewBinder.kt b/packages/SystemUI/src/com/android/systemui/scene/ui/view/SceneWindowRootViewBinder.kt
index 38f4e73..1e3a233 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/ui/view/SceneWindowRootViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/ui/view/SceneWindowRootViewBinder.kt
@@ -42,6 +42,7 @@
 import com.android.systemui.lifecycle.repeatWhenAttached
 import com.android.systemui.lifecycle.setSnapshotBinding
 import com.android.systemui.lifecycle.viewModel
+import com.android.systemui.qs.ui.adapter.QSSceneAdapter
 import com.android.systemui.res.R
 import com.android.systemui.scene.shared.flag.SceneContainerFlag
 import com.android.systemui.scene.shared.model.SceneContainerConfig
@@ -51,6 +52,7 @@
 import com.android.systemui.scene.ui.composable.SceneContainer
 import com.android.systemui.scene.ui.viewmodel.SceneContainerViewModel
 import com.android.systemui.statusbar.notification.stack.ui.view.SharedNotificationContainer
+import javax.inject.Provider
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.awaitCancellation
@@ -74,6 +76,7 @@
         overlays: Set<Overlay>,
         onVisibilityChangedInternal: (isVisible: Boolean) -> Unit,
         dataSourceDelegator: SceneDataSourceDelegator,
+        qsSceneAdapter: Provider<QSSceneAdapter>,
         alternateBouncerDependencies: AlternateBouncerDependencies,
     ) {
         val unsortedSceneByKey: Map<SceneKey, Scene> = scenes.associateBy { scene -> scene.key }
@@ -132,6 +135,7 @@
                                 sceneByKey = sortedSceneByKey,
                                 overlayByKey = sortedOverlayByKey,
                                 dataSourceDelegator = dataSourceDelegator,
+                                qsSceneAdapter = qsSceneAdapter,
                                 containerConfig = containerConfig,
                             )
                             .also { it.id = R.id.scene_container_root_composable }
@@ -177,6 +181,7 @@
         sceneByKey: Map<SceneKey, Scene>,
         overlayByKey: Map<OverlayKey, Overlay>,
         dataSourceDelegator: SceneDataSourceDelegator,
+        qsSceneAdapter: Provider<QSSceneAdapter>,
         containerConfig: SceneContainerConfig,
     ): View {
         return ComposeView(context).apply {
@@ -192,6 +197,7 @@
                             overlayByKey = overlayByKey,
                             initialSceneKey = containerConfig.initialSceneKey,
                             dataSourceDelegator = dataSourceDelegator,
+                            qsSceneAdapter = qsSceneAdapter,
                         )
                     }
                 }
diff --git a/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModel.kt b/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModel.kt
index 889380a..ce942fe 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModel.kt
@@ -73,6 +73,8 @@
     /** Whether the container is visible. */
     val isVisible: Boolean by hydrator.hydratedStateOf("isVisible", sceneInteractor.isVisible)
 
+    val allContentKeys: List<ContentKey> = sceneInteractor.allContentKeys
+
     private val hapticsViewModel = hapticsViewModelFactory.create(view)
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/HeadlessScreenshotHandler.kt b/packages/SystemUI/src/com/android/systemui/screenshot/HeadlessScreenshotHandler.kt
index 7b56688..6d3b9aa 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/HeadlessScreenshotHandler.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/HeadlessScreenshotHandler.kt
@@ -19,7 +19,6 @@
 import android.net.Uri
 import android.os.UserManager
 import android.util.Log
-import android.view.WindowManager
 import com.android.internal.logging.UiEventLogger
 import com.android.systemui.dagger.qualifiers.Main
 import com.android.systemui.res.R
@@ -51,10 +50,6 @@
         finisher: Consumer<Uri?>,
         requestCallback: TakeScreenshotService.RequestCallback,
     ) {
-        if (screenshot.type == WindowManager.TAKE_SCREENSHOT_FULLSCREEN) {
-            screenshot.bitmap = imageCapture.captureDisplay(screenshot.displayId, crop = null)
-        }
-
         if (screenshot.bitmap == null) {
             Log.e(TAG, "handleScreenshot: Screenshot bitmap was null")
             notificationsControllerFactory
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/LegacyScreenshotController.java b/packages/SystemUI/src/com/android/systemui/screenshot/LegacyScreenshotController.java
index e589600..acfcd13 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/LegacyScreenshotController.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/LegacyScreenshotController.java
@@ -255,12 +255,6 @@
         Assert.isMainThread();
 
         mCurrentRequestCallback = requestCallback;
-        if (screenshot.getType() == WindowManager.TAKE_SCREENSHOT_FULLSCREEN
-                && screenshot.getBitmap() == null) {
-            Rect bounds = getFullScreenRect();
-            screenshot.setBitmap(mImageCapture.captureDisplay(mDisplay.getDisplayId(), bounds));
-            screenshot.setScreenBounds(bounds);
-        }
 
         if (screenshot.getBitmap() == null) {
             Log.e(TAG, "handleScreenshot: Screenshot bitmap was null");
@@ -323,24 +317,25 @@
 
         attachWindow();
 
+        Rect bounds = screenshot.getOriginalScreenBounds();
         boolean showFlash;
         if (screenshot.getType() == WindowManager.TAKE_SCREENSHOT_PROVIDED_IMAGE) {
-            if (screenshot.getScreenBounds() != null
-                    && aspectRatiosMatch(screenshot.getBitmap(), screenshot.getInsets(),
-                    screenshot.getScreenBounds())) {
+            if (bounds != null
+                    && aspectRatiosMatch(screenshot.getBitmap(), screenshot.getOriginalInsets(),
+                    bounds)) {
                 showFlash = false;
             } else {
                 showFlash = true;
-                screenshot.setInsets(Insets.NONE);
-                screenshot.setScreenBounds(new Rect(0, 0, screenshot.getBitmap().getWidth(),
-                        screenshot.getBitmap().getHeight()));
+                bounds = new Rect(0, 0, screenshot.getBitmap().getWidth(),
+                        screenshot.getBitmap().getHeight());
             }
         } else {
             showFlash = true;
         }
 
+        final Rect animationBounds = bounds;
         mViewProxy.prepareEntranceAnimation(
-                () -> startAnimation(screenshot.getScreenBounds(), showFlash,
+                () -> startAnimation(animationBounds, showFlash,
                         () -> mMessageContainerController.onScreenshotTaken(screenshot)));
 
         mViewProxy.setScreenshot(screenshot);
@@ -646,7 +641,7 @@
     private void saveScreenshotInBackground(ScreenshotData screenshot, UUID requestId,
             Consumer<Uri> finisher, Consumer<ImageExporter.Result> onResult) {
         ListenableFuture<ImageExporter.Result> future = mImageExporter.export(mBgExecutor,
-                requestId, screenshot.getBitmap(), screenshot.getUserOrDefault(),
+                requestId, screenshot.getBitmap(), screenshot.getUserHandle(),
                 mDisplay.getDisplayId());
         future.addListener(() -> {
             try {
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.kt
index 0806be8..f5c6052 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.kt
@@ -35,7 +35,6 @@
 import android.view.Display
 import android.view.ScrollCaptureResponse
 import android.view.ViewRootImpl.ActivityConfigCallback
-import android.view.WindowManager.TAKE_SCREENSHOT_FULLSCREEN
 import android.view.WindowManager.TAKE_SCREENSHOT_PROVIDED_IMAGE
 import android.widget.Toast
 import android.window.WindowContext
@@ -60,7 +59,6 @@
 import java.util.concurrent.ExecutorService
 import java.util.concurrent.Executors
 import java.util.function.Consumer
-import javax.inject.Provider
 import kotlin.math.abs
 
 /** Controls the state and flow for screenshots. */
@@ -73,7 +71,7 @@
     screenshotNotificationsControllerFactory: ScreenshotNotificationsController.Factory,
     screenshotActionsControllerFactory: ScreenshotActionsController.Factory,
     actionExecutorFactory: ActionExecutor.Factory,
-    screenshotSoundControllerProvider: Provider<ScreenshotSoundController?>,
+    private val screenshotSoundController: ScreenshotSoundController,
     private val uiEventLogger: UiEventLogger,
     private val imageExporter: ImageExporter,
     private val imageCapture: ImageCapture,
@@ -97,12 +95,12 @@
     private val window: ScreenshotWindow
     private val actionExecutor: ActionExecutor
     private val copyBroadcastReceiver: BroadcastReceiver
+    private val currentRequestCallbacks: MutableList<TakeScreenshotService.RequestCallback> =
+        mutableListOf()
 
-    private var screenshotSoundController: ScreenshotSoundController? = null
     private var screenBitmap: Bitmap? = null
     private var screenshotTakenInPortrait = false
     private var screenshotAnimation: Animator? = null
-    private var currentRequestCallback: TakeScreenshotService.RequestCallback? = null
     private var packageName = ""
 
     /** Tracks config changes that require re-creating UI */
@@ -137,14 +135,6 @@
         actionExecutor = actionExecutorFactory.create(window.window, viewProxy) { finishDismiss() }
         actionsController = screenshotActionsControllerFactory.getController(actionExecutor)
 
-        // Sound is only reproduced from the controller of the default display.
-        screenshotSoundController =
-            if (display.displayId == Display.DEFAULT_DISPLAY) {
-                screenshotSoundControllerProvider.get()
-            } else {
-                null
-            }
-
         copyBroadcastReceiver =
             object : BroadcastReceiver() {
                 override fun onReceive(context: Context, intent: Intent) {
@@ -169,19 +159,13 @@
         requestCallback: TakeScreenshotService.RequestCallback,
     ) {
         Assert.isMainThread()
-
-        currentRequestCallback = requestCallback
-        if (screenshot.type == TAKE_SCREENSHOT_FULLSCREEN && screenshot.bitmap == null) {
-            val bounds = fullScreenRect
-            screenshot.bitmap = imageCapture.captureDisplay(display.displayId, bounds)
-            screenshot.screenBounds = bounds
-        }
+        screenshotHandler.resetTimeout()
 
         val currentBitmap = screenshot.bitmap
         if (currentBitmap == null) {
             Log.e(TAG, "handleScreenshot: Screenshot bitmap was null")
             notificationController.notifyScreenshotError(R.string.screenshot_failed_to_capture_text)
-            currentRequestCallback?.reportError()
+            requestCallback.reportError()
             return
         }
 
@@ -194,8 +178,10 @@
             // User setup isn't complete, so we don't want to show any UI beyond a toast, as editing
             // and sharing shouldn't be exposed to the user.
             saveScreenshotAndToast(screenshot, finisher)
+            requestCallback.onFinish()
             return
         }
+        currentRequestCallbacks.add(requestCallback)
 
         broadcastSender.sendBroadcast(
             Intent(ClipboardOverlayController.SCREENSHOT_ACTION),
@@ -235,23 +221,27 @@
 
         window.attachWindow()
 
+        var bounds =
+            screenshot.originalScreenBounds ?: Rect(0, 0, currentBitmap.width, currentBitmap.height)
+
         val showFlash: Boolean
         if (screenshot.type == TAKE_SCREENSHOT_PROVIDED_IMAGE) {
-            if (aspectRatiosMatch(currentBitmap, screenshot.insets, screenshot.screenBounds)) {
+            if (
+                aspectRatiosMatch(
+                    currentBitmap,
+                    screenshot.originalInsets,
+                    screenshot.originalScreenBounds,
+                )
+            ) {
                 showFlash = false
             } else {
                 showFlash = true
-                screenshot.insets = Insets.NONE
-                screenshot.screenBounds = Rect(0, 0, currentBitmap.width, currentBitmap.height)
+                bounds = Rect(0, 0, currentBitmap.width, currentBitmap.height)
             }
         } else {
             showFlash = true
         }
 
-        // screenshot.screenBounds is expected to be non-null in all cases at this point
-        val bounds =
-            screenshot.screenBounds ?: Rect(0, 0, currentBitmap.width, currentBitmap.height)
-
         viewProxy.prepareEntranceAnimation {
             startAnimation(bounds, showFlash) {
                 messageContainerController.onScreenshotTaken(screenshot)
@@ -302,7 +292,7 @@
     // Any cleanup needed when the service is being destroyed.
     override fun onDestroy() {
         removeWindow()
-        releaseMediaPlayer()
+        screenshotSoundController.releaseScreenshotSoundAsync()
         releaseContext()
         bgExecutor.shutdown()
     }
@@ -313,10 +303,6 @@
         context.release()
     }
 
-    private fun releaseMediaPlayer() {
-        screenshotSoundController?.releaseScreenshotSoundAsync()
-    }
-
     /** Update resources on configuration change. Reinflate for theme/color changes. */
     private fun reloadAssets() {
         if (LogConfig.DEBUG_UI) {
@@ -442,18 +428,13 @@
         viewProxy.stopInputListening()
     }
 
-    private fun playCameraSoundIfNeeded() {
-        // the controller is not-null only on the default display controller
-        screenshotSoundController?.playScreenshotSoundAsync()
-    }
-
     /**
      * Save the bitmap but don't show the normal screenshot UI.. just a toast (or notification on
      * failure).
      */
     private fun saveScreenshotAndToast(screenshot: ScreenshotData, finisher: Consumer<Uri?>) {
         // Play the shutter sound to notify that we've taken a screenshot
-        playCameraSoundIfNeeded()
+        screenshotSoundController.playScreenshotSoundAsync()
 
         saveScreenshotInBackground(screenshot, UUID.randomUUID(), finisher) {
             result: ImageExporter.Result ->
@@ -482,7 +463,7 @@
             viewProxy.createScreenshotDropInAnimation(screenRect, showFlash).apply {
                 doOnEnd { onAnimationComplete?.run() }
                 // Play the shutter sound to notify that we've taken a screenshot
-                playCameraSoundIfNeeded()
+                screenshotSoundController.playScreenshotSoundAsync()
                 if (LogConfig.DEBUG_ANIM) {
                     Log.d(TAG, "starting post-screenshot animation")
                 }
@@ -495,8 +476,8 @@
         Log.d(TAG, "finishDismiss")
         actionsController.endScreenshotSession()
         scrollCaptureExecutor.close()
-        currentRequestCallback?.onFinish()
-        currentRequestCallback = null
+        currentRequestCallbacks.forEach { it.onFinish() }
+        currentRequestCallbacks.clear()
         viewProxy.reset()
         removeWindow()
         screenshotHandler.cancelTimeout()
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotData.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotData.kt
index 2df1e8a..b5b15a9 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotData.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotData.kt
@@ -4,7 +4,6 @@
 import android.graphics.Bitmap
 import android.graphics.Insets
 import android.graphics.Rect
-import android.os.Process
 import android.os.UserHandle
 import android.view.Display
 import android.view.WindowManager
@@ -21,19 +20,15 @@
     val userHandle: UserHandle,
     /** ComponentName of the top-most app in the screenshot. */
     val topComponent: ComponentName?,
-    var screenBounds: Rect?,
     val taskId: Int,
-    var insets: Insets,
+    val originalScreenBounds: Rect?,
+    val originalInsets: Insets,
     var bitmap: Bitmap?,
     val displayId: Int,
 ) {
     val packageNameString
         get() = topComponent?.packageName ?: ""
 
-    fun getUserOrDefault(): UserHandle {
-        return userHandle ?: Process.myUserHandle()
-    }
-
     companion object {
         @JvmStatic
         fun fromRequest(request: ScreenshotRequest, displayId: Int = Display.DEFAULT_DISPLAY) =
@@ -42,9 +37,9 @@
                 source = request.source,
                 userHandle = UserHandle.of(request.userId),
                 topComponent = request.topComponent,
-                screenBounds = request.boundsInScreen,
+                originalScreenBounds = request.boundsInScreen,
                 taskId = request.taskId,
-                insets = request.insets,
+                originalInsets = request.insets,
                 bitmap = request.bitmap,
                 displayId = displayId,
             )
@@ -61,9 +56,9 @@
                 source = source,
                 userHandle = userHandle,
                 topComponent = topComponent,
-                screenBounds = null,
+                originalScreenBounds = null,
                 taskId = 0,
-                insets = Insets.NONE,
+                originalInsets = Insets.NONE,
                 bitmap = bitmap,
                 displayId = Display.DEFAULT_DISPLAY,
             )
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/policy/PolicyRequestProcessor.kt b/packages/SystemUI/src/com/android/systemui/screenshot/policy/PolicyRequestProcessor.kt
index b67ad8a..039143a 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/policy/PolicyRequestProcessor.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/policy/PolicyRequestProcessor.kt
@@ -126,7 +126,7 @@
         )
     }
 
-    suspend fun replaceWithTaskSnapshot(
+    private suspend fun replaceWithTaskSnapshot(
         original: ScreenshotData,
         componentName: ComponentName?,
         owner: UserHandle,
@@ -134,14 +134,14 @@
         taskBounds: Rect?,
     ): ScreenshotData {
         Log.i(TAG, "Capturing task snapshot: $componentName / $owner")
-        val taskSnapshot = capture.captureTask(taskId)
+        val taskSnapshot = capture.captureTask(taskId) ?: error("Failed to capture task")
         return original.copy(
             type = TAKE_SCREENSHOT_PROVIDED_IMAGE,
             bitmap = taskSnapshot,
             userHandle = owner,
             taskId = taskId,
             topComponent = componentName,
-            screenBounds = taskBounds,
+            originalScreenBounds = taskBounds,
         )
     }
 
@@ -153,13 +153,13 @@
         taskId: Int? = null,
     ): ScreenshotData {
         Log.i(TAG, "Capturing screenshot: $componentName / $owner")
-        val screenshot = captureDisplay(displayId)
+        val screenshot = captureDisplay(displayId) ?: error("Failed to capture screenshot")
         return original.copy(
             type = TAKE_SCREENSHOT_FULLSCREEN,
             bitmap = screenshot,
             userHandle = owner,
             topComponent = componentName,
-            screenBounds = Rect(0, 0, screenshot?.width ?: 0, screenshot?.height ?: 0),
+            originalScreenBounds = Rect(0, 0, screenshot.width, screenshot.height),
             taskId = taskId ?: -1,
         )
     }
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
index 2bff7c86..757e37e 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
@@ -2728,6 +2728,11 @@
     }
 
     private int calculatePanelHeightShade() {
+        // Bypass should always occupy the full height
+        if (mBarState == KEYGUARD && mKeyguardBypassController.getBypassEnabled()) {
+            return mNotificationStackScrollLayoutController.getHeight();
+        }
+
         int emptyBottomMargin = mNotificationStackScrollLayoutController.getEmptyBottomMargin();
         int maxHeight = mNotificationStackScrollLayoutController.getHeight() - emptyBottomMargin;
 
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeViewProviderModule.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeViewProviderModule.kt
index fc8a593..5afc539 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeViewProviderModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeViewProviderModule.kt
@@ -35,6 +35,7 @@
 import com.android.systemui.keyguard.ui.view.KeyguardRootView
 import com.android.systemui.keyguard.ui.viewmodel.AlternateBouncerDependencies
 import com.android.systemui.privacy.OngoingPrivacyChip
+import com.android.systemui.qs.ui.adapter.QSSceneAdapter
 import com.android.systemui.res.R
 import com.android.systemui.scene.shared.flag.SceneContainerFlag
 import com.android.systemui.scene.shared.model.SceneContainerConfig
@@ -89,6 +90,7 @@
             overlaysProvider: Provider<Set<@JvmSuppressWildcards Overlay>>,
             layoutInsetController: NotificationInsetsController,
             sceneDataSourceDelegator: Provider<SceneDataSourceDelegator>,
+            qsSceneAdapter: Provider<QSSceneAdapter>,
             alternateBouncerDependencies: Provider<AlternateBouncerDependencies>,
         ): WindowRootView {
             return if (SceneContainerFlag.isEnabled) {
@@ -104,6 +106,7 @@
                     overlays = overlaysProvider.get(),
                     layoutInsetController = layoutInsetController,
                     sceneDataSourceDelegator = sceneDataSourceDelegator.get(),
+                    qsSceneAdapter = qsSceneAdapter,
                     alternateBouncerDependencies = alternateBouncerDependencies.get(),
                 )
                 sceneWindowRootView
@@ -119,9 +122,7 @@
         //  {@link NotificationShadeWindowViewController} can inject this view.
         @Provides
         @SysUISingleton
-        fun providesNotificationShadeWindowView(
-            root: WindowRootView,
-        ): NotificationShadeWindowView {
+        fun providesNotificationShadeWindowView(root: WindowRootView): NotificationShadeWindowView {
             if (SceneContainerFlag.isEnabled) {
                 return root.requireViewById(R.id.legacy_window_root)
             }
@@ -133,7 +134,7 @@
         @Provides
         @SysUISingleton
         fun providesNotificationStackScrollLayout(
-            notificationShadeWindowView: NotificationShadeWindowView,
+            notificationShadeWindowView: NotificationShadeWindowView
         ): NotificationStackScrollLayout {
             return notificationShadeWindowView.requireViewById(R.id.notification_stack_scroller)
         }
@@ -142,7 +143,7 @@
         @Provides
         @SysUISingleton
         fun providesNotificationPanelView(
-            notificationShadeWindowView: NotificationShadeWindowView,
+            notificationShadeWindowView: NotificationShadeWindowView
         ): NotificationPanelView {
             return notificationShadeWindowView.requireViewById(R.id.notification_panel)
         }
@@ -178,7 +179,7 @@
         @Provides
         @SysUISingleton
         fun providesKeyguardRootView(
-            notificationShadeWindowView: NotificationShadeWindowView,
+            notificationShadeWindowView: NotificationShadeWindowView
         ): KeyguardRootView {
             return notificationShadeWindowView.requireViewById(R.id.keyguard_root_view)
         }
@@ -186,7 +187,7 @@
         @Provides
         @SysUISingleton
         fun providesSharedNotificationContainer(
-            notificationShadeWindowView: NotificationShadeWindowView,
+            notificationShadeWindowView: NotificationShadeWindowView
         ): SharedNotificationContainer {
             return notificationShadeWindowView.requireViewById(R.id.shared_notification_container)
         }
@@ -195,7 +196,7 @@
         @Provides
         @SysUISingleton
         fun providesAuthRippleView(
-            notificationShadeWindowView: NotificationShadeWindowView,
+            notificationShadeWindowView: NotificationShadeWindowView
         ): AuthRippleView? {
             return notificationShadeWindowView.requireViewById(R.id.auth_ripple)
         }
@@ -203,9 +204,7 @@
         // TODO(b/277762009): Only allow this view's controller to inject the view. See above.
         @Provides
         @SysUISingleton
-        fun providesTapAgainView(
-            notificationPanelView: NotificationPanelView,
-        ): TapAgainView {
+        fun providesTapAgainView(notificationPanelView: NotificationPanelView): TapAgainView {
             return notificationPanelView.requireViewById(R.id.shade_falsing_tap_again)
         }
 
@@ -213,7 +212,7 @@
         @Provides
         @SysUISingleton
         fun providesNotificationsQuickSettingsContainer(
-            notificationShadeWindowView: NotificationShadeWindowView,
+            notificationShadeWindowView: NotificationShadeWindowView
         ): NotificationsQuickSettingsContainer {
             return notificationShadeWindowView.requireViewById(R.id.notification_container_parent)
         }
@@ -223,7 +222,7 @@
         @SysUISingleton
         @Named(SHADE_HEADER)
         fun providesShadeHeaderView(
-            notificationShadeWindowView: NotificationShadeWindowView,
+            notificationShadeWindowView: NotificationShadeWindowView
         ): MotionLayout {
             val stub = notificationShadeWindowView.requireViewById<ViewStub>(R.id.qs_header_stub)
             val layoutId = R.layout.combined_qs_header
@@ -275,7 +274,7 @@
         @SysUISingleton
         @Named(SHADE_HEADER)
         fun providesOngoingPrivacyChip(
-            @Named(SHADE_HEADER) header: MotionLayout,
+            @Named(SHADE_HEADER) header: MotionLayout
         ): OngoingPrivacyChip {
             return header.requireViewById(R.id.privacy_chip)
         }
@@ -284,7 +283,7 @@
         @SysUISingleton
         @Named(SHADE_HEADER)
         fun providesStatusIconContainer(
-            @Named(SHADE_HEADER) header: MotionLayout,
+            @Named(SHADE_HEADER) header: MotionLayout
         ): StatusIconContainer {
             return header.requireViewById(R.id.statusIcons)
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
index 73ad0e5..da04f6e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
@@ -46,6 +46,7 @@
 import com.android.internal.logging.UiEventLogger;
 import com.android.keyguard.KeyguardClockSwitch;
 import com.android.systemui.DejankUtils;
+import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor;
 import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.deviceentry.domain.interactor.DeviceUnlockedInteractor;
 import com.android.systemui.deviceentry.shared.model.DeviceUnlockStatus;
@@ -123,6 +124,7 @@
     private final Lazy<SceneContainerOcclusionInteractor> mSceneContainerOcclusionInteractorLazy;
     private final Lazy<KeyguardClockInteractor> mKeyguardClockInteractorLazy;
     private final Lazy<SceneBackInteractor> mSceneBackInteractorLazy;
+    private final Lazy<AlternateBouncerInteractor> mAlternateBouncerInteractorLazy;
     private int mState;
     private int mLastState;
     private int mUpcomingState;
@@ -193,7 +195,8 @@
             Lazy<SceneInteractor> sceneInteractorLazy,
             Lazy<SceneContainerOcclusionInteractor> sceneContainerOcclusionInteractor,
             Lazy<KeyguardClockInteractor> keyguardClockInteractorLazy,
-            Lazy<SceneBackInteractor> sceneBackInteractorLazy) {
+            Lazy<SceneBackInteractor> sceneBackInteractorLazy,
+            Lazy<AlternateBouncerInteractor> alternateBouncerInteractorLazy) {
         mUiEventLogger = uiEventLogger;
         mInteractionJankMonitorLazy = interactionJankMonitorLazy;
         mJavaAdapter = javaAdapter;
@@ -205,6 +208,7 @@
         mSceneContainerOcclusionInteractorLazy = sceneContainerOcclusionInteractor;
         mKeyguardClockInteractorLazy = keyguardClockInteractorLazy;
         mSceneBackInteractorLazy = sceneBackInteractorLazy;
+        mAlternateBouncerInteractorLazy = alternateBouncerInteractorLazy;
         for (int i = 0; i < HISTORY_SIZE; i++) {
             mHistoricalRecords[i] = new HistoricalState();
         }
@@ -233,6 +237,7 @@
                         mSceneInteractorLazy.get().getCurrentOverlays(),
                         mSceneBackInteractorLazy.get().getBackStack(),
                         mSceneContainerOcclusionInteractorLazy.get().getInvisibleDueToOcclusion(),
+                        mAlternateBouncerInteractorLazy.get().isVisible(),
                         this::calculateStateFromSceneFramework),
                     this::onStatusBarStateChanged);
 
@@ -693,7 +698,8 @@
             SceneKey currentScene,
             Set<OverlayKey> currentOverlays,
             SceneStack backStack,
-            boolean isOccluded) {
+            boolean isOccluded,
+            boolean alternateBouncerIsVisible) {
         SceneContainerFlag.isUnexpectedlyInLegacyMode();
 
         final boolean onBouncer = currentScene.equals(Scenes.Bouncer);
@@ -714,7 +720,8 @@
 
         final String inputLogString = "currentScene=" + currentScene.getTestTag()
                 + " currentOverlays=" + currentOverlays + " backStack=" + backStack
-                + " isUnlocked=" + isUnlocked + " isOccluded=" + isOccluded;
+                + " isUnlocked=" + isUnlocked + " isOccluded=" + isOccluded
+                + " alternateBouncerIsVisible=" + alternateBouncerIsVisible;
 
         int newState;
 
@@ -722,6 +729,7 @@
         // 1. deviceUnlockStatus.isUnlocked changes from false to true.
         // 2. Lockscreen changes to Gone, either in currentScene or in backStack.
         // 3. Bouncer is removed from currentScene or backStack, if it was present.
+        // 4. the alternate bouncer is hidden, if it was visible.
         //
         // From this function's perspective, though, deviceUnlockStatus, currentScene, and backStack
         // each update separately, and the relative order of those updates is not well-defined. This
@@ -733,6 +741,7 @@
         // 1. deviceUnlockStatus.isUnlocked is false.
         // 2. currentScene is a keyguardish scene (Lockscreen, Bouncer, or Communal).
         // 3. backStack contains a keyguardish scene (Lockscreen or Communal).
+        // 4. the alternate bouncer is visible.
 
         final boolean onKeyguardish = onLockscreen || onBouncer || onCommunal;
         final boolean overKeyguardish = overLockscreen || overCommunal;
@@ -741,7 +750,7 @@
             // Occlusion is special; even though the device is still technically on the lockscreen,
             // the UI behaves as if it is unlocked.
             newState = StatusBarState.SHADE;
-        } else if (onKeyguardish || overKeyguardish) {
+        } else if (onKeyguardish || overKeyguardish || alternateBouncerIsVisible) {
             // We get here if we are on or over a keyguardish scene, even if isUnlocked is true; we
             // want to return SHADE_LOCKED or KEYGUARD until we are also neither on nor over a
             // keyguardish scene.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/ConnectivityModule.kt b/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/ConnectivityModule.kt
index dac0102..10090283 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/ConnectivityModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/ConnectivityModule.kt
@@ -17,6 +17,7 @@
 package com.android.systemui.statusbar.connectivity
 
 import android.os.UserManager
+import com.android.systemui.bluetooth.qsdialog.dagger.AudioSharingModule
 import com.android.systemui.flags.FeatureFlags
 import com.android.systemui.flags.Flags.SIGNAL_CALLBACK_DEPRECATION
 import com.android.systemui.qs.QsEventLogger
@@ -56,7 +57,7 @@
 import dagger.multibindings.IntoMap
 import dagger.multibindings.StringKey
 
-@Module
+@Module(includes = [AudioSharingModule::class])
 interface ConnectivityModule {
 
     /** Inject BluetoothTile into tileMap in QSModule */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarModule.kt b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarModule.kt
index cf238d5..cd1642e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarModule.kt
@@ -22,15 +22,20 @@
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.log.LogBuffer
 import com.android.systemui.log.LogBufferFactory
+import com.android.systemui.statusbar.core.StatusBarConnectedDisplays
 import com.android.systemui.statusbar.data.StatusBarDataLayerModule
 import com.android.systemui.statusbar.phone.LightBarController
 import com.android.systemui.statusbar.phone.StatusBarSignalPolicy
 import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallController
 import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallLog
 import com.android.systemui.statusbar.ui.SystemBarUtilsProxyImpl
+import com.android.systemui.statusbar.window.MultiDisplayStatusBarWindowControllerStore
+import com.android.systemui.statusbar.window.SingleDisplayStatusBarWindowControllerStore
 import com.android.systemui.statusbar.window.StatusBarWindowController
 import com.android.systemui.statusbar.window.StatusBarWindowControllerImpl
+import com.android.systemui.statusbar.window.StatusBarWindowControllerStore
 import dagger.Binds
+import dagger.Lazy
 import dagger.Module
 import dagger.Provides
 import dagger.multibindings.ClassKey
@@ -62,13 +67,19 @@
     @ClassKey(StatusBarSignalPolicy::class)
     abstract fun bindStatusBarSignalPolicy(impl: StatusBarSignalPolicy): CoreStartable
 
+    @Binds
+    @SysUISingleton
+    abstract fun statusBarWindowControllerFactory(
+        implFactory: StatusBarWindowControllerImpl.Factory
+    ): StatusBarWindowController.Factory
+
     companion object {
 
         @Provides
         @SysUISingleton
-        fun statusBarWindowController(
-            context: Context?,
-            viewCaptureAwareWindowManager: ViewCaptureAwareWindowManager?,
+        fun defaultStatusBarWindowController(
+            context: Context,
+            viewCaptureAwareWindowManager: ViewCaptureAwareWindowManager,
             factory: StatusBarWindowControllerImpl.Factory,
         ): StatusBarWindowController {
             return factory.create(context, viewCaptureAwareWindowManager)
@@ -76,6 +87,33 @@
 
         @Provides
         @SysUISingleton
+        fun windowControllerStore(
+            multiDisplayImplLazy: Lazy<MultiDisplayStatusBarWindowControllerStore>,
+            singleDisplayImplLazy: Lazy<SingleDisplayStatusBarWindowControllerStore>,
+        ): StatusBarWindowControllerStore {
+            return if (StatusBarConnectedDisplays.isEnabled) {
+                multiDisplayImplLazy.get()
+            } else {
+                singleDisplayImplLazy.get()
+            }
+        }
+
+        @Provides
+        @SysUISingleton
+        @IntoMap
+        @ClassKey(MultiDisplayStatusBarWindowControllerStore::class)
+        fun multiDisplayControllerStoreAsCoreStartable(
+            storeLazy: Lazy<MultiDisplayStatusBarWindowControllerStore>
+        ): CoreStartable {
+            return if (StatusBarConnectedDisplays.isEnabled) {
+                storeLazy.get()
+            } else {
+                CoreStartable.NOP
+            }
+        }
+
+        @Provides
+        @SysUISingleton
         @OngoingCallLog
         fun provideOngoingCallLogBuffer(factory: LogBufferFactory): LogBuffer {
             return factory.create("OngoingCall", 75)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java
index c52632e..9d5d7a1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java
@@ -275,7 +275,8 @@
             }
         }
 
-        if (LockscreenOtpRedaction.isEnabled()) {
+        if (LockscreenOtpRedaction.isSingleLineViewEnabled()) {
+
             if (inflaterParams.isChildInGroup() && needsRedaction) {
                 params.requireContentViews(FLAG_CONTENT_VIEW_PUBLIC_SINGLE_LINE);
             } else {
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 ca5f49d..684ce48 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
@@ -88,6 +88,7 @@
 import com.android.systemui.statusbar.phone.KeyguardBypassController;
 import com.android.systemui.statusbar.phone.StatusBarNotificationActivityStarter;
 import com.android.systemui.statusbar.policy.HeadsUpManager;
+import com.android.systemui.statusbar.policy.ZenModesCleanupStartable;
 
 import dagger.Binds;
 import dagger.Module;
@@ -299,4 +300,10 @@
             ZenModeRepository repository) {
         return new NotificationsSoundPolicyInteractor(repository);
     }
+
+    /** Binds {@link ZenModesCleanupStartable} as a {@link CoreStartable}. */
+    @Binds
+    @IntoMap
+    @ClassKey(ZenModesCleanupStartable.class)
+    CoreStartable bindsZenModesCleanup(ZenModesCleanupStartable zenModesCleanup);
 }
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 7b6a2cb..560028c 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
@@ -444,9 +444,11 @@
                 if (onFinishedRunnable != null) {
                     onFinishedRunnable.run();
                 }
+                if (mRunWithoutInterruptions) {
+                    enableAppearDrawing(false);
+                }
 
                 // We need to reset the View state, even if the animation was cancelled
-                enableAppearDrawing(false);
                 onAppearAnimationFinished(isAppearing);
 
                 if (mRunWithoutInterruptions) {
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 5003a6a..49153d1 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
@@ -1015,7 +1015,7 @@
         }
         mNotificationParent = isChildInGroup ? parent : null;
         mPrivateLayout.setIsChildInGroup(isChildInGroup);
-        if (LockscreenOtpRedaction.isEnabled()) {
+        if (LockscreenOtpRedaction.isSingleLineViewEnabled()) {
             mPublicLayout.setIsChildInGroup(isChildInGroup);
         }
 
@@ -3218,7 +3218,7 @@
     }
 
     @Override
-    protected void resetAllContentAlphas() {
+    public void resetAllContentAlphas() {
         mLogger.logResetAllContentAlphas(getEntry());
         mPrivateLayout.setAlpha(1f);
         mPrivateLayout.setLayerType(LAYER_TYPE_NONE, null);
@@ -3873,13 +3873,18 @@
             pw.print(", mShowingPublicInitialized: " + mShowingPublicInitialized);
             NotificationContentView showingLayout = getShowingLayout();
             pw.print(", privateShowing: " + (showingLayout == mPrivateLayout));
+            pw.print(", childrenContainerShowing: "
+                    + (!shouldShowPublic() && mIsSummaryWithChildren));
             pw.print(", mShowNoBackground: " + mShowNoBackground);
+            pw.print(", clipBounds: " + getClipBounds());
+
             pw.println();
             if (NotificationContentView.INCLUDE_HEIGHTS_TO_DUMP) {
                 dumpHeights(pw);
             }
             showingLayout.dump(pw, args);
-
+            dumpCustomOutline(pw, args);
+            dumpClipping(pw, args);
             if (getViewState() != null) {
                 getViewState().dump(pw, args);
                 pw.println();
@@ -3896,6 +3901,8 @@
                     ? 0 : mChildrenContainer.getTransientViewCount();
             if (mIsSummaryWithChildren || transientViewCount > 0) {
                 pw.println(mChildrenContainer.debugString());
+                pw.println("Children Container Intrinsic Height: "
+                        + mChildrenContainer.getIntrinsicHeight());
                 pw.println();
                 List<ExpandableNotificationRow> notificationChildren = getAttachedChildren();
                 pw.print("Children: " + notificationChildren.size() + " {");
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 aefd348..a323c26 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
@@ -365,11 +365,17 @@
         DumpUtilsKt.withIncreasedIndent(pw, () -> {
             pw.println(getRoundableState().debugString());
             if (DUMP_VERBOSE) {
-                pw.println("mCustomOutline: " + mCustomOutline + " mOutlineRect: " + mOutlineRect);
-                pw.println("mOutlineAlpha: " + mOutlineAlpha);
-                pw.println("mAlwaysRoundBothCorners: " + mAlwaysRoundBothCorners);
+                dumpCustomOutline(pw, args);
             }
         });
     }
 
+    protected void dumpCustomOutline(IndentingPrintWriter pw, String[] args) {
+        pw.print("CustomOutline: ");
+        pw.print("mCustomOutline", mCustomOutline);
+        pw.print("mOutlineRect", mOutlineRect);
+        pw.print("mOutlineAlpha", mOutlineAlpha);
+        pw.print("mAlwaysRoundBothCorners", mAlwaysRoundBothCorners);
+        pw.println();
+    }
 }
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 afda426..ef6cad1 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
@@ -856,17 +856,23 @@
                 pw.println();
             }
             if (DUMP_VERBOSE) {
-                pw.println("mInRemovalAnimation: " + mInRemovalAnimation);
-                pw.println("mClipTopAmount: " + mClipTopAmount);
-                pw.println("mClipBottomAmount " + mClipBottomAmount);
-                pw.println("mClipToActualHeight: " + mClipToActualHeight);
-                pw.println("mExtraWidthForClipping: " + mExtraWidthForClipping);
-                pw.println("mMinimumHeightForClipping: " + mMinimumHeightForClipping);
-                pw.println("getClipBounds(): " + getClipBounds());
+                dumpClipping(pw, args);
             }
         });
     }
 
+    protected void dumpClipping(IndentingPrintWriter pw, String[] args) {
+        pw.print("Clipping: ");
+        pw.print("mInRemovalAnimation", mInRemovalAnimation);
+        pw.print("mClipTopAmount", mClipTopAmount);
+        pw.print("mClipBottomAmount", mClipBottomAmount);
+        pw.print("mClipToActualHeight", mClipToActualHeight);
+        pw.print("mExtraWidthForClipping", mExtraWidthForClipping);
+        pw.print("mMinimumHeightForClipping", mMinimumHeightForClipping);
+        pw.print("getClipBounds()", getClipBounds());
+        pw.println();
+    }
+
     /**
      * return the amount that the content is translated
      */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java
index 36e3e92..e10fd8f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java
@@ -223,7 +223,7 @@
                     );
         }
 
-        if (LockscreenOtpRedaction.isEnabled()) {
+        if (LockscreenOtpRedaction.isSingleLineViewEnabled()) {
             result.mPublicInflatedSingleLineViewModel =
                     SingleLineViewInflater.inflateRedactedSingleLineViewModel(row.getContext(),
                             isConversation);
@@ -309,7 +309,7 @@
                 });
                 break;
             case FLAG_CONTENT_VIEW_PUBLIC_SINGLE_LINE:
-                if (LockscreenOtpRedaction.isEnabled()) {
+                if (LockscreenOtpRedaction.isSingleLineViewEnabled()) {
                     row.getPublicLayout()
                             .performWhenContentInactive(VISIBLE_TYPE_SINGLELINE, () -> {
                                 row.getPublicLayout().setSingleLineView(null);
@@ -360,11 +360,11 @@
         if ((contentViews & FLAG_CONTENT_VIEW_PUBLIC) != 0) {
             row.getPublicLayout().removeContentInactiveRunnable(VISIBLE_TYPE_CONTRACTED);
         }
-        if (AsyncHybridViewInflation.isEnabled()
+        if (LockscreenOtpRedaction.isSingleLineViewEnabled()
                 && (contentViews & FLAG_CONTENT_VIEW_PUBLIC_SINGLE_LINE) != 0) {
             row.getPublicLayout().removeContentInactiveRunnable(VISIBLE_TYPE_SINGLELINE);
         }
-        if (LockscreenOtpRedaction.isEnabled()
+        if (AsyncHybridViewInflation.isEnabled()
                 && (contentViews & FLAG_CONTENT_VIEW_SINGLE_LINE) != 0) {
             row.getPrivateLayout().removeContentInactiveRunnable(VISIBLE_TYPE_SINGLELINE);
         }
@@ -974,7 +974,7 @@
             }
         }
 
-        if (LockscreenOtpRedaction.isEnabled()
+        if (LockscreenOtpRedaction.isSingleLineViewEnabled()
                 && (reInflateFlags & FLAG_CONTENT_VIEW_PUBLIC_SINGLE_LINE) != 0) {
             HybridNotificationView view = result.mPublicInflatedSingleLineView;
             SingleLineViewModel viewModel = result.mPublicInflatedSingleLineViewModel;
@@ -1254,7 +1254,7 @@
                         );
             }
 
-            if (LockscreenOtpRedaction.isEnabled()) {
+            if (LockscreenOtpRedaction.isSingleLineViewEnabled()) {
                 result.mPublicInflatedSingleLineViewModel =
                         SingleLineViewInflater.inflateRedactedSingleLineViewModel(mContext,
                                 isConversation);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/SingleLineViewInflater.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/SingleLineViewInflater.kt
index d67947d..4e26ae8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/SingleLineViewInflater.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/SingleLineViewInflater.kt
@@ -90,7 +90,7 @@
                 notification = notification,
                 isGroupConversation = isGroupConversation,
                 builder = builder,
-                systemUiContext = systemUiContext
+                systemUiContext = systemUiContext,
             )
 
         val conversationData =
@@ -98,7 +98,7 @@
                 // We don't show the sender's name for one-to-one conversation
                 conversationSenderName =
                     if (isGroupConversation) conversationTextData?.senderName else null,
-                avatar = conversationAvatar
+                avatar = conversationAvatar,
             )
 
         return SingleLineViewModel(
@@ -111,7 +111,7 @@
     @JvmStatic
     fun inflateRedactedSingleLineViewModel(
         context: Context,
-        isConversation: Boolean = false
+        isConversation: Boolean = false,
     ): SingleLineViewModel {
         val conversationData =
             if (isConversation) {
@@ -122,7 +122,7 @@
                             com.android.systemui.res.R.drawable
                                 .ic_redacted_notification_single_line_icon
                         )
-                    )
+                    ),
                 )
             } else {
                 null
@@ -134,7 +134,7 @@
             context.getString(
                 com.android.systemui.res.R.string.redacted_notification_single_line_text
             ),
-            conversationData
+            conversationData,
         )
     }
 
@@ -159,11 +159,13 @@
         }
 
         // load the sender's name to display
-        val name = lastMessage.senderPerson?.name
+        // null senderPerson means the current user.
+        val name = lastMessage.senderPerson?.name ?: user.name
+
         val senderName =
             systemUiContext.resources.getString(
                 R.string.conversation_single_line_name_display,
-                if (Flags.cleanUpSpansAndNewLines()) name?.toString() else name
+                if (Flags.cleanUpSpansAndNewLines()) name?.toString() else name,
             )
 
         // We need to find back-up values for those texts if they are needed and empty
@@ -333,7 +335,7 @@
                         sender.icon
                             ?: builder.getDefaultAvatar(
                                 name = sender.name,
-                                uniqueNames = uniqueNames
+                                uniqueNames = uniqueNames,
                             )
                     lastKey = senderKey
                 } else {
@@ -341,7 +343,7 @@
                         sender.icon
                             ?: builder.getDefaultAvatar(
                                 name = sender.name,
-                                uniqueNames = uniqueNames
+                                uniqueNames = uniqueNames,
                             )
                     break
                 }
@@ -424,7 +426,7 @@
 
     private fun Notification.Builder.getDefaultAvatar(
         name: CharSequence?,
-        uniqueNames: PeopleHelper.NameToPrefixMap? = null
+        uniqueNames: PeopleHelper.NameToPrefixMap? = null,
     ): Icon {
         val layoutColor = getSmallIconColor(/* isHeader= */ false)
         if (!name.isNullOrEmpty()) {
@@ -432,7 +434,7 @@
             return peopleHelper.createAvatarSymbol(
                 /* name = */ name,
                 /* symbol = */ symbol,
-                /* layoutColor = */ layoutColor
+                /* layoutColor = */ layoutColor,
             )
         }
         // If name is null, create default avatar with background color
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/shared/LockscreenOtpRedaction.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/shared/LockscreenOtpRedaction.kt
index 078deb9..da4a126 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/shared/LockscreenOtpRedaction.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/shared/LockscreenOtpRedaction.kt
@@ -30,6 +30,9 @@
 
     @JvmStatic
     inline val isEnabled
-        get() =
-            redactSensitiveContentNotificationsOnLockscreen() && AsyncHybridViewInflation.isEnabled
+        get() = redactSensitiveContentNotificationsOnLockscreen()
+
+    @JvmStatic
+    inline val isSingleLineViewEnabled
+        get() = isEnabled && AsyncHybridViewInflation.isEnabled
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationProgressTemplateViewWrapper.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationProgressTemplateViewWrapper.kt
new file mode 100644
index 0000000..a693fd3
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationProgressTemplateViewWrapper.kt
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.row.wrapper
+
+import android.content.Context
+import android.view.View
+import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
+
+/** Wraps a notification containing a progress template */
+class NotificationProgressTemplateViewWrapper(
+    ctx: Context,
+    view: View,
+    row: ExpandableNotificationRow,
+) : NotificationTemplateViewWrapper(ctx, view, row)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java
index 22b95ef..182fba3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java
@@ -76,6 +76,8 @@
                 return new NotificationCompactHeadsUpTemplateViewWrapper(ctx, v, row);
             } else if ("compactMessagingHUN".equals((v.getTag()))) {
                 return new NotificationCompactMessagingTemplateViewWrapper(ctx, v, row);
+            } else if ("progress".equals(v.getTag())) {
+                return new NotificationProgressTemplateViewWrapper(ctx, v, row);
             }
 
             if (row.getEntry().getSbn().getNotification().isStyle(
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java
index b108388..cfca830 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java
@@ -1704,6 +1704,7 @@
                 + "visibility: " + getVisibility()
                 + ", alpha: " + getAlpha()
                 + ", translationY: " + getTranslationY()
+                + ", clipBounds: " + getClipBounds()
                 + ", roundableState: " + getRoundableState().debugString() + "}";
     }
 }
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 b466bf0..d828a67 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
@@ -113,6 +113,7 @@
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.notification.row.ExpandableView;
 import com.android.systemui.statusbar.notification.row.StackScrollerDecorView;
+import com.android.systemui.statusbar.notification.shared.NotificationContentAlphaOptimization;
 import com.android.systemui.statusbar.notification.shared.NotificationHeadsUpCycling;
 import com.android.systemui.statusbar.notification.shared.NotificationThrottleHun;
 import com.android.systemui.statusbar.notification.shared.NotificationsImprovedHunAnimation;
@@ -129,6 +130,7 @@
 import com.android.systemui.util.ColorUtilKt;
 import com.android.systemui.util.DumpUtilsKt;
 import com.android.systemui.util.ListenerSet;
+import com.android.systemui.wallpapers.domain.interactor.WallpaperInteractor;
 
 import com.google.errorprone.annotations.CompileTimeConstant;
 
@@ -627,6 +629,9 @@
     @Nullable
     private OnClickListener mManageButtonClickListener;
 
+    @Nullable
+    private WallpaperInteractor mWallpaperInteractor;
+
     public NotificationStackScrollLayout(Context context, AttributeSet attrs) {
         super(context, attrs, 0, 0);
         Resources res = getResources();
@@ -1160,11 +1165,13 @@
 
     @Override
     public void addHeadsUpHeightChangedListener(@NonNull Runnable runnable) {
+        if (SceneContainerFlag.isUnexpectedlyInLegacyMode()) return;
         mHeadsUpHeightChangedListeners.addIfAbsent(runnable);
     }
 
     @Override
     public void removeHeadsUpHeightChangedListener(@NonNull Runnable runnable) {
+        if (SceneContainerFlag.isUnexpectedlyInLegacyMode()) return;
         mHeadsUpHeightChangedListeners.remove(runnable);
     }
 
@@ -1189,6 +1196,7 @@
         if (!SceneContainerFlag.isEnabled()) {
             setMaxLayoutHeight(getHeight());
             updateContentHeight();
+            mWallpaperInteractor.setNotificationStackAbsoluteBottom(mContentHeight);
         }
         clampScrollPosition();
         requestChildrenUpdate();
@@ -1240,64 +1248,70 @@
 
     @Override
     public void setScrolledToTop(boolean scrolledToTop) {
+        if (SceneContainerFlag.isUnexpectedlyInLegacyMode()) return;
         mScrollViewFields.setScrolledToTop(scrolledToTop);
     }
 
     @Override
     public void setStackTop(float stackTop) {
+        if (SceneContainerFlag.isUnexpectedlyInLegacyMode()) return;
         if (mAmbientState.getStackTop() != stackTop) {
             mAmbientState.setStackTop(stackTop);
             onTopPaddingChanged(/* animate = */ isAddOrRemoveAnimationPending());
+            mWallpaperInteractor.setNotificationStackAbsoluteBottom((int) stackTop);
         }
     }
 
     @Override
     public void setStackCutoff(float stackCutoff) {
+        if (SceneContainerFlag.isUnexpectedlyInLegacyMode()) return;
         mAmbientState.setStackCutoff(stackCutoff);
     }
 
     @Override
     public void setHeadsUpTop(float headsUpTop) {
+        if (SceneContainerFlag.isUnexpectedlyInLegacyMode()) return;
         mAmbientState.setHeadsUpTop(headsUpTop);
         requestChildrenUpdate();
     }
 
     @Override
     public void setHeadsUpBottom(float headsUpBottom) {
+        if (SceneContainerFlag.isUnexpectedlyInLegacyMode()) return;
         mAmbientState.setHeadsUpBottom(headsUpBottom);
         mStateAnimator.setHeadsUpAppearHeightBottom(Math.round(headsUpBottom));
     }
 
     @Override
     public void closeGutsOnSceneTouch() {
+        if (SceneContainerFlag.isUnexpectedlyInLegacyMode()) return;
         mController.closeControlsDueToOutsideTouch();
     }
 
     @Override
     public void setSyntheticScrollConsumer(@Nullable Consumer<Float> consumer) {
+        if (SceneContainerFlag.isUnexpectedlyInLegacyMode()) return;
         mScrollViewFields.setSyntheticScrollConsumer(consumer);
     }
 
     @Override
     public void setCurrentGestureOverscrollConsumer(@Nullable Consumer<Boolean> consumer) {
+        if (SceneContainerFlag.isUnexpectedlyInLegacyMode()) return;
         mScrollViewFields.setCurrentGestureOverscrollConsumer(consumer);
     }
 
     @Override
     public void setCurrentGestureInGutsConsumer(@Nullable Consumer<Boolean> consumer) {
+        if (SceneContainerFlag.isUnexpectedlyInLegacyMode()) return;
         mScrollViewFields.setCurrentGestureInGutsConsumer(consumer);
     }
 
     @Override
     public void setRemoteInputRowBottomBoundConsumer(@Nullable Consumer<Float> consumer) {
+        if (SceneContainerFlag.isUnexpectedlyInLegacyMode()) return;
         mScrollViewFields.setRemoteInputRowBottomBoundConsumer(consumer);
     }
 
-    @Override
-    public void setHeadsUpHeightConsumer(@Nullable Consumer<Float> consumer) {
-        mScrollViewFields.setHeadsUpHeightConsumer(consumer);
-    }
-
     /**
      * @param listener to be notified after the location of Notification children might have
      *                 changed.
@@ -2621,11 +2635,13 @@
 
     @Override
     public int getTopHeadsUpHeight() {
+        if (SceneContainerFlag.isUnexpectedlyInLegacyMode()) return 0;
         return getTopHeadsUpIntrinsicHeight();
     }
 
     @Override
     public int getHeadsUpInset() {
+        if (SceneContainerFlag.isUnexpectedlyInLegacyMode()) return 0;
         return mHeadsUpInset;
     }
 
@@ -4363,6 +4379,16 @@
         }
     }
 
+    private void resetChildAlpha() {
+        for (int i = 0; i < getChildCount(); i++) {
+            ExpandableView child = getChildAtIndex(i);
+            if (child instanceof ExpandableNotificationRow row) {
+                if (row.isExpandAnimationRunning()) continue;
+                row.resetAllContentAlphas();
+            }
+        }
+    }
+
     private void logTransientNotificationRowTraversalCleaned(
             ExpandableNotificationRow transientView,
             String reason
@@ -4406,6 +4432,9 @@
                 if (SceneContainerFlag.isEnabled()) {
                     setHeadsUpAnimatingAway(false);
                 }
+                if (NotificationContentAlphaOptimization.isEnabled()) {
+                    resetChildAlpha();
+                }
             } else {
                 mGroupExpansionManager.collapseGroups();
                 mExpandHelper.cancelImmediately();
@@ -5875,6 +5904,10 @@
         mController.getNotificationRoundnessManager().setAnimatedChildren(mChildrenToAddAnimated);
     }
 
+    public void setWallpaperInteractor(WallpaperInteractor wallpaperInteractor) {
+        mWallpaperInteractor = wallpaperInteractor;
+    }
+
     void addSwipedOutView(View v) {
         mSwipedOutViews.add(v);
     }
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 7b02d0c..00c5c40 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
@@ -145,6 +145,7 @@
 import com.android.systemui.tuner.TunerService;
 import com.android.systemui.util.Compile;
 import com.android.systemui.util.settings.SecureSettings;
+import com.android.systemui.wallpapers.domain.interactor.WallpaperInteractor;
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
@@ -226,6 +227,8 @@
     private final SensitiveNotificationProtectionController
             mSensitiveNotificationProtectionController;
 
+    private final WallpaperInteractor mWallpaperInteractor;
+
     private View mLongPressedView;
 
     private final NotificationListContainerImpl mNotificationListContainer =
@@ -756,7 +759,8 @@
             NotificationDismissibilityProvider dismissibilityProvider,
             ActivityStarter activityStarter,
             SplitShadeStateController splitShadeStateController,
-            SensitiveNotificationProtectionController sensitiveNotificationProtectionController) {
+            SensitiveNotificationProtectionController sensitiveNotificationProtectionController,
+            WallpaperInteractor wallpaperInteractor) {
         mView = view;
         mKeyguardTransitionRepo = keyguardTransitionRepo;
         mViewBinder = viewBinder;
@@ -812,6 +816,7 @@
         mDismissibilityProvider = dismissibilityProvider;
         mActivityStarter = activityStarter;
         mSensitiveNotificationProtectionController = sensitiveNotificationProtectionController;
+        mWallpaperInteractor = wallpaperInteractor;
         mView.passSplitShadeStateController(splitShadeStateController);
         if (SceneContainerFlag.isEnabled()) {
             mWakeUpCoordinator.setStackScroller(this);
@@ -948,6 +953,8 @@
             collectFlow(mView, mKeyguardTransitionRepo.getTransitions(),
                     this::onKeyguardTransitionChanged);
         }
+
+        mView.setWallpaperInteractor(mWallpaperInteractor);
     }
 
     private boolean isInVisibleLocation(NotificationEntry entry) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ScrollViewFields.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ScrollViewFields.kt
index c08ed61..f6e8b8f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ScrollViewFields.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ScrollViewFields.kt
@@ -86,9 +86,6 @@
     fun sendRemoteInputRowBottomBound(bottomY: Float?) =
         remoteInputRowBottomBoundConsumer?.accept(bottomY)
 
-    /** send the [headsUpHeight] to the [headsUpHeightConsumer], if present. */
-    fun sendHeadsUpHeight(headsUpHeight: Float) = headsUpHeightConsumer?.accept(headsUpHeight)
-
     fun dump(pw: IndentingPrintWriter) {
         pw.printSection("StackViewStates") {
             pw.println("scrimClippingShape", scrimClippingShape)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/view/NotificationScrollView.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/view/NotificationScrollView.kt
index dbe81c1..6ad9f01 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/view/NotificationScrollView.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/view/NotificationScrollView.kt
@@ -77,9 +77,6 @@
     /** Set a consumer for current remote input notification row bottom bound events */
     fun setRemoteInputRowBottomBoundConsumer(consumer: Consumer<Float?>?)
 
-    /** Set a consumer for heads up height changed events */
-    fun setHeadsUpHeightConsumer(consumer: Consumer<Float>?)
-
     /** sets that scrolling is allowed */
     fun setScrollingEnabled(enabled: Boolean)
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt
index 0ad22e0..f39af18 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt
@@ -68,6 +68,8 @@
 import com.android.systemui.scene.shared.flag.SceneContainerFlag
 import com.android.systemui.scene.shared.model.Scenes
 import com.android.systemui.shade.domain.interactor.ShadeInteractor
+import com.android.systemui.shade.shared.flag.DualShade
+import com.android.systemui.statusbar.notification.domain.interactor.HeadsUpNotificationInteractor
 import com.android.systemui.statusbar.notification.stack.domain.interactor.NotificationStackAppearanceInteractor
 import com.android.systemui.statusbar.notification.stack.domain.interactor.SharedNotificationContainerInteractor
 import com.android.systemui.unfold.domain.interactor.UnfoldTransitionInteractor
@@ -75,6 +77,7 @@
 import com.android.systemui.util.kotlin.FlowDumperImpl
 import com.android.systemui.util.kotlin.Utils.Companion.sample as sampleCombine
 import com.android.systemui.util.kotlin.sample
+import dagger.Lazy
 import javax.inject.Inject
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -137,8 +140,10 @@
     private val primaryBouncerToGoneTransitionViewModel: PrimaryBouncerToGoneTransitionViewModel,
     private val primaryBouncerToLockscreenTransitionViewModel:
         PrimaryBouncerToLockscreenTransitionViewModel,
-    private val aodBurnInViewModel: AodBurnInViewModel,
+    aodBurnInViewModel: AodBurnInViewModel,
     private val communalSceneInteractor: CommunalSceneInteractor,
+    // Lazy because it's only used in the SceneContainer + Dual Shade configuration.
+    headsUpNotificationInteractor: Lazy<HeadsUpNotificationInteractor>,
     unfoldTransitionInteractor: UnfoldTransitionInteractor,
 ) : FlowDumperImpl(dumpManager) {
 
@@ -390,20 +395,36 @@
      * notifications unless in splitshade.
      */
     private val alphaForShadeAndQsExpansion: Flow<Float> =
-        interactor.configurationBasedDimensions
-            .flatMapLatest { configurationBasedDimensions ->
-                combineTransform(shadeInteractor.shadeExpansion, shadeInteractor.qsExpansion) {
-                    shadeExpansion,
-                    qsExpansion ->
-                    if (shadeExpansion > 0f || qsExpansion > 0f) {
-                        if (configurationBasedDimensions.useSplitShade) {
-                            emit(1f)
-                        } else if (qsExpansion == 1f) {
-                            // Ensure HUNs will be visible in QS shade (at least while unlocked)
-                            emit(1f)
-                        } else {
-                            // Fade as QS shade expands
-                            emit(1f - qsExpansion)
+        if (DualShade.isEnabled) {
+                combineTransform(
+                    headsUpNotificationInteractor.get().isHeadsUpOrAnimatingAway,
+                    shadeInteractor.shadeExpansion,
+                    shadeInteractor.qsExpansion,
+                ) { isHeadsUpOrAnimatingAway, shadeExpansion, qsExpansion ->
+                    if (isHeadsUpOrAnimatingAway) {
+                        // Ensure HUNs will be visible in QS shade (at least while unlocked)
+                        emit(1f)
+                    } else if (shadeExpansion > 0f || qsExpansion > 0f) {
+                        // Fade out as QS shade expands
+                        emit(1f - qsExpansion)
+                    }
+                }
+            } else {
+                interactor.configurationBasedDimensions.flatMapLatest { configurationBasedDimensions
+                    ->
+                    combineTransform(shadeInteractor.shadeExpansion, shadeInteractor.qsExpansion) {
+                        shadeExpansion,
+                        qsExpansion ->
+                        if (shadeExpansion > 0f || qsExpansion > 0f) {
+                            if (configurationBasedDimensions.useSplitShade) {
+                                emit(1f)
+                            } else if (qsExpansion == 1f) {
+                                // Ensure HUNs will be visible in QS shade (at least while unlocked)
+                                emit(1f)
+                            } else {
+                                // Fade as QS shade expands
+                                emit(1f - qsExpansion)
+                            }
                         }
                     }
                 }
@@ -427,7 +448,7 @@
     private fun alphaForTransitions(viewState: ViewStateAccessor): Flow<Float> {
         return merge(
             keyguardInteractor.dismissAlpha.dumpWhileCollecting("keyguardInteractor.dismissAlpha"),
-            // All transition view models are mututally exclusive, and safe to merge
+            // All transition view models are mutually exclusive, and safe to merge
             bouncerToGoneNotificationAlpha(viewState),
             aodToGoneTransitionViewModel.notificationAlpha(viewState),
             aodToLockscreenTransitionViewModel.notificationAlpha,
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 0474344..7e5b455 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
@@ -33,7 +33,6 @@
 import static com.android.systemui.Flags.statusBarSignalPolicyRefactor;
 import static com.android.systemui.charging.WirelessChargingAnimation.UNKNOWN_BATTERY_LEVEL;
 import static com.android.systemui.flags.Flags.SHORTCUT_LIST_SEARCH_LAYOUT;
-import static com.android.systemui.statusbar.NotificationLockscreenUserManager.PERMISSION_SELF;
 import static com.android.systemui.statusbar.StatusBarState.SHADE;
 
 import android.annotation.Nullable;
@@ -41,7 +40,6 @@
 import android.app.IWallpaperManager;
 import android.app.KeyguardManager;
 import android.app.Notification;
-import android.app.NotificationManager;
 import android.app.PendingIntent;
 import android.app.StatusBarManager;
 import android.app.TaskInfo;
@@ -275,11 +273,6 @@
 @SysUISingleton
 public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces {
 
-    private static final String BANNER_ACTION_CANCEL =
-            "com.android.systemui.statusbar.banner_action_cancel";
-    private static final String BANNER_ACTION_SETUP =
-            "com.android.systemui.statusbar.banner_action_setup";
-
     private static final int MSG_LAUNCH_TRANSITION_TIMEOUT = 1003;
     // 1020-1040 reserved for BaseStatusBar
 
@@ -963,12 +956,6 @@
             }
         }
 
-        IntentFilter internalFilter = new IntentFilter();
-        internalFilter.addAction(BANNER_ACTION_CANCEL);
-        internalFilter.addAction(BANNER_ACTION_SETUP);
-        mContext.registerReceiver(mBannerActionBroadcastReceiver, internalFilter, PERMISSION_SELF,
-                null, Context.RECEIVER_EXPORTED_UNAUDITED);
-
         if (mWallpaperSupported) {
             IWallpaperManager wallpaperManager = IWallpaperManager.Stub.asInterface(
                     ServiceManager.getService(Context.WALLPAPER_SERVICE));
@@ -2948,29 +2935,6 @@
         return mDeviceInteractive;
     }
 
-    private final BroadcastReceiver mBannerActionBroadcastReceiver = new BroadcastReceiver() {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            String action = intent.getAction();
-            if (BANNER_ACTION_CANCEL.equals(action) || BANNER_ACTION_SETUP.equals(action)) {
-                NotificationManager noMan = (NotificationManager)
-                        mContext.getSystemService(Context.NOTIFICATION_SERVICE);
-                noMan.cancel(com.android.internal.messages.nano.SystemMessageProto.SystemMessage.
-                        NOTE_HIDDEN_NOTIFICATIONS);
-
-                Settings.Secure.putInt(mContext.getContentResolver(),
-                        Settings.Secure.SHOW_NOTE_ABOUT_NOTIFICATION_HIDING, 0);
-                if (BANNER_ACTION_SETUP.equals(action)) {
-                    mShadeController.animateCollapseShadeForced();
-                    mContext.startActivity(new Intent(Settings.ACTION_APP_NOTIFICATION_REDACTION)
-                            .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
-
-                    );
-                }
-            }
-        }
-    };
-
     @Override
     public void handleExternalShadeWindowTouch(MotionEvent event) {
         getNotificationShadeWindowViewController().handleExternalTouch(event);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
index 178c318..6a77988 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
@@ -182,14 +182,8 @@
         mCarrierLabel.setTextSize(TypedValue.COMPLEX_UNIT_PX,
                 getResources().getDimensionPixelSize(
                         com.android.internal.R.dimen.text_size_small_material));
-        lp = (MarginLayoutParams) mCarrierLabel.getLayoutParams();
+        updateCarrierLabelMargin();
 
-        int marginStart = calculateMargin(
-                getResources().getDimensionPixelSize(R.dimen.keyguard_carrier_text_margin),
-                mPadding.left);
-        lp.setMarginStart(marginStart);
-
-        mCarrierLabel.setLayoutParams(lp);
         updateKeyguardStatusBarHeight();
     }
 
@@ -203,6 +197,15 @@
         setLayoutParams(lp);
     }
 
+    private void updateCarrierLabelMargin() {
+        MarginLayoutParams lp = (MarginLayoutParams) mCarrierLabel.getLayoutParams();
+        int marginStart = calculateMargin(
+                getResources().getDimensionPixelSize(R.dimen.keyguard_carrier_text_margin),
+                mPadding.left);
+        lp.setMarginStart(marginStart);
+        mCarrierLabel.setLayoutParams(lp);
+    }
+
     void loadDimens() {
         Resources res = getResources();
         mSystemIconsSwitcherHiddenExpandedMargin = res.getDimensionPixelSize(
@@ -334,6 +337,7 @@
 
         RelativeLayout.LayoutParams lp = (LayoutParams) mCarrierLabel.getLayoutParams();
         lp.addRule(RelativeLayout.START_OF, R.id.status_icon_area);
+        updateCarrierLabelMargin();
 
         lp = (LayoutParams) mStatusIconArea.getLayoutParams();
         lp.removeRule(RelativeLayout.RIGHT_OF);
@@ -366,6 +370,7 @@
 
         lp = (LayoutParams) mCarrierLabel.getLayoutParams();
         lp.addRule(RelativeLayout.START_OF, R.id.cutout_space_view);
+        updateCarrierLabelMargin();
 
         lp = (LayoutParams) mStatusIconArea.getLayoutParams();
         lp.addRule(RelativeLayout.RIGHT_OF, R.id.cutout_space_view);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt
index bef552c..ff7c143 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt
@@ -151,7 +151,11 @@
 
         startSideContainer = mView.requireViewById(R.id.status_bar_start_side_content)
         startSideContainer.setOnHoverListener(
-            statusOverlayHoverListenerFactory.createDarkAwareListener(startSideContainer)
+            statusOverlayHoverListenerFactory.createDarkAwareListener(
+                startSideContainer,
+                topHoverMargin = 6,
+                bottomHoverMargin = 6,
+            )
         )
         startSideContainer.setOnTouchListener(iconsOnTouchListener)
     }
@@ -210,7 +214,7 @@
                 event.action == MotionEvent.ACTION_UP || event.action == MotionEvent.ACTION_CANCEL
             centralSurfaces.setInteracting(
                 WINDOW_STATUS_BAR,
-                !upOrCancel || shadeController.isExpandedVisible
+                !upOrCancel || shadeController.isExpandedVisible,
             )
         }
     }
@@ -247,7 +251,7 @@
                         String.format(
                             "onTouchForwardedFromStatusBar: panel disabled, " +
                                 "ignoring touch at (${event.x.toInt()},${event.y.toInt()})"
-                        )
+                        ),
                     )
                 }
                 return false
@@ -266,7 +270,7 @@
                 if (!shadeViewController.isViewEnabled) {
                     shadeLogger.logMotionEvent(
                         event,
-                        "onTouchForwardedFromStatusBar: panel view disabled"
+                        "onTouchForwardedFromStatusBar: panel view disabled",
                     )
                     return true
                 }
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 479ffb7..17bd538 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -530,6 +530,7 @@
                     this::consumeKeyguardAuthenticatedBiometricsHandled
             );
         } else {
+            // Collector that keeps the AlternateBouncerInteractor#canShowAlternateBouncer flow hot.
             mListenForCanShowAlternateBouncer = mJavaAdapter.alwaysCollectFlow(
                     mAlternateBouncerInteractor.getCanShowAlternateBouncer(),
                     this::consumeCanShowAlternateBouncer
@@ -578,8 +579,17 @@
     }
 
     private void consumeCanShowAlternateBouncer(boolean canShow) {
-        // do nothing, we only are registering for the flow to ensure that there's at least
-        // one subscriber that will update AlternateBouncerInteractor.canShowAlternateBouncer.value
+        // Hack: this is required to fix issues where
+        // KeyguardBouncerRepository#alternateBouncerVisible state is incorrectly set and then never
+        // reset. This is caused by usages of show()/forceShow() that only read this flow to set the
+        // alternate bouncer visible state, if there is a race condition between when that flow
+        // changes to false and when the read happens, the flow will be set to an incorrect value
+        // and not reset on time.
+        if (!canShow) {
+            Log.d(TAG, "canShowAlternateBouncer turned false, maybe try hiding the alternate "
+                    + "bouncer if it is already visible");
+            mAlternateBouncerInteractor.maybeHide();
+        }
     }
 
     /** Register a callback, to be invoked by the Predictive Back system. */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarLocationPublisher.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarLocationPublisher.kt
deleted file mode 100644
index 4e5ecfe..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarLocationPublisher.kt
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.statusbar.phone
-
-import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.statusbar.policy.CallbackController
-import java.lang.ref.WeakReference
-import javax.inject.Inject
-
-/**
- * Publishes updates to the status bar's margins.
- *
- * While the status bar view consumes the entire width of the device, the status bar
- * contents are laid out with margins for rounded corners, padding from the absolute
- * edges, and potentially display cutouts in the corner.
- */
-@SysUISingleton
-class StatusBarLocationPublisher @Inject constructor()
-: CallbackController<StatusBarMarginUpdatedListener> {
-    private val listeners = mutableSetOf<WeakReference<StatusBarMarginUpdatedListener>>()
-
-    var marginLeft: Int = 0
-        private set
-    var marginRight: Int = 0
-        private set
-
-    override fun addCallback(listener: StatusBarMarginUpdatedListener) {
-        listeners.add(WeakReference(listener))
-    }
-
-    override fun removeCallback(listener: StatusBarMarginUpdatedListener) {
-        var toRemove: WeakReference<StatusBarMarginUpdatedListener>? = null
-        for (l in listeners) {
-            if (l.get() == listener) {
-                toRemove = l
-            }
-        }
-
-        if (toRemove != null) {
-            listeners.remove(toRemove)
-        }
-    }
-
-    fun updateStatusBarMargin(left: Int, right: Int) {
-        marginLeft = left
-        marginRight = right
-
-        notifyListeners()
-    }
-
-    private fun notifyListeners() {
-        var listenerList: List<WeakReference<StatusBarMarginUpdatedListener>>
-        synchronized(this) {
-            listenerList = listeners.toList()
-        }
-
-        listenerList.forEach { wrapper ->
-            if (wrapper.get() == null) {
-                listeners.remove(wrapper)
-            }
-
-            wrapper.get()?.onStatusBarMarginUpdated(marginLeft, marginRight)
-        }
-    }
-}
-
-interface StatusBarMarginUpdatedListener {
-    fun onStatusBarMarginUpdated(marginLeft: Int, marginRight: Int)
-}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusOverlayHoverListener.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusOverlayHoverListener.kt
index 640ec28..c40822d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusOverlayHoverListener.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusOverlayHoverListener.kt
@@ -20,6 +20,7 @@
 import android.content.res.Resources
 import android.graphics.Color
 import android.graphics.drawable.PaintDrawable
+import android.util.TypedValue
 import android.view.MotionEvent
 import android.view.View
 import android.view.View.OnHoverListener
@@ -27,10 +28,10 @@
 import androidx.lifecycle.Lifecycle
 import androidx.lifecycle.lifecycleScope
 import androidx.lifecycle.repeatOnLifecycle
-import com.android.systemui.res.R
 import com.android.systemui.dagger.qualifiers.Main
 import com.android.systemui.lifecycle.repeatWhenAttached
 import com.android.systemui.plugins.DarkIconDispatcher
+import com.android.systemui.res.R
 import com.android.systemui.statusbar.phone.SysuiDarkIconDispatcher.DarkChange
 import com.android.systemui.statusbar.policy.ConfigurationController
 import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener
@@ -65,6 +66,26 @@
         createDarkAwareListener(view, darkIconDispatcher.darkChangeFlow())
 
     /**
+     * Creates listener using [DarkIconDispatcher] to determine light or dark color of the overlay
+     * Also sets margins for hover background relative to view bounds
+     */
+    fun createDarkAwareListener(
+        view: View,
+        leftHoverMargin: Int = 0,
+        rightHoverMargin: Int = 0,
+        topHoverMargin: Int = 0,
+        bottomHoverMargin: Int = 0,
+    ) =
+        createDarkAwareListener(
+            view,
+            darkIconDispatcher.darkChangeFlow(),
+            leftHoverMargin,
+            rightHoverMargin,
+            topHoverMargin,
+            bottomHoverMargin,
+        )
+
+    /**
      * Creates listener using provided [DarkChange] producer to determine light or dark color of the
      * overlay
      */
@@ -76,6 +97,25 @@
             darkFlow.map { toHoverTheme(view, it) },
         )
 
+    private fun createDarkAwareListener(
+        view: View,
+        darkFlow: StateFlow<DarkChange>,
+        leftHoverMargin: Int = 0,
+        rightHoverMargin: Int = 0,
+        topHoverMargin: Int = 0,
+        bottomHoverMargin: Int = 0,
+    ) =
+        StatusOverlayHoverListener(
+            view,
+            configurationController,
+            resources,
+            darkFlow.map { toHoverTheme(view, it) },
+            leftHoverMargin,
+            rightHoverMargin,
+            topHoverMargin,
+            bottomHoverMargin,
+        )
+
     private fun toHoverTheme(view: View, darkChange: DarkChange): HoverTheme {
         val calculatedTint = DarkIconDispatcher.getTint(darkChange.areas, view, darkChange.tint)
         // currently calculated tint is either white or some shade of black.
@@ -91,7 +131,7 @@
  */
 enum class HoverTheme {
     LIGHT,
-    DARK
+    DARK,
 }
 
 /**
@@ -103,11 +143,19 @@
     configurationController: ConfigurationController,
     private val resources: Resources,
     private val themeFlow: Flow<HoverTheme>,
+    private val leftHoverMargin: Int = 0,
+    private val rightHoverMargin: Int = 0,
+    private val topHoverMargin: Int = 0,
+    private val bottomHoverMargin: Int = 0,
 ) : OnHoverListener {
 
     @ColorInt private var darkColor: Int = 0
     @ColorInt private var lightColor: Int = 0
     private var cornerRadius = 0f
+    private var leftHoverMarginInPx: Int = 0
+    private var rightHoverMarginInPx: Int = 0
+    private var topHoverMarginInPx: Int = 0
+    private var bottomHoverMarginInPx: Int = 0
 
     private var lastTheme = HoverTheme.LIGHT
 
@@ -138,7 +186,12 @@
             val drawable =
                 PaintDrawable(backgroundColor).apply {
                     setCornerRadius(cornerRadius)
-                    setBounds(0, 0, v.width, v.height)
+                    setBounds(
+                        /*left = */ 0 + leftHoverMarginInPx,
+                        /*top = */ 0 + topHoverMarginInPx,
+                        /*right = */ v.width - rightHoverMarginInPx,
+                        /*bottom = */ v.height - bottomHoverMarginInPx,
+                    )
                 }
             v.overlay.add(drawable)
         } else if (event.action == MotionEvent.ACTION_HOVER_EXIT) {
@@ -151,5 +204,18 @@
         lightColor = resources.getColor(R.color.status_bar_icons_hover_color_light)
         darkColor = resources.getColor(R.color.status_bar_icons_hover_color_dark)
         cornerRadius = resources.getDimension(R.dimen.status_icons_hover_state_background_radius)
+        leftHoverMarginInPx = leftHoverMargin.dpToPx(resources)
+        rightHoverMarginInPx = rightHoverMargin.dpToPx(resources)
+        topHoverMarginInPx = topHoverMargin.dpToPx(resources)
+        bottomHoverMarginInPx = bottomHoverMargin.dpToPx(resources)
+    }
+
+    private fun Int.dpToPx(resources: Resources): Int {
+        return TypedValue.applyDimension(
+                TypedValue.COMPLEX_UNIT_DIP,
+                toFloat(),
+                resources.displayMetrics,
+            )
+            .toInt()
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java
index a8b4728..c258095 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java
@@ -65,7 +65,6 @@
 import com.android.systemui.statusbar.phone.PhoneStatusBarView;
 import com.android.systemui.statusbar.phone.StatusBarHideIconsForBouncerManager;
 import com.android.systemui.statusbar.phone.StatusBarLocation;
-import com.android.systemui.statusbar.phone.StatusBarLocationPublisher;
 import com.android.systemui.statusbar.phone.fragment.dagger.StatusBarFragmentComponent;
 import com.android.systemui.statusbar.phone.fragment.dagger.StatusBarFragmentComponent.Startable;
 import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallController;
@@ -140,7 +139,6 @@
     private final OperatorNameViewController.Factory mOperatorNameViewControllerFactory;
     private final OngoingCallController mOngoingCallController;
     private final SystemStatusAnimationScheduler mAnimationScheduler;
-    private final StatusBarLocationPublisher mLocationPublisher;
     private final ShadeExpansionStateManager mShadeExpansionStateManager;
     private final StatusBarIconController mStatusBarIconController;
     private final CarrierConfigTracker mCarrierConfigTracker;
@@ -243,7 +241,6 @@
             StatusBarFragmentComponent.Factory statusBarFragmentComponentFactory,
             OngoingCallController ongoingCallController,
             SystemStatusAnimationScheduler animationScheduler,
-            StatusBarLocationPublisher locationPublisher,
             ShadeExpansionStateManager shadeExpansionStateManager,
             StatusBarIconController statusBarIconController,
             DarkIconManager.Factory darkIconManagerFactory,
@@ -267,7 +264,6 @@
         mStatusBarFragmentComponentFactory = statusBarFragmentComponentFactory;
         mOngoingCallController = ongoingCallController;
         mAnimationScheduler = animationScheduler;
-        mLocationPublisher = locationPublisher;
         mShadeExpansionStateManager = shadeExpansionStateManager;
         mStatusBarIconController = statusBarIconController;
         mCollapsedStatusBarViewModel = collapsedStatusBarViewModel;
@@ -349,9 +345,6 @@
         }
 
         mStatusBar = (PhoneStatusBarView) view;
-        View contents = mStatusBar.findViewById(R.id.status_bar_contents);
-        contents.addOnLayoutChangeListener(mStatusBarLayoutListener);
-        updateStatusBarLocation(contents.getLeft(), contents.getRight());
         if (savedInstanceState != null && savedInstanceState.containsKey(EXTRA_PANEL_STATE)) {
             mStatusBar.restoreHierarchyState(
                     savedInstanceState.getSparseParcelableArray(EXTRA_PANEL_STATE));
@@ -977,13 +970,6 @@
         }, /*isAnimationRunning*/ false);
     }
 
-    private void updateStatusBarLocation(int left, int right) {
-        int leftMargin = left - mStatusBar.getLeft();
-        int rightMargin = mStatusBar.getRight() - right;
-
-        mLocationPublisher.updateStatusBarMargin(leftMargin, rightMargin);
-    }
-
     private final ContentObserver mVolumeSettingObserver = new ContentObserver(null) {
         @Override
         public void onChange(boolean selfChange) {
@@ -991,14 +977,6 @@
         }
     };
 
-    // Listen for view end changes of PhoneStatusBarView and publish that to the privacy dot
-    private View.OnLayoutChangeListener mStatusBarLayoutListener =
-            (view, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> {
-                if (left != oldLeft || right != oldRight) {
-                    updateStatusBarLocation(left, right);
-                }
-            };
-
     @Override
     public void dump(PrintWriter printWriter, String[] args) {
         IndentingPrintWriter pw = new IndentingPrintWriter(printWriter, /* singleIndent= */"  ");
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/data/prod/DeviceBasedSatelliteRepositoryImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/data/prod/DeviceBasedSatelliteRepositoryImpl.kt
index 03ec41d..470abe6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/data/prod/DeviceBasedSatelliteRepositoryImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/data/prod/DeviceBasedSatelliteRepositoryImpl.kt
@@ -182,7 +182,7 @@
             .stateIn(
                 scope,
                 SharingStarted.WhileSubscribed(),
-                TelephonyManager.RADIO_POWER_UNAVAILABLE
+                TelephonyManager.RADIO_POWER_UNAVAILABLE,
             )
 
     /**
@@ -265,9 +265,10 @@
 
                 var registered = false
                 try {
+                    logBuffer.i { "registerForCommunicationAllowedStateChanged" }
                     sm.registerForCommunicationAllowedStateChanged(
                         bgDispatcher.asExecutor(),
-                        callback
+                        callback,
                     )
                     registered = true
                 } catch (e: Exception) {
@@ -276,6 +277,7 @@
 
                 awaitClose {
                     if (registered) {
+                        logBuffer.i { "unRegisterForCommunicationAllowedStateChanged" }
                         sm.unregisterForCommunicationAllowedStateChanged(callback)
                     }
                 }
@@ -321,9 +323,10 @@
 
                 var registered = false
                 try {
+                    logBuffer.i { "registerForSupportedStateChanged" }
                     satelliteManager.registerForSupportedStateChanged(
                         bgDispatcher.asExecutor(),
-                        callback
+                        callback,
                     )
                     registered = true
                 } catch (e: Exception) {
@@ -332,6 +335,7 @@
 
                 awaitClose {
                     if (registered) {
+                        logBuffer.i { "unregisterForSupportedStateChanged" }
                         satelliteManager.unregisterForSupportedStateChanged(callback)
                     }
                 }
@@ -366,10 +370,7 @@
                 var registered = false
                 try {
                     logBuffer.i { "registerForProvisionStateChanged" }
-                    sm.registerForProvisionStateChanged(
-                        bgDispatcher.asExecutor(),
-                        callback,
-                    )
+                    sm.registerForProvisionStateChanged(bgDispatcher.asExecutor(), callback)
                     registered = true
                 } catch (e: Exception) {
                     logBuffer.e("error registering for provisioning state callback", e)
@@ -377,6 +378,7 @@
 
                 awaitClose {
                     if (registered) {
+                        logBuffer.i { "unregisterForProvisionStateChanged" }
                         sm.unregisterForProvisionStateChanged(callback)
                     }
                 }
@@ -526,17 +528,10 @@
             uptime - (clock.uptimeMillis() - android.os.Process.getStartUptimeMillis())
 
         /** A couple of convenience logging methods rather than a whole class */
-        private fun LogBuffer.i(
-            initializer: MessageInitializer = {},
-            printer: MessagePrinter,
-        ) = this.log(TAG, LogLevel.INFO, initializer, printer)
+        private fun LogBuffer.i(initializer: MessageInitializer = {}, printer: MessagePrinter) =
+            this.log(TAG, LogLevel.INFO, initializer, printer)
 
         private fun LogBuffer.e(message: String, exception: Throwable? = null) =
-            this.log(
-                tag = TAG,
-                level = LogLevel.ERROR,
-                message = message,
-                exception = exception,
-            )
+            this.log(tag = TAG, level = LogLevel.ERROR, message = message, exception = exception)
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/data/repository/ConnectivityRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/data/repository/ConnectivityRepository.kt
index f5cfc8c..e0bf00f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/data/repository/ConnectivityRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/data/repository/ConnectivityRepository.kt
@@ -26,6 +26,7 @@
 import android.net.NetworkCapabilities.TRANSPORT_ETHERNET
 import android.net.NetworkCapabilities.TRANSPORT_WIFI
 import android.net.vcn.VcnTransportInfo
+import android.net.vcn.VcnUtils
 import android.net.wifi.WifiInfo
 import android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID
 import androidx.annotation.ArrayRes
@@ -161,7 +162,9 @@
         defaultNetworkCapabilities
             .map { networkCapabilities ->
                 networkCapabilities?.run {
-                    val subId = (transportInfo as? VcnTransportInfo)?.subId
+                    val subId =
+                        VcnUtils.getSubIdFromVcnCaps(connectivityManager, networkCapabilities)
+
                     // Never return an INVALID_SUBSCRIPTION_ID (-1)
                     if (subId != INVALID_SUBSCRIPTION_ID) {
                         subId
@@ -245,9 +248,9 @@
          * info.
          */
         fun NetworkCapabilities.getMainOrUnderlyingWifiInfo(
-            connectivityManager: ConnectivityManager,
+            connectivityManager: ConnectivityManager
         ): WifiInfo? {
-            val mainWifiInfo = this.getMainWifiInfo()
+            val mainWifiInfo = this.getMainWifiInfo(connectivityManager)
             if (mainWifiInfo != null) {
                 return mainWifiInfo
             }
@@ -264,7 +267,9 @@
             // eventually traced to a wifi or carrier merged connection. So, check those underlying
             // networks for possible wifi information as well. See b/225902574.
             return this.underlyingNetworks?.firstNotNullOfOrNull { underlyingNetwork ->
-                connectivityManager.getNetworkCapabilities(underlyingNetwork)?.getMainWifiInfo()
+                connectivityManager
+                    .getNetworkCapabilities(underlyingNetwork)
+                    ?.getMainWifiInfo(connectivityManager)
             }
         }
 
@@ -272,7 +277,9 @@
          * Checks the network capabilities for wifi info, but does *not* check the underlying
          * networks. See [getMainOrUnderlyingWifiInfo].
          */
-        private fun NetworkCapabilities.getMainWifiInfo(): WifiInfo? {
+        private fun NetworkCapabilities.getMainWifiInfo(
+            connectivityManager: ConnectivityManager
+        ): WifiInfo? {
             // Wifi info can either come from a WIFI Transport, or from a CELLULAR transport for
             // virtual networks like VCN.
             val canHaveWifiInfo =
@@ -286,7 +293,7 @@
                 // [com.android.settingslib.Utils.tryGetWifiInfoForVcn]. It's copied instead of
                 // re-used because it makes the logic here clearer, and because the method will be
                 // removed once this pipeline is fully launched.
-                is VcnTransportInfo -> currentTransportInfo.wifiInfo
+                is VcnTransportInfo -> VcnUtils.getWifiInfoFromVcnCaps(connectivityManager, this)
                 is WifiInfo -> currentTransportInfo
                 else -> null
             }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java
index e09e577..0cba940 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java
@@ -16,8 +16,6 @@
 
 package com.android.systemui.statusbar.policy;
 
-import static com.android.systemui.Flags.registerZenModeContentObserverBackground;
-
 import android.app.AlarmManager;
 import android.app.Flags;
 import android.app.NotificationManager;
@@ -47,7 +45,6 @@
 import com.android.systemui.Dumpable;
 import com.android.systemui.broadcast.BroadcastDispatcher;
 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;
@@ -107,7 +104,6 @@
     public ZenModeControllerImpl(
             Context context,
             @Main Handler handler,
-            @Background Handler bgHandler,
             BroadcastDispatcher broadcastDispatcher,
             DumpManager dumpManager,
             GlobalSettings globalSettings,
@@ -138,17 +134,9 @@
             }
         };
         mNoMan = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
-        if (registerZenModeContentObserverBackground()) {
-            bgHandler.post(() -> {
-                globalSettings.registerContentObserverSync(Global.ZEN_MODE, modeContentObserver);
-                globalSettings.registerContentObserverSync(Global.ZEN_MODE_CONFIG_ETAG,
-                        configContentObserver);
-            });
-        } else {
-            globalSettings.registerContentObserverSync(Global.ZEN_MODE, modeContentObserver);
-            globalSettings.registerContentObserverSync(Global.ZEN_MODE_CONFIG_ETAG,
-                    configContentObserver);
-        }
+        globalSettings.registerContentObserverAsync(Global.ZEN_MODE, modeContentObserver);
+        globalSettings.registerContentObserverAsync(Global.ZEN_MODE_CONFIG_ETAG,
+                configContentObserver);
         updateZenMode(getModeSettingValueFromProvider());
         updateZenModeConfig();
         updateConsolidatedNotificationPolicy();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModesCleanupStartable.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModesCleanupStartable.kt
new file mode 100644
index 0000000..32b476b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModesCleanupStartable.kt
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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 android.app.NotificationManager
+import com.android.systemui.CoreStartable
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.modes.shared.ModesUi
+import javax.inject.Inject
+import kotlin.coroutines.CoroutineContext
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
+
+/**
+ * Cleanup task that deletes the obsolete "Gaming" AutomaticZenRule that was created by SystemUI in
+ * the faraway past, and still exists on some devices through upgrades or B&R.
+ */
+// TODO: b/372874878 - Remove this thing once it has run long enough
+class ZenModesCleanupStartable
+@Inject
+constructor(
+    @Application private val applicationCoroutineScope: CoroutineScope,
+    @Background private val bgContext: CoroutineContext,
+    val notificationManager: NotificationManager,
+) : CoreStartable {
+
+    override fun start() {
+        if (!ModesUi.isEnabled) {
+            return
+        }
+        applicationCoroutineScope.launch { deleteObsoleteGamingMode() }
+    }
+
+    private suspend fun deleteObsoleteGamingMode() {
+        withContext(bgContext) {
+            val allRules = notificationManager.automaticZenRules
+            val gamingModeEntry =
+                allRules.entries.firstOrNull { entry ->
+                    entry.value.packageName == "com.android.systemui" &&
+                        entry.value.conditionId?.toString() ==
+                            "android-app://com.android.systemui/game-mode-dnd-controller"
+                }
+            if (gamingModeEntry != null) {
+                notificationManager.removeAutomaticZenRule(gamingModeEntry.key)
+            }
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/domain/interactor/ZenModeInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/domain/interactor/ZenModeInteractor.kt
index daba109..9839f9d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/domain/interactor/ZenModeInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/domain/interactor/ZenModeInteractor.kt
@@ -16,10 +16,12 @@
 
 package com.android.systemui.statusbar.policy.domain.interactor
 
+import android.app.NotificationManager.INTERRUPTION_FILTER_NONE
 import android.content.Context
 import android.provider.Settings
 import android.provider.Settings.Secure.ZEN_DURATION_FOREVER
 import android.provider.Settings.Secure.ZEN_DURATION_PROMPT
+import android.service.notification.ZenPolicy.STATE_DISALLOW
 import android.service.notification.ZenPolicy.VISUAL_EFFECT_NOTIFICATION_LIST
 import android.util.Log
 import androidx.concurrent.futures.await
@@ -115,6 +117,26 @@
             .flowOn(bgDispatcher)
             .distinctUntilChanged()
 
+    val activeModesBlockingEverything: Flow<ActiveZenModes> = getFilteredActiveModesFlow { mode ->
+        mode.interruptionFilter == INTERRUPTION_FILTER_NONE
+    }
+
+    val activeModesBlockingMedia: Flow<ActiveZenModes> = getFilteredActiveModesFlow { mode ->
+        mode.policy.priorityCategoryMedia == STATE_DISALLOW
+    }
+
+    val activeModesBlockingAlarms: Flow<ActiveZenModes> = getFilteredActiveModesFlow { mode ->
+        mode.policy.priorityCategoryAlarms == STATE_DISALLOW
+    }
+
+    private fun getFilteredActiveModesFlow(predicate: (ZenMode) -> Boolean): Flow<ActiveZenModes> {
+        return modes
+            .map { modes -> modes.filter { mode -> predicate(mode) } }
+            .map { modes -> buildActiveZenModes(modes) }
+            .flowOn(bgDispatcher)
+            .distinctUntilChanged()
+    }
+
     suspend fun getActiveModes() = buildActiveZenModes(zenModeRepository.getModes())
 
     private suspend fun buildActiveZenModes(modes: List<ZenMode>): ActiveZenModes {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowController.kt
index 421e5c4..e8dc934 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowController.kt
@@ -16,8 +16,10 @@
 
 package com.android.systemui.statusbar.window
 
+import android.content.Context
 import android.view.View
 import android.view.ViewGroup
+import com.android.app.viewcapture.ViewCaptureAwareWindowManager
 import com.android.systemui.animation.ActivityTransitionAnimator
 import com.android.systemui.fragments.FragmentHostManager
 import java.util.Optional
@@ -73,4 +75,11 @@
      *   this#setForceStatusBarVisible} together and use some sort of ranking system instead.
      */
     fun setOngoingProcessRequiresStatusBarVisible(visible: Boolean)
+
+    interface Factory {
+        fun create(
+            context: Context,
+            viewCaptureAwareWindowManager: ViewCaptureAwareWindowManager,
+        ): StatusBarWindowController
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowControllerImpl.java
index 1ee7cf3..d709e5a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowControllerImpl.java
@@ -354,11 +354,13 @@
     }
 
     @AssistedFactory
-    public interface Factory {
+    public interface Factory extends StatusBarWindowController.Factory {
         /** Creates a new instance. */
+        @NonNull
+        @Override
         StatusBarWindowControllerImpl create(
-                Context context,
-                ViewCaptureAwareWindowManager viewCaptureAwareWindowManager);
+                @NonNull Context context,
+                @NonNull ViewCaptureAwareWindowManager viewCaptureAwareWindowManager);
     }
 
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowControllerStore.kt b/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowControllerStore.kt
new file mode 100644
index 0000000..5f30b37
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowControllerStore.kt
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.window
+
+import android.view.Display
+import android.view.WindowManager
+import com.android.app.viewcapture.ViewCaptureAwareWindowManager
+import com.android.systemui.CoreStartable
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.display.data.repository.DisplayRepository
+import com.android.systemui.display.data.repository.DisplayWindowPropertiesRepository
+import com.android.systemui.statusbar.core.StatusBarConnectedDisplays
+import java.util.concurrent.ConcurrentHashMap
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineName
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.launch
+
+/** Store that allows to retrieve per display instances of [StatusBarWindowController]. */
+interface StatusBarWindowControllerStore {
+    /**
+     * The instance for the default/main display of the device. For example, on a phone or a tablet,
+     * the default display is the internal/built-in display of the device.
+     *
+     * Note that the id of the default display is [Display.DEFAULT_DISPLAY].
+     */
+    val defaultDisplay: StatusBarWindowController
+
+    /**
+     * Returns an instance for a specific display id.
+     *
+     * @throws IllegalArgumentException if [displayId] doesn't match the id of any existing
+     *   displays.
+     */
+    fun forDisplay(displayId: Int): StatusBarWindowController
+}
+
+@SysUISingleton
+class MultiDisplayStatusBarWindowControllerStore
+@Inject
+constructor(
+    @Background private val backgroundApplicationScope: CoroutineScope,
+    private val controllerFactory: StatusBarWindowController.Factory,
+    private val displayWindowPropertiesRepository: DisplayWindowPropertiesRepository,
+    private val viewCaptureAwareWindowManagerFactory: ViewCaptureAwareWindowManager.Factory,
+    private val displayRepository: DisplayRepository,
+) : StatusBarWindowControllerStore, CoreStartable {
+
+    init {
+        StatusBarConnectedDisplays.assertInNewMode()
+    }
+
+    private val perDisplayControllers = ConcurrentHashMap<Int, StatusBarWindowController>()
+
+    override fun start() {
+        backgroundApplicationScope.launch(CoroutineName("StatusBarWindowController#start")) {
+            displayRepository.displayRemovalEvent.collect { displayId ->
+                perDisplayControllers.remove(displayId)
+            }
+        }
+    }
+
+    override val defaultDisplay: StatusBarWindowController
+        get() = forDisplay(Display.DEFAULT_DISPLAY)
+
+    override fun forDisplay(displayId: Int): StatusBarWindowController {
+        if (displayRepository.getDisplay(displayId) == null) {
+            throw IllegalArgumentException("Display with id $displayId doesn't exist.")
+        }
+        return perDisplayControllers.computeIfAbsent(displayId) {
+            createControllerForDisplay(displayId)
+        }
+    }
+
+    private fun createControllerForDisplay(displayId: Int): StatusBarWindowController {
+        val statusBarDisplayContext =
+            displayWindowPropertiesRepository.get(
+                displayId = displayId,
+                windowType = WindowManager.LayoutParams.TYPE_STATUS_BAR,
+            )
+        val viewCaptureAwareWindowManager =
+            viewCaptureAwareWindowManagerFactory.create(statusBarDisplayContext.windowManager)
+        return controllerFactory.create(
+            statusBarDisplayContext.context,
+            viewCaptureAwareWindowManager,
+        )
+    }
+}
+
+@SysUISingleton
+class SingleDisplayStatusBarWindowControllerStore
+@Inject
+constructor(private val controller: StatusBarWindowController) : StatusBarWindowControllerStore {
+
+    init {
+        StatusBarConnectedDisplays.assertInLegacyMode()
+    }
+
+    override val defaultDisplay = controller
+
+    override fun forDisplay(displayId: Int) = controller
+}
diff --git a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/BackGestureTutorialScreen.kt b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/BackGestureTutorialScreen.kt
index 411ff8b..d85cfcd 100644
--- a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/BackGestureTutorialScreen.kt
+++ b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/BackGestureTutorialScreen.kt
@@ -16,6 +16,7 @@
 
 package com.android.systemui.touchpad.tutorial.ui.composable
 
+import androidx.compose.material3.MaterialTheme
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.remember
 import com.airbnb.lottie.compose.rememberLottieDynamicProperties
@@ -23,13 +24,10 @@
 import com.android.systemui.inputdevice.tutorial.ui.composable.TutorialScreenConfig
 import com.android.systemui.inputdevice.tutorial.ui.composable.rememberColorFilterProperty
 import com.android.systemui.res.R
-import com.android.systemui.touchpad.tutorial.ui.gesture.BackGestureMonitor
+import com.android.systemui.touchpad.tutorial.ui.gesture.BackGestureRecognizer
 
 @Composable
-fun BackGestureTutorialScreen(
-    onDoneButtonClicked: () -> Unit,
-    onBack: () -> Unit,
-) {
+fun BackGestureTutorialScreen(onDoneButtonClicked: () -> Unit, onBack: () -> Unit) {
     val screenConfig =
         TutorialScreenConfig(
             colors = rememberScreenColors(),
@@ -38,26 +36,28 @@
                     titleResId = R.string.touchpad_back_gesture_action_title,
                     bodyResId = R.string.touchpad_back_gesture_guidance,
                     titleSuccessResId = R.string.touchpad_back_gesture_success_title,
-                    bodySuccessResId = R.string.touchpad_back_gesture_success_body
+                    bodySuccessResId = R.string.touchpad_back_gesture_success_body,
                 ),
             animations =
                 TutorialScreenConfig.Animations(
                     educationResId = R.raw.trackpad_back_edu,
-                    successResId = R.raw.trackpad_back_success
-                )
+                    successResId = R.raw.trackpad_back_success,
+                ),
         )
-    val gestureMonitorProvider =
-        DistanceBasedGestureMonitorProvider(
-            monitorFactory = { distanceThresholdPx, gestureStateCallback ->
-                BackGestureMonitor(distanceThresholdPx, gestureStateCallback)
+    val gestureRecognizerProvider =
+        DistanceBasedGestureRecognizerProvider(
+            recognizerFactory = { distanceThresholdPx, gestureStateCallback ->
+                BackGestureRecognizer(distanceThresholdPx).also {
+                    it.addGestureStateCallback(gestureStateCallback)
+                }
             }
         )
-    GestureTutorialScreen(screenConfig, gestureMonitorProvider, onDoneButtonClicked, onBack)
+    GestureTutorialScreen(screenConfig, gestureRecognizerProvider, onDoneButtonClicked, onBack)
 }
 
 @Composable
 private fun rememberScreenColors(): TutorialScreenConfig.Colors {
-    val onTertiary = LocalAndroidColorScheme.current.onTertiary
+    val onTertiary = MaterialTheme.colorScheme.onTertiary
     val onTertiaryFixed = LocalAndroidColorScheme.current.onTertiaryFixed
     val onTertiaryFixedVariant = LocalAndroidColorScheme.current.onTertiaryFixedVariant
     val tertiaryFixedDim = LocalAndroidColorScheme.current.tertiaryFixedDim
@@ -66,7 +66,7 @@
             rememberColorFilterProperty(".tertiaryFixedDim", tertiaryFixedDim),
             rememberColorFilterProperty(".onTertiaryFixed", onTertiaryFixed),
             rememberColorFilterProperty(".onTertiary", onTertiary),
-            rememberColorFilterProperty(".onTertiaryFixedVariant", onTertiaryFixedVariant)
+            rememberColorFilterProperty(".onTertiaryFixedVariant", onTertiaryFixedVariant),
         )
     val screenColors =
         remember(dynamicProperties) {
diff --git a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/GestureTutorialScreen.kt b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/GestureTutorialScreen.kt
index e1b89da..75c66f2 100644
--- a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/GestureTutorialScreen.kt
+++ b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/GestureTutorialScreen.kt
@@ -37,69 +37,69 @@
 import com.android.systemui.inputdevice.tutorial.ui.composable.TutorialActionState
 import com.android.systemui.inputdevice.tutorial.ui.composable.TutorialScreenConfig
 import com.android.systemui.touchpad.tutorial.ui.gesture.EasterEggGestureMonitor
+import com.android.systemui.touchpad.tutorial.ui.gesture.GestureRecognizer
 import com.android.systemui.touchpad.tutorial.ui.gesture.GestureState
-import com.android.systemui.touchpad.tutorial.ui.gesture.GestureState.FINISHED
-import com.android.systemui.touchpad.tutorial.ui.gesture.GestureState.IN_PROGRESS
-import com.android.systemui.touchpad.tutorial.ui.gesture.GestureState.NOT_STARTED
+import com.android.systemui.touchpad.tutorial.ui.gesture.GestureState.Finished
+import com.android.systemui.touchpad.tutorial.ui.gesture.GestureState.InProgress
+import com.android.systemui.touchpad.tutorial.ui.gesture.GestureState.NotStarted
 import com.android.systemui.touchpad.tutorial.ui.gesture.TouchpadGestureHandler
-import com.android.systemui.touchpad.tutorial.ui.gesture.TouchpadGestureMonitor
 
-interface GestureMonitorProvider {
+interface GestureRecognizerProvider {
 
     @Composable
-    fun rememberGestureMonitor(
+    fun rememberGestureRecognizer(
         resources: Resources,
         gestureStateChangedCallback: (GestureState) -> Unit,
-    ): TouchpadGestureMonitor
+    ): GestureRecognizer
 }
 
 typealias gestureStateCallback = (GestureState) -> Unit
 
-class DistanceBasedGestureMonitorProvider(
-    val monitorFactory: (Int, gestureStateCallback) -> TouchpadGestureMonitor
-) : GestureMonitorProvider {
+class DistanceBasedGestureRecognizerProvider(
+    val recognizerFactory: (Int, gestureStateCallback) -> GestureRecognizer
+) : GestureRecognizerProvider {
 
     @Composable
-    override fun rememberGestureMonitor(
+    override fun rememberGestureRecognizer(
         resources: Resources,
         gestureStateChangedCallback: (GestureState) -> Unit,
-    ): TouchpadGestureMonitor {
+    ): GestureRecognizer {
         val distanceThresholdPx =
             resources.getDimensionPixelSize(
                 com.android.internal.R.dimen.system_gestures_distance_threshold
             )
         return remember(distanceThresholdPx) {
-            monitorFactory(distanceThresholdPx, gestureStateChangedCallback)
+            recognizerFactory(distanceThresholdPx, gestureStateChangedCallback)
         }
     }
 }
 
 fun GestureState.toTutorialActionState(): TutorialActionState {
     return when (this) {
-        NOT_STARTED -> TutorialActionState.NOT_STARTED
-        IN_PROGRESS -> TutorialActionState.IN_PROGRESS
-        FINISHED -> TutorialActionState.FINISHED
+        NotStarted -> TutorialActionState.NotStarted
+        is InProgress -> TutorialActionState.InProgress(progress)
+        Finished -> TutorialActionState.Finished
     }
 }
 
 @Composable
 fun GestureTutorialScreen(
     screenConfig: TutorialScreenConfig,
-    gestureMonitorProvider: GestureMonitorProvider,
+    gestureRecognizerProvider: GestureRecognizerProvider,
     onDoneButtonClicked: () -> Unit,
     onBack: () -> Unit,
 ) {
     BackHandler(onBack = onBack)
-    var gestureState by remember { mutableStateOf(NOT_STARTED) }
+    var gestureState: GestureState by remember { mutableStateOf(NotStarted) }
     var easterEggTriggered by remember { mutableStateOf(false) }
-    val gestureMonitor =
-        gestureMonitorProvider.rememberGestureMonitor(
+    val gestureRecognizer =
+        gestureRecognizerProvider.rememberGestureRecognizer(
             resources = LocalContext.current.resources,
             gestureStateChangedCallback = { gestureState = it },
         )
     val easterEggMonitor = EasterEggGestureMonitor { easterEggTriggered = true }
     val gestureHandler =
-        remember(gestureMonitor) { TouchpadGestureHandler(gestureMonitor, easterEggMonitor) }
+        remember(gestureRecognizer) { TouchpadGestureHandler(gestureRecognizer, easterEggMonitor) }
     TouchpadGesturesHandlingBox(
         gestureHandler,
         gestureState,
@@ -143,7 +143,7 @@
                 .pointerInteropFilter(
                     onTouchEvent = { event ->
                         // FINISHED is the final state so we don't need to process touches anymore
-                        if (gestureState == FINISHED) {
+                        if (gestureState == Finished) {
                             false
                         } else {
                             gestureHandler.onMotionEvent(event)
diff --git a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/HomeGestureTutorialScreen.kt b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/HomeGestureTutorialScreen.kt
index f2fec5f..69ec598 100644
--- a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/HomeGestureTutorialScreen.kt
+++ b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/HomeGestureTutorialScreen.kt
@@ -23,13 +23,10 @@
 import com.android.systemui.inputdevice.tutorial.ui.composable.TutorialScreenConfig
 import com.android.systemui.inputdevice.tutorial.ui.composable.rememberColorFilterProperty
 import com.android.systemui.res.R
-import com.android.systemui.touchpad.tutorial.ui.gesture.HomeGestureMonitor
+import com.android.systemui.touchpad.tutorial.ui.gesture.HomeGestureRecognizer
 
 @Composable
-fun HomeGestureTutorialScreen(
-    onDoneButtonClicked: () -> Unit,
-    onBack: () -> Unit,
-) {
+fun HomeGestureTutorialScreen(onDoneButtonClicked: () -> Unit, onBack: () -> Unit) {
     val screenConfig =
         TutorialScreenConfig(
             colors = rememberScreenColors(),
@@ -38,21 +35,23 @@
                     titleResId = R.string.touchpad_home_gesture_action_title,
                     bodyResId = R.string.touchpad_home_gesture_guidance,
                     titleSuccessResId = R.string.touchpad_home_gesture_success_title,
-                    bodySuccessResId = R.string.touchpad_home_gesture_success_body
+                    bodySuccessResId = R.string.touchpad_home_gesture_success_body,
                 ),
             animations =
                 TutorialScreenConfig.Animations(
                     educationResId = R.raw.trackpad_home_edu,
-                    successResId = R.raw.trackpad_home_success
-                )
+                    successResId = R.raw.trackpad_home_success,
+                ),
         )
-    val gestureMonitorProvider =
-        DistanceBasedGestureMonitorProvider(
-            monitorFactory = { distanceThresholdPx, gestureStateCallback ->
-                HomeGestureMonitor(distanceThresholdPx, gestureStateCallback)
+    val gestureRecognizerProvider =
+        DistanceBasedGestureRecognizerProvider(
+            recognizerFactory = { distanceThresholdPx, gestureStateCallback ->
+                HomeGestureRecognizer(distanceThresholdPx).also {
+                    it.addGestureStateCallback(gestureStateCallback)
+                }
             }
         )
-    GestureTutorialScreen(screenConfig, gestureMonitorProvider, onDoneButtonClicked, onBack)
+    GestureTutorialScreen(screenConfig, gestureRecognizerProvider, onDoneButtonClicked, onBack)
 }
 
 @Composable
@@ -64,7 +63,7 @@
         rememberLottieDynamicProperties(
             rememberColorFilterProperty(".primaryFixedDim", primaryFixedDim),
             rememberColorFilterProperty(".onPrimaryFixed", onPrimaryFixed),
-            rememberColorFilterProperty(".onPrimaryFixedVariant", onPrimaryFixedVariant)
+            rememberColorFilterProperty(".onPrimaryFixedVariant", onPrimaryFixedVariant),
         )
     val screenColors =
         remember(dynamicProperties) {
diff --git a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/RecentAppsGestureTutorialScreen.kt b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/RecentAppsGestureTutorialScreen.kt
index b2fb6cd..3097a18 100644
--- a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/RecentAppsGestureTutorialScreen.kt
+++ b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/RecentAppsGestureTutorialScreen.kt
@@ -24,15 +24,12 @@
 import com.android.systemui.inputdevice.tutorial.ui.composable.TutorialScreenConfig
 import com.android.systemui.inputdevice.tutorial.ui.composable.rememberColorFilterProperty
 import com.android.systemui.res.R
+import com.android.systemui.touchpad.tutorial.ui.gesture.GestureRecognizer
 import com.android.systemui.touchpad.tutorial.ui.gesture.GestureState
-import com.android.systemui.touchpad.tutorial.ui.gesture.RecentAppsGestureMonitor
-import com.android.systemui.touchpad.tutorial.ui.gesture.TouchpadGestureMonitor
+import com.android.systemui.touchpad.tutorial.ui.gesture.RecentAppsGestureRecognizer
 
 @Composable
-fun RecentAppsGestureTutorialScreen(
-    onDoneButtonClicked: () -> Unit,
-    onBack: () -> Unit,
-) {
+fun RecentAppsGestureTutorialScreen(onDoneButtonClicked: () -> Unit, onBack: () -> Unit) {
     val screenConfig =
         TutorialScreenConfig(
             colors = rememberScreenColors(),
@@ -41,21 +38,21 @@
                     titleResId = R.string.touchpad_recent_apps_gesture_action_title,
                     bodyResId = R.string.touchpad_recent_apps_gesture_guidance,
                     titleSuccessResId = R.string.touchpad_recent_apps_gesture_success_title,
-                    bodySuccessResId = R.string.touchpad_recent_apps_gesture_success_body
+                    bodySuccessResId = R.string.touchpad_recent_apps_gesture_success_body,
                 ),
             animations =
                 TutorialScreenConfig.Animations(
                     educationResId = R.raw.trackpad_recent_apps_edu,
-                    successResId = R.raw.trackpad_recent_apps_success
-                )
+                    successResId = R.raw.trackpad_recent_apps_success,
+                ),
         )
-    val gestureMonitorProvider =
-        object : GestureMonitorProvider {
+    val gestureRecognizerProvider =
+        object : GestureRecognizerProvider {
             @Composable
-            override fun rememberGestureMonitor(
+            override fun rememberGestureRecognizer(
                 resources: Resources,
-                gestureStateChangedCallback: (GestureState) -> Unit
-            ): TouchpadGestureMonitor {
+                gestureStateChangedCallback: (GestureState) -> Unit,
+            ): GestureRecognizer {
                 val distanceThresholdPx =
                     resources.getDimensionPixelSize(
                         com.android.internal.R.dimen.system_gestures_distance_threshold
@@ -63,15 +60,12 @@
                 val velocityThresholdPxPerMs =
                     resources.getDimension(R.dimen.touchpad_recent_apps_gesture_velocity_threshold)
                 return remember(distanceThresholdPx, velocityThresholdPxPerMs) {
-                    RecentAppsGestureMonitor(
-                        distanceThresholdPx,
-                        gestureStateChangedCallback,
-                        velocityThresholdPxPerMs
-                    )
+                    RecentAppsGestureRecognizer(distanceThresholdPx, velocityThresholdPxPerMs)
+                        .also { it.addGestureStateCallback(gestureStateChangedCallback) }
                 }
             }
         }
-    GestureTutorialScreen(screenConfig, gestureMonitorProvider, onDoneButtonClicked, onBack)
+    GestureTutorialScreen(screenConfig, gestureRecognizerProvider, onDoneButtonClicked, onBack)
 }
 
 @Composable
@@ -83,7 +77,7 @@
         rememberLottieDynamicProperties(
             rememberColorFilterProperty(".secondaryFixedDim", secondaryFixedDim),
             rememberColorFilterProperty(".onSecondaryFixed", onSecondaryFixed),
-            rememberColorFilterProperty(".onSecondaryFixedVariant", onSecondaryFixedVariant)
+            rememberColorFilterProperty(".onSecondaryFixedVariant", onSecondaryFixedVariant),
         )
     val screenColors =
         remember(dynamicProperties) {
diff --git a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/TutorialSelectionScreen.kt b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/TutorialSelectionScreen.kt
index 94e19de..3c31efa 100644
--- a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/TutorialSelectionScreen.kt
+++ b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/TutorialSelectionScreen.kt
@@ -84,7 +84,7 @@
     ) {
         TutorialButton(
             text = stringResource(R.string.touchpad_tutorial_home_gesture_button),
-            icon = Icons.AutoMirrored.Outlined.ArrowBack,
+            icon = ImageVector.vectorResource(id = R.drawable.touchpad_tutorial_home_icon),
             iconColor = MaterialTheme.colorScheme.onPrimary,
             onClick = onHomeTutorialClicked,
             backgroundColor = MaterialTheme.colorScheme.primary,
@@ -92,7 +92,7 @@
         )
         TutorialButton(
             text = stringResource(R.string.touchpad_tutorial_back_gesture_button),
-            icon = ImageVector.vectorResource(id = R.drawable.touchpad_tutorial_home_icon),
+            icon = Icons.AutoMirrored.Outlined.ArrowBack,
             iconColor = MaterialTheme.colorScheme.onTertiary,
             onClick = onBackTutorialClicked,
             backgroundColor = MaterialTheme.colorScheme.tertiary,
diff --git a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/gesture/BackGestureMonitor.kt b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/gesture/BackGestureMonitor.kt
deleted file mode 100644
index 084da2c..0000000
--- a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/gesture/BackGestureMonitor.kt
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (C) 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES 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.touchpad.tutorial.ui.gesture
-
-import kotlin.math.abs
-
-/** Monitors for touchpad back gesture, that is three fingers swiping left or right */
-class BackGestureMonitor(
-    override val gestureDistanceThresholdPx: Int,
-    override val gestureStateChangedCallback: (GestureState) -> Unit
-) :
-    TouchpadGestureMonitor by ThreeFingerDistanceBasedGestureMonitor(
-        gestureDistanceThresholdPx = gestureDistanceThresholdPx,
-        gestureStateChangedCallback = gestureStateChangedCallback,
-        donePredicate =
-            object : GestureDonePredicate {
-                override fun wasGestureDone(
-                    startX: Float,
-                    startY: Float,
-                    endX: Float,
-                    endY: Float
-                ): Boolean {
-                    val distance = abs(endX - startX)
-                    return distance >= gestureDistanceThresholdPx
-                }
-            }
-    )
diff --git a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/gesture/BackGestureRecognizer.kt b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/gesture/BackGestureRecognizer.kt
new file mode 100644
index 0000000..56e97a3
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/gesture/BackGestureRecognizer.kt
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.touchpad.tutorial.ui.gesture
+
+import android.view.MotionEvent
+import kotlin.math.abs
+
+/** Recognizes touchpad back gesture, that is three fingers swiping left or right */
+class BackGestureRecognizer(private val gestureDistanceThresholdPx: Int) : GestureRecognizer {
+
+    private val distanceTracker = DistanceTracker()
+    private var gestureStateChangedCallback: (GestureState) -> Unit = {}
+
+    override fun addGestureStateCallback(callback: (GestureState) -> Unit) {
+        gestureStateChangedCallback = callback
+    }
+
+    override fun accept(event: MotionEvent) {
+        if (!isThreeFingerTouchpadSwipe(event)) return
+        val gestureState = distanceTracker.processEvent(event)
+        updateGestureState(
+            gestureStateChangedCallback,
+            gestureState,
+            isFinished = { abs(it.deltaX) >= gestureDistanceThresholdPx },
+            progress = { 0f },
+        )
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/gesture/DistanceTracker.kt b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/gesture/DistanceTracker.kt
new file mode 100644
index 0000000..d482358
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/gesture/DistanceTracker.kt
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.touchpad.tutorial.ui.gesture
+
+import android.view.MotionEvent
+
+/**
+ * Tracks distance change for processed MotionEvents. Useful for recognizing gestures based on
+ * distance travelled instead of specific position on the screen.
+ */
+class DistanceTracker(var startX: Float = 0f, var startY: Float = 0f) {
+    fun processEvent(event: MotionEvent): DistanceGestureState? {
+        val action = event.actionMasked
+        return when (action) {
+            MotionEvent.ACTION_DOWN -> {
+                startX = event.x
+                startY = event.y
+                Started(event.x, event.y)
+            }
+            MotionEvent.ACTION_MOVE -> Moving(event.x - startX, event.y - startY)
+            MotionEvent.ACTION_UP -> Finished(event.x - startX, event.y - startY)
+            else -> null
+        }
+    }
+}
+
+sealed class DistanceGestureState(val deltaX: Float, val deltaY: Float)
+
+class Started(deltaX: Float, deltaY: Float) : DistanceGestureState(deltaX, deltaY)
+
+class Moving(deltaX: Float, deltaY: Float) : DistanceGestureState(deltaX, deltaY)
+
+class Finished(deltaX: Float, deltaY: Float) : DistanceGestureState(deltaX, deltaY)
diff --git a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/gesture/TouchpadGestureMonitor.kt b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/gesture/GestureRecognizer.kt
similarity index 77%
rename from packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/gesture/TouchpadGestureMonitor.kt
rename to packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/gesture/GestureRecognizer.kt
index 8774a92..d146268 100644
--- a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/gesture/TouchpadGestureMonitor.kt
+++ b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/gesture/GestureRecognizer.kt
@@ -17,17 +17,11 @@
 package com.android.systemui.touchpad.tutorial.ui.gesture
 
 import android.view.MotionEvent
+import java.util.function.Consumer
 
-/**
- * Monitor for touchpad gestures that calls [gestureStateChangedCallback] when [GestureState]
- * changes. All tracked motion events should be passed to [processTouchpadEvent]
- */
-interface TouchpadGestureMonitor {
-
-    val gestureDistanceThresholdPx: Int
-    val gestureStateChangedCallback: (GestureState) -> Unit
-
-    fun processTouchpadEvent(event: MotionEvent)
+/** Based on passed [MotionEvent]s recognizes different states of gesture and notifies callback. */
+interface GestureRecognizer : Consumer<MotionEvent> {
+    fun addGestureStateCallback(callback: (GestureState) -> Unit)
 }
 
 fun isThreeFingerTouchpadSwipe(event: MotionEvent) = isNFingerTouchpadSwipe(event, fingerCount = 3)
diff --git a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/gesture/GestureState.kt b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/gesture/GestureState.kt
index 446875a..b513c49 100644
--- a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/gesture/GestureState.kt
+++ b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/gesture/GestureState.kt
@@ -16,8 +16,10 @@
 
 package com.android.systemui.touchpad.tutorial.ui.gesture
 
-enum class GestureState {
-    NOT_STARTED,
-    IN_PROGRESS,
-    FINISHED
+sealed interface GestureState {
+    data object NotStarted : GestureState
+
+    data object Finished : GestureState
+
+    data class InProgress(val progress: Float = 0f) : GestureState
 }
diff --git a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/gesture/GestureStateUpdates.kt b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/gesture/GestureStateUpdates.kt
new file mode 100644
index 0000000..f194677
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/gesture/GestureStateUpdates.kt
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.touchpad.tutorial.ui.gesture
+
+/** Helper function for gesture recognizers to have common state triggering logic */
+inline fun updateGestureState(
+    gestureStateChangedCallback: (GestureState) -> Unit,
+    gestureState: DistanceGestureState?,
+    isFinished: (Finished) -> Boolean,
+    progress: (Moving) -> Float,
+) {
+    when (gestureState) {
+        is Finished -> {
+            if (isFinished(gestureState)) {
+                gestureStateChangedCallback(GestureState.Finished)
+            } else {
+                gestureStateChangedCallback(GestureState.NotStarted)
+            }
+        }
+        is Moving -> {
+            gestureStateChangedCallback(GestureState.InProgress(progress(gestureState)))
+        }
+        is Started -> gestureStateChangedCallback(GestureState.InProgress())
+        else -> {}
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/gesture/HomeGestureMonitor.kt b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/gesture/HomeGestureMonitor.kt
deleted file mode 100644
index a9aa5c8..0000000
--- a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/gesture/HomeGestureMonitor.kt
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (C) 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES 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.touchpad.tutorial.ui.gesture
-
-/** Monitors for touchpad home gesture, that is three fingers swiping up */
-class HomeGestureMonitor(
-    override val gestureDistanceThresholdPx: Int,
-    override val gestureStateChangedCallback: (GestureState) -> Unit
-) :
-    TouchpadGestureMonitor by ThreeFingerDistanceBasedGestureMonitor(
-        gestureDistanceThresholdPx = gestureDistanceThresholdPx,
-        gestureStateChangedCallback = gestureStateChangedCallback,
-        donePredicate =
-            object : GestureDonePredicate {
-                override fun wasGestureDone(
-                    startX: Float,
-                    startY: Float,
-                    endX: Float,
-                    endY: Float
-                ): Boolean {
-                    val distance = startY - endY
-                    return distance >= gestureDistanceThresholdPx
-                }
-            }
-    )
diff --git a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/gesture/HomeGestureRecognizer.kt b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/gesture/HomeGestureRecognizer.kt
new file mode 100644
index 0000000..3db9d7c
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/gesture/HomeGestureRecognizer.kt
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.touchpad.tutorial.ui.gesture
+
+import android.view.MotionEvent
+
+/** Recognizes touchpad home gesture, that is three fingers swiping up */
+class HomeGestureRecognizer(private val gestureDistanceThresholdPx: Int) : GestureRecognizer {
+
+    private val distanceTracker = DistanceTracker()
+    private var gestureStateChangedCallback: (GestureState) -> Unit = {}
+
+    override fun addGestureStateCallback(callback: (GestureState) -> Unit) {
+        gestureStateChangedCallback = callback
+    }
+
+    override fun accept(event: MotionEvent) {
+        if (!isThreeFingerTouchpadSwipe(event)) return
+        val gestureState = distanceTracker.processEvent(event)
+        updateGestureState(
+            gestureStateChangedCallback,
+            gestureState,
+            isFinished = { -it.deltaY >= gestureDistanceThresholdPx },
+            progress = { 0f },
+        )
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/gesture/RecentAppsGestureMonitor.kt b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/gesture/RecentAppsGestureMonitor.kt
deleted file mode 100644
index 5828239..0000000
--- a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/gesture/RecentAppsGestureMonitor.kt
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright (C) 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES 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.touchpad.tutorial.ui.gesture
-
-import android.view.MotionEvent
-import androidx.compose.ui.input.pointer.util.VelocityTracker1D
-import kotlin.math.abs
-
-/**
- * Monitors recent apps gesture completion. That is - using three fingers on touchpad - swipe up
- * over some distance threshold and then slow down gesture before fingers are lifted. Implementation
- * is based on [com.android.quickstep.util.TriggerSwipeUpTouchTracker]
- */
-class RecentAppsGestureMonitor(
-    override val gestureDistanceThresholdPx: Int,
-    override val gestureStateChangedCallback: (GestureState) -> Unit,
-    private val velocityThresholdPxPerMs: Float,
-    private val velocityTracker: VelocityTracker1D = VelocityTracker1D(isDataDifferential = false),
-) : TouchpadGestureMonitor {
-
-    private var xStart = 0f
-    private var yStart = 0f
-
-    override fun processTouchpadEvent(event: MotionEvent) {
-        val action = event.actionMasked
-        velocityTracker.addDataPoint(event.eventTime, event.y)
-        when (action) {
-            MotionEvent.ACTION_DOWN -> {
-                if (isThreeFingerTouchpadSwipe(event)) {
-                    xStart = event.x
-                    yStart = event.y
-                    gestureStateChangedCallback(GestureState.IN_PROGRESS)
-                }
-            }
-            MotionEvent.ACTION_UP -> {
-                if (isThreeFingerTouchpadSwipe(event) && isRecentAppsGesture(event)) {
-                    gestureStateChangedCallback(GestureState.FINISHED)
-                } else {
-                    gestureStateChangedCallback(GestureState.NOT_STARTED)
-                }
-                velocityTracker.resetTracking()
-            }
-            MotionEvent.ACTION_CANCEL -> {
-                velocityTracker.resetTracking()
-            }
-        }
-    }
-
-    private fun isRecentAppsGesture(event: MotionEvent): Boolean {
-        // below is trying to mirror behavior of TriggerSwipeUpTouchTracker#onGestureEnd.
-        // We're diving velocity by 1000, to have the same unit of measure: pixels/ms.
-        val swipeDistance = yStart - event.y
-        val velocity = velocityTracker.calculateVelocity() / 1000
-        return swipeDistance >= gestureDistanceThresholdPx &&
-            abs(velocity) <= velocityThresholdPxPerMs
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/gesture/RecentAppsGestureRecognizer.kt b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/gesture/RecentAppsGestureRecognizer.kt
new file mode 100644
index 0000000..a194ad6
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/gesture/RecentAppsGestureRecognizer.kt
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.touchpad.tutorial.ui.gesture
+
+import android.view.MotionEvent
+import kotlin.math.abs
+
+/**
+ * Recognizes apps gesture completion. That is - using three fingers on touchpad - swipe up over
+ * some distance threshold and then slow down gesture before fingers are lifted. Implementation is
+ * based on [com.android.quickstep.util.TriggerSwipeUpTouchTracker]
+ */
+class RecentAppsGestureRecognizer(
+    private val gestureDistanceThresholdPx: Int,
+    private val velocityThresholdPxPerMs: Float,
+    private val distanceTracker: DistanceTracker = DistanceTracker(),
+    private val velocityTracker: VerticalVelocityTracker = VerticalVelocityTracker(),
+) : GestureRecognizer {
+
+    private var gestureStateChangedCallback: (GestureState) -> Unit = {}
+
+    override fun addGestureStateCallback(callback: (GestureState) -> Unit) {
+        gestureStateChangedCallback = callback
+    }
+
+    override fun accept(event: MotionEvent) {
+        if (!isThreeFingerTouchpadSwipe(event)) return
+        val gestureState = distanceTracker.processEvent(event)
+        velocityTracker.accept(event)
+
+        updateGestureState(
+            gestureStateChangedCallback,
+            gestureState,
+            isFinished = { state ->
+                -state.deltaY >= gestureDistanceThresholdPx &&
+                    abs(velocityTracker.calculateVelocity().value) <= velocityThresholdPxPerMs
+            },
+            progress = { 0f },
+        )
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/gesture/ThreeFingerDistanceBasedGestureMonitor.kt b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/gesture/ThreeFingerDistanceBasedGestureMonitor.kt
deleted file mode 100644
index 9bf0fe9..0000000
--- a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/gesture/ThreeFingerDistanceBasedGestureMonitor.kt
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (C) 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES 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.touchpad.tutorial.ui.gesture
-
-import android.view.MotionEvent
-
-interface GestureDonePredicate {
-    /**
-     * Should return if gesture was finished. The only events this predicate receives are ACTION_UP.
-     */
-    fun wasGestureDone(startX: Float, startY: Float, endX: Float, endY: Float): Boolean
-}
-
-/**
- * Common implementation for three-finger gesture monitors that are only distance-based. E.g. recent
- * apps gesture is not only distance-based because it requires going over threshold distance and
- * slowing down the movement.
- */
-class ThreeFingerDistanceBasedGestureMonitor(
-    override val gestureDistanceThresholdPx: Int,
-    override val gestureStateChangedCallback: (GestureState) -> Unit,
-    private val donePredicate: GestureDonePredicate
-) : TouchpadGestureMonitor {
-
-    private var xStart = 0f
-    private var yStart = 0f
-
-    override fun processTouchpadEvent(event: MotionEvent) {
-        val action = event.actionMasked
-        when (action) {
-            MotionEvent.ACTION_DOWN -> {
-                if (isThreeFingerTouchpadSwipe(event)) {
-                    xStart = event.x
-                    yStart = event.y
-                    gestureStateChangedCallback(GestureState.IN_PROGRESS)
-                }
-            }
-            MotionEvent.ACTION_UP -> {
-                if (isThreeFingerTouchpadSwipe(event)) {
-                    if (donePredicate.wasGestureDone(xStart, yStart, event.x, event.y)) {
-                        gestureStateChangedCallback(GestureState.FINISHED)
-                    } else {
-                        gestureStateChangedCallback(GestureState.NOT_STARTED)
-                    }
-                }
-            }
-        }
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/gesture/TouchpadGestureHandler.kt b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/gesture/TouchpadGestureHandler.kt
index 88671d4..21e2917 100644
--- a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/gesture/TouchpadGestureHandler.kt
+++ b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/gesture/TouchpadGestureHandler.kt
@@ -18,13 +18,14 @@
 
 import android.view.InputDevice
 import android.view.MotionEvent
+import java.util.function.Consumer
 
 /**
  * Allows listening to touchpadGesture and calling onDone when gesture was triggered. Can have all
  * motion events passed to [onMotionEvent] and will filter touchpad events accordingly
  */
 class TouchpadGestureHandler(
-    private val gestureMonitor: TouchpadGestureMonitor,
+    private val gestureRecognizer: Consumer<MotionEvent>,
     private val easterEggGestureMonitor: EasterEggGestureMonitor,
 ) {
 
@@ -40,7 +41,7 @@
             if (isTwoFingerSwipe(event)) {
                 easterEggGestureMonitor.processTouchpadEvent(event)
             } else {
-                gestureMonitor.processTouchpadEvent(event)
+                gestureRecognizer.accept(event)
             }
             true
         } else {
diff --git a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/gesture/VelocityTracker.kt b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/gesture/VelocityTracker.kt
new file mode 100644
index 0000000..9b38eca
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/gesture/VelocityTracker.kt
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.touchpad.tutorial.ui.gesture
+
+import android.view.MotionEvent
+import androidx.compose.ui.input.pointer.util.VelocityTracker1D
+import java.util.function.Consumer
+
+/** Velocity in pixels/ms. */
+@JvmInline value class Velocity(val value: Float)
+
+/**
+ * Tracks velocity for processed MotionEvents. Useful for recognizing gestures based on velocity.
+ */
+interface VelocityTracker : Consumer<MotionEvent> {
+
+    fun calculateVelocity(): Velocity
+}
+
+class VerticalVelocityTracker(
+    private val velocityTracker: VelocityTracker1D = VelocityTracker1D(isDataDifferential = false)
+) : VelocityTracker {
+
+    override fun accept(event: MotionEvent) {
+        val action = event.actionMasked
+        if (action == MotionEvent.ACTION_DOWN) {
+            velocityTracker.resetTracking()
+        }
+        velocityTracker.addDataPoint(event.eventTime, event.y)
+    }
+
+    /**
+     * Calculates velocity on demand - this calculation can be expensive so shouldn't be called
+     * after every event.
+     */
+    override fun calculateVelocity() = Velocity(velocityTracker.calculateVelocity() / 1000)
+}
diff --git a/packages/SystemUI/src/com/android/systemui/user/legacyhelper/ui/LegacyUserUiHelper.kt b/packages/SystemUI/src/com/android/systemui/user/legacyhelper/ui/LegacyUserUiHelper.kt
index 8957fe1..09cef1e 100644
--- a/packages/SystemUI/src/com/android/systemui/user/legacyhelper/ui/LegacyUserUiHelper.kt
+++ b/packages/SystemUI/src/com/android/systemui/user/legacyhelper/ui/LegacyUserUiHelper.kt
@@ -18,6 +18,7 @@
 package com.android.systemui.user.legacyhelper.ui
 
 import android.content.Context
+import android.util.Log
 import androidx.annotation.DrawableRes
 import androidx.annotation.StringRes
 import com.android.systemui.res.R
@@ -32,6 +33,8 @@
  */
 object LegacyUserUiHelper {
 
+    private const val TAG = "LegacyUserUiHelper"
+
     @JvmStatic
     @DrawableRes
     fun getUserSwitcherActionIconResourceId(
@@ -67,7 +70,9 @@
         val resourceId: Int? = getGuestUserRecordNameResourceId(record)
         return when {
             resourceId != null -> context.getString(resourceId)
-            record.info != null -> checkNotNull(record.info.name)
+            record.info != null ->
+                record.info.name
+                    ?: "".also { Log.i(TAG, "Expected display name for: ${record.info}") }
             else ->
                 context.getString(
                     getUserSwitcherActionTextResourceId(
diff --git a/packages/SystemUI/src/com/android/systemui/util/AlphaTintDrawableWrapper.java b/packages/SystemUI/src/com/android/systemui/util/AlphaTintDrawableWrapper.java
index 947746c..4b2fe49 100644
--- a/packages/SystemUI/src/com/android/systemui/util/AlphaTintDrawableWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/util/AlphaTintDrawableWrapper.java
@@ -45,8 +45,8 @@
  * This class should only be used in XML.
  *
  * @attr ref android.R.styleable#DrawableWrapper_drawable
- * @attr ref R.styleable#AlphaTintDrawableWrapper_tint
- * @attr ref R.styleable#AlphaTintDrawableWrapper_alpha
+ * @attr ref android.R.styleable#AlphaTintDrawableWrapper_tint
+ * @attr ref android.R.styleable#AlphaTintDrawableWrapper_alpha
  */
 public class AlphaTintDrawableWrapper extends InsetDrawable {
     private ColorStateList mTint;
diff --git a/packages/SystemUI/src/com/android/systemui/util/WallpaperController.kt b/packages/SystemUI/src/com/android/systemui/util/WallpaperController.kt
index 65a0218..0744b5a 100644
--- a/packages/SystemUI/src/com/android/systemui/util/WallpaperController.kt
+++ b/packages/SystemUI/src/com/android/systemui/util/WallpaperController.kt
@@ -32,19 +32,24 @@
  * Note: New logic should be added to [WallpaperRepository], not this class.
  */
 @SysUISingleton
-class WallpaperController @Inject constructor(
+class WallpaperController
+@Inject
+constructor(
     private val wallpaperManager: WallpaperManager,
     private val wallpaperRepository: WallpaperRepository,
 ) {
 
     var rootView: View? = null
+        set(value) {
+            field = value
+            wallpaperRepository.rootView = value
+        }
 
     private var notificationShadeZoomOut: Float = 0f
     private var unfoldTransitionZoomOut: Float = 0f
 
     private val shouldUseDefaultUnfoldTransition: Boolean
-        get() = wallpaperRepository.wallpaperInfo.value?.shouldUseDefaultUnfoldTransition()
-            ?: true
+        get() = wallpaperRepository.wallpaperInfo.value?.shouldUseDefaultUnfoldTransition() ?: true
 
     fun setNotificationShadeZoom(zoomOut: Float) {
         notificationShadeZoomOut = zoomOut
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
index 1f92bc1..bbd8f3dc 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
@@ -59,7 +59,6 @@
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
-import androidx.annotation.VisibleForTesting;
 import androidx.lifecycle.Observer;
 
 import com.android.internal.annotations.GuardedBy;
@@ -110,8 +109,8 @@
     // It is safe to use 99 as the broadcast stream now. There are only 10+ default audio
     // streams defined in AudioSystem for now and audio team is in the middle of restructure,
     // no new default stream is preferred.
-    @VisibleForTesting static final int DYNAMIC_STREAM_BROADCAST = 99;
-    private static final int DYNAMIC_STREAM_REMOTE_START_INDEX = 100;
+    public static final int DYNAMIC_STREAM_BROADCAST = 99;
+    public static final int DYNAMIC_STREAM_REMOTE_START_INDEX = 100;
     private static final AudioAttributes SONIFICIATION_VIBRATION_ATTRIBUTES =
             new AudioAttributes.Builder()
                     .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
index 7166428..7c5116d 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
@@ -537,7 +537,7 @@
 
         mWindow.setAttributes(lp);
         mWindow.setLayout(WRAP_CONTENT, WRAP_CONTENT);
-        mDialog.setContentView(R.layout.volume_dialog);
+        mDialog.setContentView(R.layout.volume_dialog_legacy);
         mDialogView = mDialog.findViewById(R.id.volume_dialog);
         mDialogView.setAlpha(0);
         mDialogTimeoutMillis = mSecureSettings.get().getInt(
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/dagger/module/VolumeDialogPluginModule.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/dagger/module/VolumeDialogPluginModule.kt
index 3fdf86a..cd8cdc8 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/dialog/dagger/module/VolumeDialogPluginModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/dagger/module/VolumeDialogPluginModule.kt
@@ -17,6 +17,13 @@
 package com.android.systemui.volume.dialog.dagger.module
 
 import com.android.systemui.volume.dialog.dagger.VolumeDialogComponent
+import com.android.systemui.volume.dialog.utils.VolumeTracer
+import com.android.systemui.volume.dialog.utils.VolumeTracerImpl
+import dagger.Binds
 import dagger.Module
 
-@Module(subcomponents = [VolumeDialogComponent::class]) interface VolumeDialogPluginModule
+@Module(subcomponents = [VolumeDialogComponent::class])
+interface VolumeDialogPluginModule {
+
+    @Binds fun bindVolumeTracer(volumeTracer: VolumeTracerImpl): VolumeTracer
+}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/data/VolumeDialogVisibilityRepository.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/data/VolumeDialogVisibilityRepository.kt
new file mode 100644
index 0000000..2aeaa5c
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/data/VolumeDialogVisibilityRepository.kt
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.volume.dialog.data
+
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.volume.dialog.shared.model.VolumeDialogVisibilityModel
+import javax.inject.Inject
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.asStateFlow
+import kotlinx.coroutines.flow.update
+
+@SysUISingleton
+class VolumeDialogVisibilityRepository @Inject constructor() {
+
+    private val mutableDialogVisibility =
+        MutableStateFlow<VolumeDialogVisibilityModel>(VolumeDialogVisibilityModel.Invisible)
+    val dialogVisibility: Flow<VolumeDialogVisibilityModel> = mutableDialogVisibility.asStateFlow()
+
+    fun updateVisibility(
+        update: (current: VolumeDialogVisibilityModel) -> VolumeDialogVisibilityModel
+    ) {
+        mutableDialogVisibility.update(update)
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/data/repository/VolumeDialogStateRepository.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/data/repository/VolumeDialogStateRepository.kt
new file mode 100644
index 0000000..26fdb9f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/data/repository/VolumeDialogStateRepository.kt
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.volume.dialog.data.repository
+
+import com.android.systemui.volume.dialog.dagger.scope.VolumeDialogPlugin
+import com.android.systemui.volume.dialog.shared.model.VolumeDialogStateModel
+import javax.inject.Inject
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.asStateFlow
+import kotlinx.coroutines.flow.update
+
+/** Holds current [VolumeDialogStateModel]. */
+@VolumeDialogPlugin
+class VolumeDialogStateRepository @Inject constructor() {
+
+    private val mutableState = MutableStateFlow(VolumeDialogStateModel())
+    val state: Flow<VolumeDialogStateModel> = mutableState.asStateFlow()
+
+    fun updateState(update: (VolumeDialogStateModel) -> VolumeDialogStateModel) {
+        mutableState.update(update)
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/domain/interactor/VolumeDialogCallbacksInteractor.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/domain/interactor/VolumeDialogCallbacksInteractor.kt
index 2e26fd6..3d125b8 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/dialog/domain/interactor/VolumeDialogCallbacksInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/domain/interactor/VolumeDialogCallbacksInteractor.kt
@@ -23,7 +23,6 @@
 import com.android.systemui.volume.dialog.dagger.scope.VolumeDialogPlugin
 import com.android.systemui.volume.dialog.dagger.scope.VolumeDialogPluginScope
 import com.android.systemui.volume.dialog.domain.model.VolumeDialogEventModel
-import com.android.systemui.volume.dialog.domain.model.VolumeDialogStateModel
 import javax.inject.Inject
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.channels.ProducerScope
@@ -50,7 +49,7 @@
     @Background private val bgHandler: Handler,
 ) {
 
-    @SuppressLint("SharedFlowCreation") // event-but needed
+    @SuppressLint("SharedFlowCreation") // event-bus needed
     val event: Flow<VolumeDialogEventModel> =
         callbackFlow {
                 val producer = VolumeDialogEventModelProducer(this)
@@ -79,7 +78,7 @@
 
         override fun onStateChanged(state: VolumeDialogController.State?) {
             if (state != null) {
-                scope.trySend(VolumeDialogEventModel.StateChanged(VolumeDialogStateModel(state)))
+                scope.trySend(VolumeDialogEventModel.StateChanged(state))
             }
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/domain/interactor/VolumeDialogStateInteractor.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/domain/interactor/VolumeDialogStateInteractor.kt
index 4a709a44b..5c7289b 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/dialog/domain/interactor/VolumeDialogStateInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/domain/interactor/VolumeDialogStateInteractor.kt
@@ -16,20 +16,21 @@
 
 package com.android.systemui.volume.dialog.domain.interactor
 
+import android.util.SparseArray
+import androidx.core.util.keyIterator
 import com.android.systemui.plugins.VolumeDialogController
 import com.android.systemui.volume.dialog.dagger.scope.VolumeDialogPlugin
 import com.android.systemui.volume.dialog.dagger.scope.VolumeDialogPluginScope
+import com.android.systemui.volume.dialog.data.repository.VolumeDialogStateRepository
 import com.android.systemui.volume.dialog.domain.model.VolumeDialogEventModel
-import com.android.systemui.volume.dialog.domain.model.VolumeDialogStateModel
+import com.android.systemui.volume.dialog.shared.model.VolumeDialogStateModel
+import com.android.systemui.volume.dialog.shared.model.VolumeDialogStreamModel
 import javax.inject.Inject
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.SharingStarted
-import kotlinx.coroutines.flow.filterIsInstance
-import kotlinx.coroutines.flow.filterNotNull
-import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
 import kotlinx.coroutines.flow.onStart
-import kotlinx.coroutines.flow.stateIn
 
 /**
  * Exposes [VolumeDialogController.getState] in the [volumeDialogState].
@@ -42,14 +43,69 @@
 constructor(
     volumeDialogCallbacksInteractor: VolumeDialogCallbacksInteractor,
     private val volumeDialogController: VolumeDialogController,
+    private val volumeDialogStateRepository: VolumeDialogStateRepository,
     @VolumeDialogPlugin private val coroutineScope: CoroutineScope,
 ) {
 
-    val volumeDialogState: Flow<VolumeDialogStateModel> =
+    init {
         volumeDialogCallbacksInteractor.event
+            .onEach { event ->
+                when (event) {
+                    is VolumeDialogEventModel.StateChanged -> {
+                        volumeDialogStateRepository.updateState { oldState ->
+                            event.state.copyIntoModel(oldState)
+                        }
+                    }
+                    is VolumeDialogEventModel.AccessibilityModeChanged -> {
+                        volumeDialogStateRepository.updateState { oldState ->
+                            oldState.copy(shouldShowA11ySlider = event.showA11yStream)
+                        }
+                    }
+                    else -> {
+                        // do nothing
+                    }
+                }
+            }
             .onStart { volumeDialogController.getState() }
-            .filterIsInstance(VolumeDialogEventModel.StateChanged::class)
-            .map { it.state }
-            .stateIn(scope = coroutineScope, started = SharingStarted.Eagerly, initialValue = null)
-            .filterNotNull()
+            .launchIn(coroutineScope)
+    }
+
+    val volumeDialogState: Flow<VolumeDialogStateModel> = volumeDialogStateRepository.state
+
+    /** Returns a copy of [model] filled with the values from [VolumeDialogController.State]. */
+    private fun VolumeDialogController.State.copyIntoModel(
+        model: VolumeDialogStateModel
+    ): VolumeDialogStateModel {
+        return model.copy(
+            streamModels =
+                states.mapToMap { stream, streamState ->
+                    VolumeDialogStreamModel(
+                        stream = stream,
+                        isActive = stream == activeStream,
+                        legacyState = streamState,
+                    )
+                },
+            ringerModeInternal = ringerModeInternal,
+            ringerModeExternal = ringerModeExternal,
+            zenMode = zenMode,
+            effectsSuppressor = effectsSuppressor,
+            effectsSuppressorName = effectsSuppressorName,
+            activeStream = activeStream,
+            disallowAlarms = disallowAlarms,
+            disallowMedia = disallowMedia,
+            disallowSystem = disallowSystem,
+            disallowRinger = disallowRinger,
+        )
+    }
+}
+
+private fun <INPUT, OUTPUT> SparseArray<INPUT>.mapToMap(
+    map: (Int, INPUT) -> OUTPUT
+): Map<Int, OUTPUT> {
+    val resultMap = mutableMapOf<Int, OUTPUT>()
+    for (key in keyIterator()) {
+        val mappedValue: OUTPUT = map(key, get(key)!!)
+        resultMap[key] = mappedValue
+    }
+    return resultMap
 }
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/domain/interactor/VolumeDialogVisibilityInteractor.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/domain/interactor/VolumeDialogVisibilityInteractor.kt
index 6c92754..2668589b 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/dialog/domain/interactor/VolumeDialogVisibilityInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/domain/interactor/VolumeDialogVisibilityInteractor.kt
@@ -20,8 +20,12 @@
 import com.android.systemui.volume.Events
 import com.android.systemui.volume.dialog.dagger.scope.VolumeDialogPlugin
 import com.android.systemui.volume.dialog.dagger.scope.VolumeDialogPluginScope
+import com.android.systemui.volume.dialog.data.VolumeDialogVisibilityRepository
 import com.android.systemui.volume.dialog.domain.model.VolumeDialogEventModel
-import com.android.systemui.volume.dialog.domain.model.VolumeDialogVisibilityModel
+import com.android.systemui.volume.dialog.shared.model.VolumeDialogVisibilityModel
+import com.android.systemui.volume.dialog.shared.model.VolumeDialogVisibilityModel.Dismissed
+import com.android.systemui.volume.dialog.shared.model.VolumeDialogVisibilityModel.Visible
+import com.android.systemui.volume.dialog.utils.VolumeTracer
 import javax.inject.Inject
 import kotlin.time.Duration
 import kotlin.time.Duration.Companion.seconds
@@ -30,15 +34,13 @@
 import kotlinx.coroutines.delay
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.MutableSharedFlow
-import kotlinx.coroutines.flow.MutableStateFlow
-import kotlinx.coroutines.flow.asStateFlow
 import kotlinx.coroutines.flow.launchIn
 import kotlinx.coroutines.flow.mapLatest
+import kotlinx.coroutines.flow.mapNotNull
 import kotlinx.coroutines.flow.merge
 import kotlinx.coroutines.flow.onEach
-import kotlinx.coroutines.flow.update
 
-private val maxDialogShowTime: Duration = 3.seconds
+private val MAX_DIALOG_SHOW_TIME: Duration = 3.seconds
 
 /**
  * Handles Volume Dialog visibility state. It might change from several sources:
@@ -53,29 +55,27 @@
 constructor(
     @VolumeDialogPlugin coroutineScope: CoroutineScope,
     callbacksInteractor: VolumeDialogCallbacksInteractor,
+    private val tracer: VolumeTracer,
+    private val repository: VolumeDialogVisibilityRepository,
 ) {
 
     @SuppressLint("SharedFlowCreation")
     private val mutableDismissDialogEvents = MutableSharedFlow<Unit>()
-    private val mutableDialogVisibility =
-        MutableStateFlow<VolumeDialogVisibilityModel>(VolumeDialogVisibilityModel.Invisible)
-
-    val dialogVisibility: Flow<VolumeDialogVisibilityModel> = mutableDialogVisibility.asStateFlow()
+    val dialogVisibility: Flow<VolumeDialogVisibilityModel> = repository.dialogVisibility
 
     init {
         merge(
                 mutableDismissDialogEvents.mapLatest {
-                    delay(maxDialogShowTime)
+                    delay(MAX_DIALOG_SHOW_TIME)
                     VolumeDialogEventModel.DismissRequested(Events.DISMISS_REASON_TIMEOUT)
                 },
                 callbacksInteractor.event,
             )
-            .onEach { event ->
-                VolumeDialogVisibilityModel.fromEvent(event)?.let { model ->
-                    mutableDialogVisibility.value = model
-                    if (model is VolumeDialogVisibilityModel.Visible) {
-                        resetDismissTimeout()
-                    }
+            .mapNotNull { it.toVisibilityModel() }
+            .onEach { model ->
+                updateVisibility { model }
+                if (model is VolumeDialogVisibilityModel.Visible) {
+                    resetDismissTimeout()
                 }
             }
             .launchIn(coroutineScope)
@@ -86,9 +86,9 @@
      * [dialogVisibility].
      */
     fun dismissDialog(reason: Int) {
-        mutableDialogVisibility.update {
-            if (it is VolumeDialogVisibilityModel.Dismissed) {
-                it
+        updateVisibility { visibilityModel ->
+            if (visibilityModel is VolumeDialogVisibilityModel.Dismissed) {
+                visibilityModel
             } else {
                 VolumeDialogVisibilityModel.Dismissed(reason)
             }
@@ -99,4 +99,19 @@
     suspend fun resetDismissTimeout() {
         mutableDismissDialogEvents.emit(Unit)
     }
+
+    private fun updateVisibility(
+        update: (VolumeDialogVisibilityModel) -> VolumeDialogVisibilityModel
+    ) {
+        repository.updateVisibility { update(it).also(tracer::traceVisibilityStart) }
+    }
+
+    private fun VolumeDialogEventModel.toVisibilityModel(): VolumeDialogVisibilityModel? {
+        return when (this) {
+            is VolumeDialogEventModel.DismissRequested -> Dismissed(reason)
+            is VolumeDialogEventModel.ShowRequested ->
+                Visible(reason, keyguardLocked, lockTaskModeState)
+            else -> null
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/domain/model/VolumeDialogEventModel.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/domain/model/VolumeDialogEventModel.kt
index ca0310e..80e4238 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/dialog/domain/model/VolumeDialogEventModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/domain/model/VolumeDialogEventModel.kt
@@ -17,6 +17,7 @@
 package com.android.systemui.volume.dialog.domain.model
 
 import android.media.AudioManager
+import com.android.systemui.plugins.VolumeDialogController
 
 /**
  * Models VolumeDialogController callback events.
@@ -33,7 +34,7 @@
 
     data class DismissRequested(val reason: Int) : VolumeDialogEventModel
 
-    data class StateChanged(val state: VolumeDialogStateModel) : VolumeDialogEventModel
+    data class StateChanged(val state: VolumeDialogController.State) : VolumeDialogEventModel
 
     data class LayoutDirectionChanged(val layoutDirection: Int) : VolumeDialogEventModel
 
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/domain/model/VolumeDialogStateModel.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/domain/model/VolumeDialogStateModel.kt
deleted file mode 100644
index f1443e3..0000000
--- a/packages/SystemUI/src/com/android/systemui/volume/dialog/domain/model/VolumeDialogStateModel.kt
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright (C) 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES 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.volume.dialog.domain.model
-
-import android.content.ComponentName
-import android.util.SparseArray
-import androidx.core.util.keyIterator
-import com.android.systemui.plugins.VolumeDialogController
-
-/** Models a state of the Volume Dialog. */
-data class VolumeDialogStateModel(
-    val states: Map<Int, VolumeDialogStreamStateModel>,
-    val ringerModeInternal: Int = 0,
-    val ringerModeExternal: Int = 0,
-    val zenMode: Int = 0,
-    val effectsSuppressor: ComponentName? = null,
-    val effectsSuppressorName: String? = null,
-    val activeStream: Int = NO_ACTIVE_STREAM,
-    val disallowAlarms: Boolean = false,
-    val disallowMedia: Boolean = false,
-    val disallowSystem: Boolean = false,
-    val disallowRinger: Boolean = false,
-) {
-
-    constructor(
-        legacyState: VolumeDialogController.State
-    ) : this(
-        states = legacyState.states.mapToMap { VolumeDialogStreamStateModel(it) },
-        ringerModeInternal = legacyState.ringerModeInternal,
-        ringerModeExternal = legacyState.ringerModeExternal,
-        zenMode = legacyState.zenMode,
-        effectsSuppressor = legacyState.effectsSuppressor,
-        effectsSuppressorName = legacyState.effectsSuppressorName,
-        activeStream = legacyState.activeStream,
-        disallowAlarms = legacyState.disallowAlarms,
-        disallowMedia = legacyState.disallowMedia,
-        disallowSystem = legacyState.disallowSystem,
-        disallowRinger = legacyState.disallowRinger,
-    )
-
-    companion object {
-        const val NO_ACTIVE_STREAM: Int = -1
-    }
-}
-
-private fun <INPUT, OUTPUT> SparseArray<INPUT>.mapToMap(map: (INPUT) -> OUTPUT): Map<Int, OUTPUT> {
-    val resultMap = mutableMapOf<Int, OUTPUT>()
-    for (key in keyIterator()) {
-        val mappedValue: OUTPUT = map(get(key)!!)
-        resultMap[key] = mappedValue
-    }
-    return resultMap
-}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/settings/domain/VolumeDialogSettingsButtonInteractor.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/settings/domain/VolumeDialogSettingsButtonInteractor.kt
new file mode 100644
index 0000000..2dd0bda
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/settings/domain/VolumeDialogSettingsButtonInteractor.kt
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.volume.dialog.settings.domain
+
+import android.app.ActivityManager
+import com.android.app.tracing.coroutines.flow.map
+import com.android.systemui.statusbar.policy.DeviceProvisionedController
+import com.android.systemui.volume.Events
+import com.android.systemui.volume.dialog.dagger.scope.VolumeDialog
+import com.android.systemui.volume.dialog.dagger.scope.VolumeDialogScope
+import com.android.systemui.volume.dialog.domain.interactor.VolumeDialogVisibilityInteractor
+import com.android.systemui.volume.dialog.shared.model.VolumeDialogVisibilityModel
+import com.android.systemui.volume.panel.domain.interactor.VolumePanelGlobalStateInteractor
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.filterIsInstance
+import kotlinx.coroutines.flow.stateIn
+
+@VolumeDialogScope
+class VolumeDialogSettingsButtonInteractor
+@Inject
+constructor(
+    @VolumeDialog private val coroutineScope: CoroutineScope,
+    private val deviceProvisionedController: DeviceProvisionedController,
+    private val volumePanelGlobalStateInteractor: VolumePanelGlobalStateInteractor,
+    private val visibilityInteractor: VolumeDialogVisibilityInteractor,
+) {
+
+    val isVisible: StateFlow<Boolean> =
+        visibilityInteractor.dialogVisibility
+            .filterIsInstance(VolumeDialogVisibilityModel.Visible::class)
+            .map { model ->
+                deviceProvisionedController.isCurrentUserSetup() &&
+                    model.lockTaskModeState == ActivityManager.LOCK_TASK_MODE_NONE
+            }
+            .stateIn(coroutineScope, SharingStarted.Eagerly, false)
+
+    fun onButtonClicked() {
+        volumePanelGlobalStateInteractor.setVisible(true)
+        visibilityInteractor.dismissDialog(Events.DISMISS_REASON_SETTINGS_CLICKED)
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/settings/ui/binder/VolumeDialogSettingsButtonViewBinder.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/settings/ui/binder/VolumeDialogSettingsButtonViewBinder.kt
new file mode 100644
index 0000000..b2f6cb3
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/settings/ui/binder/VolumeDialogSettingsButtonViewBinder.kt
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.volume.dialog.settings.ui.binder
+
+import android.view.View
+import com.android.systemui.lifecycle.WindowLifecycleState
+import com.android.systemui.lifecycle.repeatWhenAttached
+import com.android.systemui.lifecycle.setSnapshotBinding
+import com.android.systemui.lifecycle.viewModel
+import com.android.systemui.res.R
+import com.android.systemui.volume.dialog.dagger.scope.VolumeDialogScope
+import com.android.systemui.volume.dialog.settings.ui.viewmodel.VolumeDialogSettingsButtonViewModel
+import javax.inject.Inject
+import kotlinx.coroutines.awaitCancellation
+
+@VolumeDialogScope
+class VolumeDialogSettingsButtonViewBinder
+@Inject
+constructor(private val viewModelFactory: VolumeDialogSettingsButtonViewModel.Factory) {
+
+    fun bind(view: View) {
+        with(view) {
+            val button = requireViewById<View>(R.id.volume_dialog_settings)
+            repeatWhenAttached {
+                viewModel(
+                    traceName = "VolumeDialogViewBinder",
+                    minWindowLifecycleState = WindowLifecycleState.ATTACHED,
+                    factory = { viewModelFactory.create() },
+                ) { viewModel ->
+                    setSnapshotBinding {
+                        visibility = if (viewModel.isVisible) View.VISIBLE else View.GONE
+                        button.setOnClickListener { viewModel.onButtonClicked() }
+                    }
+
+                    awaitCancellation()
+                }
+            }
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/settings/ui/viewmodel/VolumeDialogSettingsButtonViewModel.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/settings/ui/viewmodel/VolumeDialogSettingsButtonViewModel.kt
new file mode 100644
index 0000000..2acc33b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/settings/ui/viewmodel/VolumeDialogSettingsButtonViewModel.kt
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.volume.dialog.settings.ui.viewmodel
+
+import androidx.compose.runtime.getValue
+import com.android.systemui.lifecycle.ExclusiveActivatable
+import com.android.systemui.lifecycle.Hydrator
+import com.android.systemui.volume.dialog.dagger.scope.VolumeDialogScope
+import com.android.systemui.volume.dialog.settings.domain.VolumeDialogSettingsButtonInteractor
+import dagger.assisted.AssistedFactory
+import dagger.assisted.AssistedInject
+
+class VolumeDialogSettingsButtonViewModel
+@AssistedInject
+constructor(private val interactor: VolumeDialogSettingsButtonInteractor) : ExclusiveActivatable() {
+
+    private val hydrator = Hydrator("VolumeDialog_settings_button")
+
+    val isVisible by hydrator.hydratedStateOf("isVisible", interactor.isVisible)
+
+    override suspend fun onActivated(): Nothing {
+        hydrator.activate()
+    }
+
+    fun onButtonClicked() {
+        interactor.onButtonClicked()
+    }
+
+    @VolumeDialogScope
+    @AssistedFactory
+    interface Factory {
+
+        fun create(): VolumeDialogSettingsButtonViewModel
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/shared/model/VolumeDialogStateModel.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/shared/model/VolumeDialogStateModel.kt
new file mode 100644
index 0000000..1792b99
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/shared/model/VolumeDialogStateModel.kt
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.volume.dialog.shared.model
+
+import android.content.ComponentName
+
+/** Models a state of the Volume Dialog. */
+data class VolumeDialogStateModel(
+    val shouldShowA11ySlider: Boolean = false,
+    val streamModels: Map<Int, VolumeDialogStreamModel> = mapOf(),
+    val ringerModeInternal: Int = 0,
+    val ringerModeExternal: Int = 0,
+    val zenMode: Int = 0,
+    val effectsSuppressor: ComponentName? = null,
+    val effectsSuppressorName: String? = null,
+    val activeStream: Int = NO_ACTIVE_STREAM,
+    val disallowAlarms: Boolean = false,
+    val disallowMedia: Boolean = false,
+    val disallowSystem: Boolean = false,
+    val disallowRinger: Boolean = false,
+) {
+
+    companion object {
+        const val NO_ACTIVE_STREAM: Int = -1
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/domain/model/VolumeDialogStreamStateModel.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/shared/model/VolumeDialogStreamModel.kt
similarity index 79%
rename from packages/SystemUI/src/com/android/systemui/volume/dialog/domain/model/VolumeDialogStreamStateModel.kt
rename to packages/SystemUI/src/com/android/systemui/volume/dialog/shared/model/VolumeDialogStreamModel.kt
index a9d367d..be3cd97 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/dialog/domain/model/VolumeDialogStreamStateModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/shared/model/VolumeDialogStreamModel.kt
@@ -14,26 +14,32 @@
  * limitations under the License.
  */
 
-package com.android.systemui.volume.dialog.domain.model
+package com.android.systemui.volume.dialog.shared.model
 
-import android.annotation.IntegerRes
+import androidx.annotation.StringRes
 import com.android.systemui.plugins.VolumeDialogController
 
 /** Models a state of an audio stream of the Volume Dialog. */
-data class VolumeDialogStreamStateModel(
+data class VolumeDialogStreamModel(
+    val stream: Int,
     val isDynamic: Boolean = false,
+    val isActive: Boolean,
     val level: Int = 0,
     val levelMin: Int = 0,
     val levelMax: Int = 0,
     val muted: Boolean = false,
     val muteSupported: Boolean = false,
-    @IntegerRes val name: Int = 0,
+    @StringRes val name: Int = 0,
     val remoteLabel: String? = null,
     val routedToBluetooth: Boolean = false,
 ) {
     constructor(
-        legacyState: VolumeDialogController.StreamState
+        stream: Int,
+        isActive: Boolean,
+        legacyState: VolumeDialogController.StreamState,
     ) : this(
+        stream = stream,
+        isActive = isActive,
         isDynamic = legacyState.dynamic,
         level = legacyState.level,
         levelMin = legacyState.levelMin,
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/domain/model/VolumeDialogVisibilityModel.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/shared/model/VolumeDialogVisibilityModel.kt
similarity index 65%
rename from packages/SystemUI/src/com/android/systemui/volume/dialog/domain/model/VolumeDialogVisibilityModel.kt
rename to packages/SystemUI/src/com/android/systemui/volume/dialog/shared/model/VolumeDialogVisibilityModel.kt
index 646445d..56a707d 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/dialog/domain/model/VolumeDialogVisibilityModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/shared/model/VolumeDialogVisibilityModel.kt
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.systemui.volume.dialog.domain.model
+package com.android.systemui.volume.dialog.shared.model
 
 /** Models current Volume Dialog visibility state. */
 sealed interface VolumeDialogVisibilityModel {
@@ -30,19 +30,4 @@
 
     /** Dialog has been shown and then dismissed. */
     data class Dismissed(val reason: Int) : Invisible
-
-    companion object {
-
-        /**
-         * Creates [VolumeDialogVisibilityModel] from appropriate events and returns null otherwise.
-         */
-        fun fromEvent(event: VolumeDialogEventModel): VolumeDialogVisibilityModel? {
-            return when (event) {
-                is VolumeDialogEventModel.DismissRequested -> Dismissed(event.reason)
-                is VolumeDialogEventModel.ShowRequested ->
-                    Visible(event.reason, event.keyguardLocked, event.lockTaskModeState)
-                else -> null
-            }
-        }
-    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/domain/interactor/VolumeDialogSliderInteractor.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/domain/interactor/VolumeDialogSliderInteractor.kt
new file mode 100644
index 0000000..f78a8dc
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/domain/interactor/VolumeDialogSliderInteractor.kt
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.volume.dialog.sliders.domain.interactor
+
+import com.android.systemui.plugins.VolumeDialogController
+import com.android.systemui.volume.dialog.dagger.scope.VolumeDialogScope
+import com.android.systemui.volume.dialog.domain.interactor.VolumeDialogStateInteractor
+import com.android.systemui.volume.dialog.shared.model.VolumeDialogStreamModel
+import com.android.systemui.volume.dialog.sliders.domain.model.VolumeDialogSliderType
+import dagger.assisted.Assisted
+import dagger.assisted.AssistedFactory
+import dagger.assisted.AssistedInject
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.mapNotNull
+
+/** Operates a state of particular slider of the Volume Dialog. */
+class VolumeDialogSliderInteractor
+@AssistedInject
+constructor(
+    @Assisted private val sliderType: VolumeDialogSliderType,
+    volumeDialogStateInteractor: VolumeDialogStateInteractor,
+    private val volumeDialogController: VolumeDialogController,
+) {
+
+    val slider: Flow<VolumeDialogStreamModel> =
+        volumeDialogStateInteractor.volumeDialogState.mapNotNull {
+            it.streamModels[sliderType.audioStream]
+        }
+
+    fun setStreamVolume(userLevel: Int) {
+        volumeDialogController.setStreamVolume(sliderType.audioStream, userLevel)
+    }
+
+    @VolumeDialogScope
+    @AssistedFactory
+    interface Factory {
+
+        fun create(sliderType: VolumeDialogSliderType): VolumeDialogSliderInteractor
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/domain/interactor/VolumeDialogSlidersInteractor.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/domain/interactor/VolumeDialogSlidersInteractor.kt
new file mode 100644
index 0000000..7af4258
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/domain/interactor/VolumeDialogSlidersInteractor.kt
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.volume.dialog.sliders.domain.interactor
+
+import android.content.pm.PackageManager
+import android.media.AudioManager
+import android.media.AudioSystem
+import com.android.settingslib.flags.Flags
+import com.android.systemui.volume.VolumeDialogControllerImpl
+import com.android.systemui.volume.dialog.dagger.scope.VolumeDialog
+import com.android.systemui.volume.dialog.dagger.scope.VolumeDialogScope
+import com.android.systemui.volume.dialog.domain.interactor.VolumeDialogStateInteractor
+import com.android.systemui.volume.dialog.shared.model.VolumeDialogStateModel
+import com.android.systemui.volume.dialog.shared.model.VolumeDialogStreamModel
+import com.android.systemui.volume.dialog.sliders.domain.model.VolumeDialogSliderType
+import com.android.systemui.volume.dialog.sliders.domain.model.VolumeDialogSlidersModel
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.filter
+import kotlinx.coroutines.flow.filterNotNull
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.stateIn
+
+private const val DEFAULT_STREAM = AudioManager.STREAM_MUSIC
+
+/** Provides a state for the Sliders section of the Volume Dialog. */
+@VolumeDialogScope
+class VolumeDialogSlidersInteractor
+@Inject
+constructor(
+    volumeDialogStateInteractor: VolumeDialogStateInteractor,
+    private val packageManager: PackageManager,
+    @VolumeDialog private val coroutineScope: CoroutineScope,
+) {
+
+    private val streamsSorter = StreamsSorter()
+    val sliders: Flow<VolumeDialogSlidersModel> =
+        volumeDialogStateInteractor.volumeDialogState
+            .filter { it.streamModels.isNotEmpty() }
+            .map { stateModel ->
+                stateModel.streamModels.values
+                    .filter { streamModel -> shouldShowSliders(stateModel, streamModel) }
+                    .sortedWith(streamsSorter)
+            }
+            .map { models ->
+                val sliderTypes: List<VolumeDialogSliderType> =
+                    models.map { model -> model.toType() }
+                VolumeDialogSlidersModel(
+                    slider = sliderTypes.first(),
+                    floatingSliders = sliderTypes.drop(1),
+                )
+            }
+            .stateIn(coroutineScope, SharingStarted.Eagerly, null)
+            .filterNotNull()
+
+    private fun shouldShowSliders(
+        stateModel: VolumeDialogStateModel,
+        streamModel: VolumeDialogStreamModel,
+    ): Boolean {
+        if (streamModel.isActive) {
+            return true
+        }
+
+        if (!packageManager.isTv()) {
+            if (streamModel.stream == AudioSystem.STREAM_ACCESSIBILITY) {
+                return stateModel.shouldShowA11ySlider
+            }
+
+            // Always show the stream for audio sharing if it exists.
+            if (
+                Flags.volumeDialogAudioSharingFix() &&
+                    streamModel.stream == VolumeDialogControllerImpl.DYNAMIC_STREAM_BROADCAST
+            ) {
+                return true
+            }
+
+            return streamModel.stream == DEFAULT_STREAM || streamModel.isDynamic
+        }
+
+        return false
+    }
+
+    private fun VolumeDialogStreamModel.toType(): VolumeDialogSliderType {
+        return when {
+            stream == VolumeDialogControllerImpl.DYNAMIC_STREAM_BROADCAST ->
+                VolumeDialogSliderType.AudioSharingStream(stream)
+            stream >= VolumeDialogControllerImpl.DYNAMIC_STREAM_REMOTE_START_INDEX ->
+                VolumeDialogSliderType.RemoteMediaStream(stream)
+            else -> VolumeDialogSliderType.Stream(stream)
+        }
+    }
+
+    private class StreamsSorter : Comparator<VolumeDialogStreamModel> {
+
+        /**
+         * This list reflects the order of the sorted collection. Elements that satisfy predicates
+         * at the beginning of this list will be earlier in the sorted collection.
+         */
+        private val priorityPredicates: List<(VolumeDialogStreamModel) -> Boolean> =
+            listOf(
+                { it.isActive },
+                { it.stream == AudioManager.STREAM_MUSIC },
+                { it.stream == AudioManager.STREAM_ACCESSIBILITY },
+                { it.stream == AudioManager.STREAM_RING },
+                { it.stream == AudioManager.STREAM_NOTIFICATION },
+                { it.stream == AudioManager.STREAM_VOICE_CALL },
+                { it.stream == AudioManager.STREAM_SYSTEM },
+                { it.isDynamic },
+            )
+
+        override fun compare(lhs: VolumeDialogStreamModel, rhs: VolumeDialogStreamModel): Int {
+            return lhs.getPriority() - rhs.getPriority()
+        }
+
+        private fun VolumeDialogStreamModel.getPriority(): Int {
+            val index = priorityPredicates.indexOfFirst { it(this) }
+            return if (index >= 0) {
+                index
+            } else {
+                stream
+            }
+        }
+    }
+}
+
+private fun PackageManager.isTv(): Boolean = hasSystemFeature(PackageManager.FEATURE_LEANBACK)
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/domain/model/VolumeDialogSliderType.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/domain/model/VolumeDialogSliderType.kt
new file mode 100644
index 0000000..605b54a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/domain/model/VolumeDialogSliderType.kt
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.volume.dialog.sliders.domain.model
+
+/** Models different possible audio sliders shown in the Volume Dialog. */
+sealed interface VolumeDialogSliderType {
+
+    // VolumeDialogController uses the same model for every slider type. We need to follow the same
+    // logic until we refactor and decouple data and domain layers from the VolumeDialogController
+    // into separated interactors.
+    val audioStream: Int
+
+    data class Stream(override val audioStream: Int) : VolumeDialogSliderType
+
+    data class RemoteMediaStream(override val audioStream: Int) : VolumeDialogSliderType
+
+    data class AudioSharingStream(override val audioStream: Int) : VolumeDialogSliderType
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/data/repository/FixedColumnsRepositoryKosmos.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/domain/model/VolumeDialogSlidersModel.kt
similarity index 69%
copy from packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/data/repository/FixedColumnsRepositoryKosmos.kt
copy to packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/domain/model/VolumeDialogSlidersModel.kt
index 2f5daaa..91a3328 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/data/repository/FixedColumnsRepositoryKosmos.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/domain/model/VolumeDialogSlidersModel.kt
@@ -14,8 +14,10 @@
  * limitations under the License.
  */
 
-package com.android.systemui.qs.panels.data.repository
+package com.android.systemui.volume.dialog.sliders.domain.model
 
-import com.android.systemui.kosmos.Kosmos
-
-val Kosmos.fixedColumnsRepository by Kosmos.Fixture { FixedColumnsRepository() }
+/** Models a state of the sliders section of the Volume Dialog. */
+data class VolumeDialogSlidersModel(
+    val slider: VolumeDialogSliderType,
+    val floatingSliders: List<VolumeDialogSliderType>,
+)
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/VolumeDialogSliderViewBinder.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/VolumeDialogSliderViewBinder.kt
new file mode 100644
index 0000000..25a5f28
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/VolumeDialogSliderViewBinder.kt
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.volume.dialog.sliders.ui
+
+import android.view.View
+import androidx.lifecycle.viewmodel.compose.viewModel
+import com.android.systemui.lifecycle.WindowLifecycleState
+import com.android.systemui.lifecycle.repeatWhenAttached
+import com.android.systemui.lifecycle.setSnapshotBinding
+import com.android.systemui.lifecycle.viewModel
+import com.android.systemui.volume.dialog.dagger.scope.VolumeDialogScope
+import com.android.systemui.volume.dialog.sliders.ui.viewmodel.VolumeDialogSliderViewModel
+import dagger.assisted.Assisted
+import dagger.assisted.AssistedFactory
+import dagger.assisted.AssistedInject
+import kotlinx.coroutines.awaitCancellation
+
+class VolumeDialogSliderViewBinder
+@AssistedInject
+constructor(@Assisted private val viewModelProvider: () -> VolumeDialogSliderViewModel) {
+
+    fun bind(view: View) {
+        with(view) {
+            repeatWhenAttached {
+                viewModel(
+                    traceName = "VolumeDialogSliderViewBinder",
+                    minWindowLifecycleState = WindowLifecycleState.ATTACHED,
+                    factory = { viewModelProvider() },
+                ) { viewModel ->
+                    setSnapshotBinding {}
+
+                    awaitCancellation()
+                }
+            }
+        }
+    }
+
+    @AssistedFactory
+    @VolumeDialogScope
+    interface Factory {
+
+        fun create(
+            viewModelProvider: () -> VolumeDialogSliderViewModel
+        ): VolumeDialogSliderViewBinder
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/VolumeDialogSlidersViewBinder.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/VolumeDialogSlidersViewBinder.kt
new file mode 100644
index 0000000..0a00f70
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/VolumeDialogSlidersViewBinder.kt
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.volume.dialog.sliders.ui
+
+import android.view.View
+import com.android.systemui.lifecycle.WindowLifecycleState
+import com.android.systemui.lifecycle.repeatWhenAttached
+import com.android.systemui.lifecycle.setSnapshotBinding
+import com.android.systemui.lifecycle.viewModel
+import com.android.systemui.volume.dialog.dagger.scope.VolumeDialogScope
+import com.android.systemui.volume.dialog.sliders.ui.viewmodel.VolumeDialogSlidersViewModel
+import javax.inject.Inject
+import kotlinx.coroutines.awaitCancellation
+
+@VolumeDialogScope
+class VolumeDialogSlidersViewBinder
+@Inject
+constructor(private val viewModelFactory: VolumeDialogSlidersViewModel.Factory) {
+
+    fun bind(view: View) {
+        with(view) {
+            repeatWhenAttached {
+                viewModel(
+                    traceName = "VolumeDialogSlidersViewBinder",
+                    minWindowLifecycleState = WindowLifecycleState.ATTACHED,
+                    factory = { viewModelFactory.create() },
+                ) { viewModel ->
+                    setSnapshotBinding {}
+
+                    awaitCancellation()
+                }
+            }
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/viewmodel/VolumeDialogSliderViewModel.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/viewmodel/VolumeDialogSliderViewModel.kt
new file mode 100644
index 0000000..7ee722d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/viewmodel/VolumeDialogSliderViewModel.kt
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.volume.dialog.sliders.ui.viewmodel
+
+import com.android.systemui.volume.dialog.shared.model.VolumeDialogStreamModel
+import com.android.systemui.volume.dialog.sliders.domain.interactor.VolumeDialogSliderInteractor
+import dagger.assisted.Assisted
+import dagger.assisted.AssistedFactory
+import dagger.assisted.AssistedInject
+import kotlinx.coroutines.flow.Flow
+
+class VolumeDialogSliderViewModel
+@AssistedInject
+constructor(@Assisted private val interactor: VolumeDialogSliderInteractor) {
+
+    val model: Flow<VolumeDialogStreamModel> = interactor.slider
+
+    fun setStreamVolume(volume: Int) {
+        interactor.setStreamVolume(volume)
+    }
+
+    @AssistedFactory
+    interface Factory {
+
+        fun create(interactor: VolumeDialogSliderInteractor): VolumeDialogSliderViewModel
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/viewmodel/VolumeDialogSlidersViewModel.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/viewmodel/VolumeDialogSlidersViewModel.kt
new file mode 100644
index 0000000..b5b292f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/viewmodel/VolumeDialogSlidersViewModel.kt
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.volume.dialog.sliders.ui.viewmodel
+
+import com.android.systemui.volume.dialog.dagger.scope.VolumeDialog
+import com.android.systemui.volume.dialog.sliders.domain.interactor.VolumeDialogSliderInteractor
+import com.android.systemui.volume.dialog.sliders.domain.interactor.VolumeDialogSlidersInteractor
+import com.android.systemui.volume.dialog.sliders.domain.model.VolumeDialogSliderType
+import com.android.systemui.volume.dialog.sliders.ui.VolumeDialogSliderViewBinder
+import dagger.assisted.AssistedFactory
+import dagger.assisted.AssistedInject
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.filterNotNull
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.stateIn
+
+class VolumeDialogSlidersViewModel
+@AssistedInject
+constructor(
+    @VolumeDialog coroutineScope: CoroutineScope,
+    private val slidersInteractor: VolumeDialogSlidersInteractor,
+    private val sliderInteractorFactory: VolumeDialogSliderInteractor.Factory,
+    private val sliderViewModelFactory: VolumeDialogSliderViewModel.Factory,
+    private val sliderViewBinderFactory: VolumeDialogSliderViewBinder.Factory,
+) {
+
+    val sliders: Flow<VolumeDialogSliderUiModel> =
+        slidersInteractor.sliders
+            .distinctUntilChanged()
+            .map { slidersModel ->
+                VolumeDialogSliderUiModel(
+                    sliderViewBinder = createSliderViewBinder(slidersModel.slider),
+                    floatingSliderViewBinders =
+                        slidersModel.floatingSliders.map(::createSliderViewBinder),
+                )
+            }
+            .stateIn(coroutineScope, SharingStarted.Eagerly, null)
+            .filterNotNull()
+
+    private fun createSliderViewBinder(type: VolumeDialogSliderType): VolumeDialogSliderViewBinder =
+        sliderViewBinderFactory.create {
+            sliderViewModelFactory.create(sliderInteractorFactory.create(type))
+        }
+
+    @AssistedFactory
+    interface Factory {
+
+        fun create(): VolumeDialogSlidersViewModel
+    }
+}
+
+/** Models slider ui */
+data class VolumeDialogSliderUiModel(
+    val sliderViewBinder: VolumeDialogSliderViewBinder,
+    val floatingSliderViewBinders: List<VolumeDialogSliderViewBinder>,
+)
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/binder/VolumeDialogBinder.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/binder/VolumeDialogBinder.kt
index 3f2c39b..77733fe 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/binder/VolumeDialogBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/binder/VolumeDialogBinder.kt
@@ -20,28 +20,27 @@
 import android.graphics.Color
 import android.graphics.PixelFormat
 import android.graphics.drawable.ColorDrawable
-import android.view.View
 import android.view.ViewGroup
 import android.view.Window
 import android.view.WindowManager
-import androidx.lifecycle.lifecycleScope
-import com.android.systemui.lifecycle.repeatWhenAttached
 import com.android.systemui.res.R
 import com.android.systemui.volume.dialog.dagger.scope.VolumeDialog
 import com.android.systemui.volume.dialog.dagger.scope.VolumeDialogScope
+import com.android.systemui.volume.dialog.settings.ui.binder.VolumeDialogSettingsButtonViewBinder
 import com.android.systemui.volume.dialog.ui.viewmodel.VolumeDialogGravityViewModel
 import javax.inject.Inject
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.flow.launchIn
 import kotlinx.coroutines.flow.onEach
-import kotlinx.coroutines.launch
 
+/** Binds the Volume Dialog itself. */
 @VolumeDialogScope
 class VolumeDialogBinder
 @Inject
 constructor(
     @VolumeDialog private val coroutineScope: CoroutineScope,
     private val volumeDialogViewBinder: VolumeDialogViewBinder,
+    private val settingsButtonViewBinder: VolumeDialogSettingsButtonViewBinder,
     private val gravityViewModel: VolumeDialogGravityViewModel,
 ) {
 
@@ -49,11 +48,13 @@
         with(dialog) {
             setupWindow(window!!)
             dialog.setContentView(R.layout.volume_dialog)
+            dialog.setCanceledOnTouchOutside(true)
 
-            val volumeDialogView: View = dialog.requireViewById(R.id.volume_dialog_container)
-            volumeDialogView.repeatWhenAttached {
-                lifecycleScope.launch { volumeDialogViewBinder.bind(volumeDialogView) }
-            }
+            settingsButtonViewBinder.bind(dialog.requireViewById(R.id.volume_dialog_settings))
+            volumeDialogViewBinder.bind(
+                dialog,
+                dialog.requireViewById(R.id.volume_dialog_container),
+            )
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/binder/VolumeDialogViewBinder.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/binder/VolumeDialogViewBinder.kt
index 700225d..23e6eac 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/binder/VolumeDialogViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/binder/VolumeDialogViewBinder.kt
@@ -16,30 +16,144 @@
 
 package com.android.systemui.volume.dialog.ui.binder
 
+import android.app.Dialog
+import android.view.Gravity
 import android.view.View
+import com.android.internal.view.RotationPolicy
 import com.android.systemui.lifecycle.WindowLifecycleState
 import com.android.systemui.lifecycle.repeatWhenAttached
-import com.android.systemui.lifecycle.setSnapshotBinding
 import com.android.systemui.lifecycle.viewModel
+import com.android.systemui.volume.SystemUIInterpolators
+import com.android.systemui.volume.dialog.dagger.scope.VolumeDialogScope
+import com.android.systemui.volume.dialog.shared.model.VolumeDialogVisibilityModel
+import com.android.systemui.volume.dialog.ui.utils.JankListenerFactory
+import com.android.systemui.volume.dialog.ui.utils.suspendAnimate
+import com.android.systemui.volume.dialog.ui.viewmodel.VolumeDialogGravityViewModel
+import com.android.systemui.volume.dialog.ui.viewmodel.VolumeDialogResourcesViewModel
 import com.android.systemui.volume.dialog.ui.viewmodel.VolumeDialogViewModel
+import com.android.systemui.volume.dialog.utils.VolumeTracer
 import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.awaitCancellation
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.first
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.mapLatest
 
+/** Binds the root view of the Volume Dialog. */
+@OptIn(ExperimentalCoroutinesApi::class)
+@VolumeDialogScope
 class VolumeDialogViewBinder
 @Inject
-constructor(private val volumeDialogViewModelFactory: VolumeDialogViewModel.Factory) {
+constructor(
+    private val volumeResources: VolumeDialogResourcesViewModel,
+    private val gravityViewModel: VolumeDialogGravityViewModel,
+    private val viewModelFactory: VolumeDialogViewModel.Factory,
+    private val jankListenerFactory: JankListenerFactory,
+    private val tracer: VolumeTracer,
+) {
 
-    suspend fun bind(view: View) {
+    fun bind(dialog: Dialog, view: View) {
+        view.alpha = 0f
         view.repeatWhenAttached {
             view.viewModel(
                 traceName = "VolumeDialogViewBinder",
                 minWindowLifecycleState = WindowLifecycleState.ATTACHED,
-                factory = { volumeDialogViewModelFactory.create() },
+                factory = { viewModelFactory.create() },
             ) { viewModel ->
-                view.setSnapshotBinding {}
+                animateVisibility(view, dialog, viewModel.dialogVisibilityModel)
 
                 awaitCancellation()
             }
         }
     }
+
+    private fun CoroutineScope.animateVisibility(
+        view: View,
+        dialog: Dialog,
+        visibilityModel: Flow<VolumeDialogVisibilityModel>,
+    ) {
+        visibilityModel
+            .mapLatest {
+                when (it) {
+                    is VolumeDialogVisibilityModel.Visible -> {
+                        tracer.traceVisibilityEnd(it)
+                        calculateTranslationX(view)?.let(view::setTranslationX)
+                        view.animateShow(volumeResources.dialogShowDurationMillis.first())
+                    }
+                    is VolumeDialogVisibilityModel.Dismissed -> {
+                        tracer.traceVisibilityEnd(it)
+                        view.animateHide(
+                            duration = volumeResources.dialogHideDurationMillis.first(),
+                            translationX = calculateTranslationX(view),
+                        )
+                        dialog.dismiss()
+                    }
+                    is VolumeDialogVisibilityModel.Invisible -> {
+                        // do nothing
+                    }
+                }
+            }
+            .launchIn(this)
+    }
+
+    private suspend fun calculateTranslationX(view: View): Float? {
+        return if (view.display.rotation == RotationPolicy.NATURAL_ROTATION) {
+            val dialogGravity = gravityViewModel.dialogGravity.first()
+            val isGravityLeft = (dialogGravity and Gravity.LEFT) == Gravity.LEFT
+            if (isGravityLeft) {
+                -1
+            } else {
+                1
+            } * view.width / 2.0f
+        } else {
+            null
+        }
+    }
+
+    private suspend fun View.animateShow(duration: Long) {
+        animate()
+            .alpha(1f)
+            .translationX(0f)
+            .setDuration(duration)
+            .setInterpolator(SystemUIInterpolators.LogDecelerateInterpolator())
+            .suspendAnimate(jankListenerFactory.show(this, duration))
+        /* TODO(b/369993851)
+        .withEndAction(Runnable {
+            if (!Prefs.getBoolean(mContext, Prefs.Key.TOUCHED_RINGER_TOGGLE, false)) {
+                if (mRingerIcon != null) {
+                    mRingerIcon.postOnAnimationDelayed(
+                        getSinglePressFor(mRingerIcon), 1500
+                    )
+                }
+            }
+        })
+         */
+    }
+
+    private suspend fun View.animateHide(duration: Long, translationX: Float?) {
+        val animator =
+            animate()
+                .alpha(0f)
+                .setDuration(duration)
+                .setInterpolator(SystemUIInterpolators.LogAccelerateInterpolator())
+        /*  TODO(b/369993851)
+        .withEndAction(
+            Runnable {
+                mHandler.postDelayed(
+                    Runnable {
+                        hideRingerDrawer()
+
+                    },
+                    50
+                )
+            }
+        )
+         */
+        if (translationX != null) {
+            animator.translationX(translationX)
+        }
+        animator.suspendAnimate(jankListenerFactory.dismiss(this, duration))
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/utils/JankListenerFactory.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/utils/JankListenerFactory.kt
new file mode 100644
index 0000000..9fcd777
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/utils/JankListenerFactory.kt
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.volume.dialog.ui.utils
+
+import android.animation.Animator
+import android.animation.AnimatorListenerAdapter
+import android.view.View
+import com.android.internal.jank.Cuj
+import com.android.internal.jank.InteractionJankMonitor
+import com.android.systemui.volume.dialog.dagger.scope.VolumeDialogPluginScope
+import javax.inject.Inject
+
+/** Provides [Animator.AnimatorListener] to measure Volume CUJ Jank */
+@VolumeDialogPluginScope
+class JankListenerFactory
+@Inject
+constructor(private val interactionJankMonitor: InteractionJankMonitor) {
+
+    fun show(view: View, timeout: Long) = getJunkListener(view, "show", timeout)
+
+    fun update(view: View, timeout: Long) = getJunkListener(view, "update", timeout)
+
+    fun dismiss(view: View, timeout: Long) = getJunkListener(view, "dismiss", timeout)
+
+    private fun getJunkListener(
+        view: View,
+        type: String,
+        timeout: Long,
+    ): Animator.AnimatorListener {
+        return object : AnimatorListenerAdapter() {
+            override fun onAnimationStart(animation: Animator) {
+                interactionJankMonitor.begin(
+                    InteractionJankMonitor.Configuration.Builder.withView(
+                            Cuj.CUJ_VOLUME_CONTROL,
+                            view,
+                        )
+                        .setTag(type)
+                        .setTimeout(timeout)
+                )
+            }
+
+            override fun onAnimationEnd(animation: Animator) {
+                interactionJankMonitor.end(Cuj.CUJ_VOLUME_CONTROL)
+            }
+
+            override fun onAnimationCancel(animation: Animator) {
+                interactionJankMonitor.cancel(Cuj.CUJ_VOLUME_CONTROL)
+            }
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/utils/SuspendAnimators.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/utils/SuspendAnimators.kt
new file mode 100644
index 0000000..4eae3b9a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/utils/SuspendAnimators.kt
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.volume.dialog.ui.utils
+
+import android.animation.Animator
+import android.view.ViewPropertyAnimator
+import kotlin.coroutines.resume
+import kotlinx.coroutines.suspendCancellableCoroutine
+
+/**
+ * Starts animation and suspends until it's finished. Cancels the animation if the running coroutine
+ * is cancelled.
+ *
+ * Careful! This method overrides [ViewPropertyAnimator.setListener]. Use [animationListener]
+ * instead.
+ */
+suspend fun ViewPropertyAnimator.suspendAnimate(
+    animationListener: Animator.AnimatorListener? = null
+) = suspendCancellableCoroutine { continuation ->
+    start()
+    setListener(
+        object : Animator.AnimatorListener {
+            override fun onAnimationStart(animation: Animator) {
+                animationListener?.onAnimationStart(animation)
+            }
+
+            override fun onAnimationEnd(animation: Animator) {
+                continuation.resume(Unit)
+                animationListener?.onAnimationEnd(animation)
+            }
+
+            override fun onAnimationCancel(animation: Animator) {
+                animationListener?.onAnimationCancel(animation)
+            }
+
+            override fun onAnimationRepeat(animation: Animator) {
+                animationListener?.onAnimationRepeat(animation)
+            }
+        }
+    )
+    continuation.invokeOnCancellation { this.cancel() }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/viewmodel/VolumeDialogGravityViewModel.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/viewmodel/VolumeDialogGravityViewModel.kt
index df6523c..112afb1 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/viewmodel/VolumeDialogGravityViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/viewmodel/VolumeDialogGravityViewModel.kt
@@ -39,6 +39,7 @@
 import kotlinx.coroutines.flow.stateIn
 import kotlinx.coroutines.withContext
 
+/** Exposes dialog [GravityInt] for use in the UI layer. */
 @VolumeDialogScope
 class VolumeDialogGravityViewModel
 @Inject
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/viewmodel/VolumeDialogPluginViewModel.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/viewmodel/VolumeDialogPluginViewModel.kt
index 329a947..f336d46 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/viewmodel/VolumeDialogPluginViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/viewmodel/VolumeDialogPluginViewModel.kt
@@ -16,15 +16,14 @@
 
 package com.android.systemui.volume.dialog.ui.viewmodel
 
-import android.app.Dialog
 import com.android.systemui.lifecycle.ExclusiveActivatable
 import com.android.systemui.plugins.VolumeDialogController
 import com.android.systemui.volume.Events
 import com.android.systemui.volume.dialog.dagger.VolumeDialogComponent
 import com.android.systemui.volume.dialog.dagger.scope.VolumeDialogPluginScope
 import com.android.systemui.volume.dialog.domain.interactor.VolumeDialogVisibilityInteractor
-import com.android.systemui.volume.dialog.domain.model.VolumeDialogVisibilityModel
 import com.android.systemui.volume.dialog.shared.VolumeDialogLogger
+import com.android.systemui.volume.dialog.shared.model.VolumeDialogVisibilityModel
 import javax.inject.Inject
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.awaitCancellation
@@ -32,8 +31,7 @@
 import kotlinx.coroutines.coroutineScope
 import kotlinx.coroutines.flow.launchIn
 import kotlinx.coroutines.flow.mapLatest
-import kotlinx.coroutines.launch
-import kotlinx.coroutines.suspendCancellableCoroutine
+import kotlinx.coroutines.flow.onEach
 
 @OptIn(ExperimentalCoroutinesApi::class)
 @VolumeDialogPluginScope
@@ -49,10 +47,11 @@
     override suspend fun onActivated(): Nothing {
         coroutineScope {
             dialogVisibilityInteractor.dialogVisibility
+                .onEach { controller.notifyVisible(it is VolumeDialogVisibilityModel.Visible) }
                 .mapLatest { visibilityModel ->
                     with(visibilityModel) {
                         if (this is VolumeDialogVisibilityModel.Visible) {
-                            showDialog(reason, keyguardLocked, lockTaskModeState)
+                            showDialog(reason, keyguardLocked)
                         }
                         if (this is VolumeDialogVisibilityModel.Dismissed) {
                             Events.writeEvent(Events.EVENT_DISMISS_DIALOG, reason)
@@ -65,29 +64,21 @@
         awaitCancellation()
     }
 
-    suspend fun showDialog(reason: Int, keyguardLocked: Boolean, lockTaskModeState: Int): Unit =
-        coroutineScope {
-            logger.onShow(reason)
+    suspend fun showDialog(reason: Int, keyguardLocked: Boolean): Unit = coroutineScope {
+        logger.onShow(reason)
 
-            controller.notifyVisible(true)
+        controller.notifyVisible(true)
 
-            val volumeDialogComponent: VolumeDialogComponent = componentFactory.create(this)
-            val dialog =
-                volumeDialogComponent.volumeDialog().apply {
-                    setOnDismissListener {
-                        volumeDialogComponent.coroutineScope().cancel()
-                        dialogVisibilityInteractor.dismissDialog(Events.DISMISS_REASON_UNKNOWN)
-                    }
+        val volumeDialogComponent: VolumeDialogComponent = componentFactory.create(this)
+        val dialog =
+            volumeDialogComponent.volumeDialog().apply {
+                setOnDismissListener {
+                    volumeDialogComponent.coroutineScope().cancel()
+                    dialogVisibilityInteractor.dismissDialog(Events.DISMISS_REASON_UNKNOWN)
                 }
-            launch { dialog.awaitShow() }
+            }
+        dialog.show()
 
-            Events.writeEvent(Events.EVENT_SHOW_DIALOG, reason, keyguardLocked)
-        }
-}
-
-/** Shows [Dialog] until suspend function is cancelled. */
-private suspend fun Dialog.awaitShow() =
-    suspendCancellableCoroutine<Unit> {
-        show()
-        it.invokeOnCancellation { dismiss() }
+        Events.writeEvent(Events.EVENT_SHOW_DIALOG, reason, keyguardLocked)
     }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/viewmodel/VolumeDialogResourcesViewModel.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/viewmodel/VolumeDialogResourcesViewModel.kt
new file mode 100644
index 0000000..da9be98
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/viewmodel/VolumeDialogResourcesViewModel.kt
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.volume.dialog.ui.viewmodel
+
+import android.content.Context
+import android.content.res.Resources
+import com.android.systemui.dagger.qualifiers.UiBackground
+import com.android.systemui.res.R
+import com.android.systemui.statusbar.policy.ConfigurationController
+import com.android.systemui.statusbar.policy.onConfigChanged
+import com.android.systemui.volume.dialog.dagger.scope.VolumeDialog
+import com.android.systemui.volume.dialog.dagger.scope.VolumeDialogScope
+import javax.inject.Inject
+import kotlin.coroutines.CoroutineContext
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.filterNotNull
+import kotlinx.coroutines.flow.flowOn
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.onStart
+import kotlinx.coroutines.flow.stateIn
+
+/**
+ * Provides cached resources [Flow]s that update when the configuration changes.
+ *
+ * Consume or use [kotlinx.coroutines.flow.first] to get the value.
+ */
+@VolumeDialogScope
+class VolumeDialogResourcesViewModel
+@Inject
+constructor(
+    @VolumeDialog private val coroutineScope: CoroutineScope,
+    @UiBackground private val uiBackgroundContext: CoroutineContext,
+    private val context: Context,
+    private val configurationController: ConfigurationController,
+) {
+
+    val dialogShowDurationMillis: Flow<Long> = configurationResource {
+        getInteger(R.integer.config_dialogShowAnimationDurationMs).toLong()
+    }
+
+    val dialogHideDurationMillis: Flow<Long> = configurationResource {
+        getInteger(R.integer.config_dialogHideAnimationDurationMs).toLong()
+    }
+
+    private fun <T> configurationResource(get: Resources.() -> T): Flow<T> =
+        configurationController.onConfigChanged
+            .map { context.resources.get() }
+            .onStart { emit(context.resources.get()) }
+            .flowOn(uiBackgroundContext)
+            .stateIn(coroutineScope, SharingStarted.Eagerly, null)
+            .filterNotNull()
+}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/viewmodel/VolumeDialogViewModel.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/viewmodel/VolumeDialogViewModel.kt
index 30c8c15..84c837c 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/viewmodel/VolumeDialogViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/viewmodel/VolumeDialogViewModel.kt
@@ -17,11 +17,20 @@
 package com.android.systemui.volume.dialog.ui.viewmodel
 
 import com.android.systemui.lifecycle.ExclusiveActivatable
+import com.android.systemui.volume.dialog.domain.interactor.VolumeDialogVisibilityInteractor
+import com.android.systemui.volume.dialog.shared.model.VolumeDialogVisibilityModel
 import dagger.assisted.AssistedFactory
 import dagger.assisted.AssistedInject
 import kotlinx.coroutines.awaitCancellation
+import kotlinx.coroutines.flow.Flow
 
-class VolumeDialogViewModel @AssistedInject constructor() : ExclusiveActivatable() {
+/** Provides a state for the Volume Dialog. */
+class VolumeDialogViewModel
+@AssistedInject
+constructor(dialogVisibilityInteractor: VolumeDialogVisibilityInteractor) : ExclusiveActivatable() {
+
+    val dialogVisibilityModel: Flow<VolumeDialogVisibilityModel> =
+        dialogVisibilityInteractor.dialogVisibility
 
     override suspend fun onActivated(): Nothing {
         awaitCancellation()
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/utils/VolumeTracer.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/utils/VolumeTracer.kt
new file mode 100644
index 0000000..db35ca7
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/utils/VolumeTracer.kt
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.volume.dialog.utils
+
+import android.os.Trace
+import com.android.systemui.volume.dialog.dagger.scope.VolumeDialogPluginScope
+import com.android.systemui.volume.dialog.shared.model.VolumeDialogVisibilityModel
+import javax.inject.Inject
+
+/** Traces the async sections for the Volume Dialog. */
+interface VolumeTracer {
+
+    fun traceVisibilityStart(model: VolumeDialogVisibilityModel)
+
+    fun traceVisibilityEnd(model: VolumeDialogVisibilityModel)
+}
+
+@VolumeDialogPluginScope
+class VolumeTracerImpl @Inject constructor() : VolumeTracer {
+
+    override fun traceVisibilityStart(model: VolumeDialogVisibilityModel) =
+        with(model) { Trace.beginAsyncSection(methodName, tracingCookie) }
+
+    override fun traceVisibilityEnd(model: VolumeDialogVisibilityModel) =
+        with(model) { Trace.endAsyncSection(methodName, tracingCookie) }
+
+    private val VolumeDialogVisibilityModel.tracingCookie
+        get() = this.hashCode()
+
+    private val VolumeDialogVisibilityModel.methodName
+        get() =
+            when (this) {
+                is VolumeDialogVisibilityModel.Visible -> "VolumeDialog#show"
+                is VolumeDialogVisibilityModel.Dismissed -> "VolumeDialog#dismiss"
+                is VolumeDialogVisibilityModel.Invisible -> error("Invisible is unsupported")
+            }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/MediaOutputComponentInteractor.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/MediaOutputComponentInteractor.kt
index f94cbda..609ba02 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/MediaOutputComponentInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/MediaOutputComponentInteractor.kt
@@ -16,7 +16,10 @@
 
 package com.android.systemui.volume.panel.component.mediaoutput.domain.interactor
 
+import com.android.settingslib.media.PhoneMediaDevice.inputRoutingEnabledAndIsDesktop
+import android.content.Context
 import com.android.settingslib.volume.domain.interactor.AudioModeInteractor
+import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.volume.domain.interactor.AudioOutputInteractor
 import com.android.systemui.volume.domain.interactor.AudioSharingInteractor
 import com.android.systemui.volume.domain.model.AudioOutputDevice
@@ -46,6 +49,7 @@
 class MediaOutputComponentInteractor
 @Inject
 constructor(
+    @Application private val context: Context,
     @VolumePanelScope private val coroutineScope: CoroutineScope,
     private val mediaDeviceSessionInteractor: MediaDeviceSessionInteractor,
     audioOutputInteractor: AudioOutputInteractor,
@@ -91,7 +95,8 @@
                         MediaOutputComponentModel.Calling(
                             device = currentAudioDevice,
                             isInAudioSharing = isInAudioSharing,
-                            canOpenAudioSwitcher = false,
+                            /* allow open switcher when input routing is enabled in desktop */
+                            canOpenAudioSwitcher = inputRoutingEnabledAndIsDesktop(context),
                         )
                     )
                 } else {
diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/AudioStreamSliderViewModel.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/AudioStreamSliderViewModel.kt
index ffb1f11..2aa1ac9 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/AudioStreamSliderViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/AudioStreamSliderViewModel.kt
@@ -18,6 +18,9 @@
 
 import android.content.Context
 import android.media.AudioManager
+import android.media.AudioManager.STREAM_ALARM
+import android.media.AudioManager.STREAM_MUSIC
+import android.media.AudioManager.STREAM_NOTIFICATION
 import android.util.Log
 import com.android.internal.logging.UiEventLogger
 import com.android.settingslib.volume.domain.interactor.AudioVolumeInteractor
@@ -25,7 +28,11 @@
 import com.android.settingslib.volume.shared.model.AudioStreamModel
 import com.android.settingslib.volume.shared.model.RingerMode
 import com.android.systemui.common.shared.model.Icon
+import com.android.systemui.modes.shared.ModesUiIcons
 import com.android.systemui.res.R
+import com.android.systemui.statusbar.policy.domain.interactor.ZenModeInteractor
+import com.android.systemui.statusbar.policy.domain.model.ActiveZenModes
+import com.android.systemui.util.kotlin.combine
 import com.android.systemui.volume.panel.shared.VolumePanelLogger
 import com.android.systemui.volume.panel.ui.VolumePanelUiEvent
 import dagger.assisted.Assisted
@@ -51,16 +58,14 @@
     @Assisted private val coroutineScope: CoroutineScope,
     private val context: Context,
     private val audioVolumeInteractor: AudioVolumeInteractor,
+    private val zenModeInteractor: ZenModeInteractor,
     private val uiEventLogger: UiEventLogger,
     private val volumePanelLogger: VolumePanelLogger,
 ) : SliderViewModel {
 
     private val volumeChanges = MutableStateFlow<Int?>(null)
     private val streamsAffectedByRing =
-        setOf(
-            AudioManager.STREAM_RING,
-            AudioManager.STREAM_NOTIFICATION,
-        )
+        setOf(AudioManager.STREAM_RING, AudioManager.STREAM_NOTIFICATION)
     private val audioStream = audioStreamWrapper.audioStream
     private val iconsByStream =
         mapOf(
@@ -78,11 +83,6 @@
             AudioStream(AudioManager.STREAM_NOTIFICATION) to R.string.stream_notification,
             AudioStream(AudioManager.STREAM_ALARM) to R.string.stream_alarm,
         )
-    private val disabledTextByStream =
-        mapOf(
-            AudioStream(AudioManager.STREAM_NOTIFICATION) to
-                R.string.stream_notification_unavailable,
-        )
     private val uiEventByStream =
         mapOf(
             AudioStream(AudioManager.STREAM_MUSIC) to
@@ -98,15 +98,48 @@
         )
 
     override val slider: StateFlow<SliderState> =
-        combine(
-                audioVolumeInteractor.getAudioStream(audioStream),
-                audioVolumeInteractor.canChangeVolume(audioStream),
-                audioVolumeInteractor.ringerMode,
-            ) { model, isEnabled, ringerMode ->
-                volumePanelLogger.onVolumeUpdateReceived(audioStream, model.volume)
-                model.toState(isEnabled, ringerMode)
-            }
-            .stateIn(coroutineScope, SharingStarted.Eagerly, SliderState.Empty)
+        if (ModesUiIcons.isEnabled) {
+            combine(
+                    audioVolumeInteractor.getAudioStream(audioStream),
+                    audioVolumeInteractor.canChangeVolume(audioStream),
+                    audioVolumeInteractor.ringerMode,
+                    zenModeInteractor.activeModesBlockingEverything,
+                    zenModeInteractor.activeModesBlockingAlarms,
+                    zenModeInteractor.activeModesBlockingMedia,
+                ) {
+                    model,
+                    isEnabled,
+                    ringerMode,
+                    modesBlockingEverything,
+                    modesBlockingAlarms,
+                    modesBlockingMedia ->
+                    volumePanelLogger.onVolumeUpdateReceived(audioStream, model.volume)
+                    model.toState(
+                        isEnabled,
+                        ringerMode,
+                        getStreamDisabledMessage(
+                            modesBlockingEverything,
+                            modesBlockingAlarms,
+                            modesBlockingMedia,
+                        ),
+                    )
+                }
+                .stateIn(coroutineScope, SharingStarted.Eagerly, SliderState.Empty)
+        } else {
+            combine(
+                    audioVolumeInteractor.getAudioStream(audioStream),
+                    audioVolumeInteractor.canChangeVolume(audioStream),
+                    audioVolumeInteractor.ringerMode,
+                ) { model, isEnabled, ringerMode ->
+                    volumePanelLogger.onVolumeUpdateReceived(audioStream, model.volume)
+                    model.toState(
+                        isEnabled,
+                        ringerMode,
+                        getStreamDisabledMessageWithoutModes(audioStream),
+                    )
+                }
+                .stateIn(coroutineScope, SharingStarted.Eagerly, SliderState.Empty)
+        }
 
     init {
         volumeChanges
@@ -139,6 +172,7 @@
     private fun AudioStreamModel.toState(
         isEnabled: Boolean,
         ringerMode: RingerMode,
+        disabledMessage: String?,
     ): State {
         val label =
             labelsByStream[audioStream]?.let(context::getString)
@@ -148,13 +182,7 @@
             valueRange = volumeRange.first.toFloat()..volumeRange.last.toFloat(),
             icon = getIcon(ringerMode),
             label = label,
-            disabledMessage =
-                context.getString(
-                    disabledTextByStream.getOrDefault(
-                        audioStream,
-                        R.string.stream_alarm_unavailable,
-                    )
-                ),
+            disabledMessage = disabledMessage,
             isEnabled = isEnabled,
             a11yStep = volumeRange.step,
             a11yClickDescription =
@@ -191,6 +219,43 @@
         )
     }
 
+    private fun getStreamDisabledMessage(
+        blockingEverything: ActiveZenModes,
+        blockingAlarms: ActiveZenModes,
+        blockingMedia: ActiveZenModes,
+    ): String {
+        // TODO: b/372213356 - Figure out the correct messages for VOICE_CALL and RING.
+        //  In fact, VOICE_CALL should not be affected by interruption filtering at all.
+        return if (audioStream.value == STREAM_NOTIFICATION) {
+            context.getString(R.string.stream_notification_unavailable)
+        } else {
+            val blockingModeName =
+                when {
+                    blockingEverything.mainMode != null -> blockingEverything.mainMode.name
+                    audioStream.value == STREAM_ALARM -> blockingAlarms.mainMode?.name
+                    audioStream.value == STREAM_MUSIC -> blockingMedia.mainMode?.name
+                    else -> null
+                }
+
+            if (blockingModeName != null) {
+                context.getString(R.string.stream_unavailable_by_modes, blockingModeName)
+            } else {
+                // Should not actually be visible, but as a catch-all.
+                context.getString(R.string.stream_unavailable_by_unknown)
+            }
+        }
+    }
+
+    private fun getStreamDisabledMessageWithoutModes(audioStream: AudioStream): String {
+        // TODO: b/372213356 - Figure out the correct messages for VOICE_CALL and RING.
+        //  In fact, VOICE_CALL should not be affected by interruption filtering at all.
+        return if (audioStream.value == STREAM_NOTIFICATION) {
+            context.getString(R.string.stream_notification_unavailable)
+        } else {
+            context.getString(R.string.stream_alarm_unavailable)
+        }
+    }
+
     private fun AudioStreamModel.getIcon(ringerMode: RingerMode): Icon {
         val iconRes =
             if (isAffectedByMute && isMuted) {
diff --git a/packages/SystemUI/src/com/android/systemui/wallpapers/data/repository/NoopWallpaperRepository.kt b/packages/SystemUI/src/com/android/systemui/wallpapers/data/repository/NoopWallpaperRepository.kt
index b45b8cd..54953c9 100644
--- a/packages/SystemUI/src/com/android/systemui/wallpapers/data/repository/NoopWallpaperRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/wallpapers/data/repository/NoopWallpaperRepository.kt
@@ -17,6 +17,7 @@
 package com.android.systemui.wallpapers.data.repository
 
 import android.app.WallpaperInfo
+import android.view.View
 import com.android.systemui.dagger.SysUISingleton
 import javax.inject.Inject
 import kotlinx.coroutines.flow.MutableStateFlow
@@ -33,4 +34,7 @@
 class NoopWallpaperRepository @Inject constructor() : WallpaperRepository {
     override val wallpaperInfo: StateFlow<WallpaperInfo?> = MutableStateFlow(null).asStateFlow()
     override val wallpaperSupportsAmbientMode = MutableStateFlow(false).asStateFlow()
+    override var rootView: View? = null
+
+    override fun setNotificationStackAbsoluteBottom(bottom: Float) {}
 }
diff --git a/packages/SystemUI/src/com/android/systemui/wallpapers/data/repository/WallpaperRepository.kt b/packages/SystemUI/src/com/android/systemui/wallpapers/data/repository/WallpaperRepository.kt
index 041b6f9..203e1da 100644
--- a/packages/SystemUI/src/com/android/systemui/wallpapers/data/repository/WallpaperRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/wallpapers/data/repository/WallpaperRepository.kt
@@ -21,10 +21,16 @@
 import android.content.Context
 import android.content.Intent
 import android.content.IntentFilter
+import android.os.Bundle
 import android.os.UserHandle
+import android.view.View
+import androidx.annotation.VisibleForTesting
+import com.android.systemui.Flags
 import com.android.systemui.broadcast.BroadcastDispatcher
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.keyguard.data.repository.KeyguardClockRepository
+import com.android.systemui.keyguard.data.repository.KeyguardRepository
 import com.android.systemui.user.data.model.SelectedUserModel
 import com.android.systemui.user.data.model.SelectionStatus
 import com.android.systemui.user.data.repository.UserRepository
@@ -32,16 +38,19 @@
 import javax.inject.Inject
 import kotlinx.coroutines.CoroutineDispatcher
 import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Job
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.MutableStateFlow
 import kotlinx.coroutines.flow.SharingStarted
 import kotlinx.coroutines.flow.StateFlow
 import kotlinx.coroutines.flow.asStateFlow
+import kotlinx.coroutines.flow.collect
 import kotlinx.coroutines.flow.combine
 import kotlinx.coroutines.flow.filter
 import kotlinx.coroutines.flow.map
 import kotlinx.coroutines.flow.onStart
 import kotlinx.coroutines.flow.stateIn
+import kotlinx.coroutines.launch
 import kotlinx.coroutines.withContext
 
 /** A repository storing information about the current wallpaper. */
@@ -51,6 +60,15 @@
 
     /** Emits true if the current user's current wallpaper supports ambient mode. */
     val wallpaperSupportsAmbientMode: StateFlow<Boolean>
+
+    /** Set rootView to get its windowToken afterwards */
+    var rootView: View?
+
+    /**
+     * Set bottom of notifications from notification stack, and Magic Portrait will layout base on
+     * this value
+     */
+    fun setNotificationStackAbsoluteBottom(bottom: Float)
 }
 
 @SysUISingleton
@@ -61,6 +79,8 @@
     @Background private val bgDispatcher: CoroutineDispatcher,
     broadcastDispatcher: BroadcastDispatcher,
     userRepository: UserRepository,
+    keyguardRepository: KeyguardRepository,
+    keyguardClockRepository: KeyguardClockRepository,
     private val wallpaperManager: WallpaperManager,
     context: Context,
 ) : WallpaperRepository {
@@ -69,10 +89,7 @@
 
     private val wallpaperChanged: Flow<Unit> =
         broadcastDispatcher
-            .broadcastFlow(
-                IntentFilter(Intent.ACTION_WALLPAPER_CHANGED),
-                user = UserHandle.ALL,
-            )
+            .broadcastFlow(IntentFilter(Intent.ACTION_WALLPAPER_CHANGED), user = UserHandle.ALL)
             // The `combine` defining `wallpaperSupportsAmbientMode` will not run until both of the
             // input flows emit at least once. Since this flow is an input flow, it needs to emit
             // when it starts up to ensure that the `combine` will run if the user changes before we
@@ -87,6 +104,27 @@
             // Only update the wallpaper status once the user selection has finished.
             .filter { it.selectionStatus == SelectionStatus.SELECTION_COMPLETE }
 
+    /** The bottom of notification stack respect to the top of screen. */
+    private val notificationStackAbsoluteBottom: MutableStateFlow<Float> = MutableStateFlow(0F)
+
+    /** The top of shortcut respect to the top of screen. */
+    private val shortcutAbsoluteTop: StateFlow<Float> = keyguardRepository.shortcutAbsoluteTop
+
+    /**
+     * The top of notification stack to give a default state of lockscreen remaining space for
+     * states with notifications to compare with. It's the bottom of smartspace date and weather
+     * smartspace in small clock state, plus proper bottom margin.
+     */
+    private val notificationStackDefaultTop = keyguardClockRepository.notificationDefaultTop
+    @VisibleForTesting var sendLockscreenLayoutJob: Job? = null
+    private val lockscreenRemainingSpaceWithNotification: Flow<Triple<Float, Float, Float>> =
+        combine(
+            notificationStackAbsoluteBottom,
+            notificationStackDefaultTop,
+            shortcutAbsoluteTop,
+            ::Triple,
+        )
+
     override val wallpaperInfo: StateFlow<WallpaperInfo?> =
         if (!wallpaperManager.isWallpaperSupported || !deviceSupportsAodWallpaper) {
             MutableStateFlow(null).asStateFlow()
@@ -116,9 +154,70 @@
                 initialValue = wallpaperInfo.value?.supportsAmbientMode() == true,
             )
 
+    override var rootView: View? = null
+
+    val shouldSendNotificationLayout =
+        wallpaperInfo
+            .map {
+                val shouldSendNotificationLayout = shouldSendNotificationLayout(it)
+                if (shouldSendNotificationLayout) {
+                    sendLockscreenLayoutJob =
+                        scope.launch {
+                            lockscreenRemainingSpaceWithNotification.collect {
+                                (notificationBottom, notificationDefaultTop, shortcutTop) ->
+                                wallpaperManager.sendWallpaperCommand(
+                                    /* windowToken = */ rootView?.windowToken,
+                                    /* action = */ WallpaperManager
+                                        .COMMAND_LOCKSCREEN_LAYOUT_CHANGED,
+                                    /* x = */ 0,
+                                    /* y = */ 0,
+                                    /* z = */ 0,
+                                    /* extras = */ Bundle().apply {
+                                        putFloat("screenLeft", 0F)
+                                        putFloat("smartspaceBottom", notificationDefaultTop)
+                                        putFloat("notificationBottom", notificationBottom)
+                                        putFloat(
+                                            "screenRight",
+                                            context.resources.displayMetrics.widthPixels.toFloat(),
+                                        )
+                                        putFloat("shortCutTop", shortcutTop)
+                                    },
+                                )
+                            }
+                        }
+                } else {
+                    sendLockscreenLayoutJob?.cancel()
+                }
+                shouldSendNotificationLayout
+            }
+            .stateIn(
+                scope,
+                // Always be listening for wallpaper changes.
+                if (Flags.magicPortraitWallpapers()) SharingStarted.Eagerly
+                else SharingStarted.Lazily,
+                initialValue = false,
+            )
+
+    override fun setNotificationStackAbsoluteBottom(bottom: Float) {
+        notificationStackAbsoluteBottom.value = bottom
+    }
+
     private suspend fun getWallpaper(selectedUser: SelectedUserModel): WallpaperInfo? {
         return withContext(bgDispatcher) {
             wallpaperManager.getWallpaperInfoForUser(selectedUser.userInfo.id)
         }
     }
+
+    private fun shouldSendNotificationLayout(wallpaperInfo: WallpaperInfo?): Boolean {
+        return if (wallpaperInfo != null && wallpaperInfo.component != null) {
+            wallpaperInfo.component!!.className == MAGIC_PORTRAIT_CLASSNAME
+        } else {
+            false
+        }
+    }
+
+    companion object {
+        const val MAGIC_PORTRAIT_CLASSNAME =
+            "com.google.android.apps.magicportrait.service.MagicPortraitWallpaperService"
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/domain/interactor/FixedColumnsSizeInteractor.kt b/packages/SystemUI/src/com/android/systemui/wallpapers/domain/interactor/WallpaperInteractor.kt
similarity index 63%
copy from packages/SystemUI/src/com/android/systemui/qs/panels/domain/interactor/FixedColumnsSizeInteractor.kt
copy to packages/SystemUI/src/com/android/systemui/wallpapers/domain/interactor/WallpaperInteractor.kt
index 9591002..79ebf01 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/domain/interactor/FixedColumnsSizeInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/wallpapers/domain/interactor/WallpaperInteractor.kt
@@ -14,14 +14,13 @@
  * limitations under the License.
  */
 
-package com.android.systemui.qs.panels.domain.interactor
+package com.android.systemui.wallpapers.domain.interactor
 
-import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.qs.panels.data.repository.FixedColumnsRepository
+import com.android.systemui.wallpapers.data.repository.WallpaperRepository
 import javax.inject.Inject
-import kotlinx.coroutines.flow.StateFlow
 
-@SysUISingleton
-class FixedColumnsSizeInteractor @Inject constructor(repo: FixedColumnsRepository) {
-    val columns: StateFlow<Int> = repo.columns
+class WallpaperInteractor @Inject constructor(val wallpaperRepository: WallpaperRepository) {
+    fun setNotificationStackAbsoluteBottom(bottom: Float) {
+        wallpaperRepository.setNotificationStackAbsoluteBottom(bottom)
+    }
 }
diff --git a/packages/SystemUI/tests/goldens/backgroundAnimationWithoutFade_whenLaunching.json b/packages/SystemUI/tests/goldens/backgroundAnimationWithoutFade_whenLaunching.json
index 60bff17..7f62357 100644
--- a/packages/SystemUI/tests/goldens/backgroundAnimationWithoutFade_whenLaunching.json
+++ b/packages/SystemUI/tests/goldens/backgroundAnimationWithoutFade_whenLaunching.json
@@ -1,25 +1,30 @@
 {
   "frame_ids": [
-    "before",
     0,
-    26,
-    52,
-    78,
-    105,
-    131,
-    157,
-    184,
-    210,
-    236,
-    263,
-    289,
-    315,
-    342,
-    368,
-    394,
-    421,
-    447,
-    473,
+    20,
+    40,
+    60,
+    80,
+    100,
+    120,
+    140,
+    160,
+    180,
+    200,
+    220,
+    240,
+    260,
+    280,
+    300,
+    320,
+    340,
+    360,
+    380,
+    400,
+    420,
+    440,
+    460,
+    480,
     500
   ],
   "features": [
@@ -28,70 +33,82 @@
       "type": "rect",
       "data_points": [
         {
-          "left": 0,
-          "top": 0,
-          "right": 0,
-          "bottom": 0
-        },
-        {
           "left": 100,
           "top": 300,
           "right": 200,
           "bottom": 400
         },
         {
-          "left": 98,
-          "top": 293,
-          "right": 203,
-          "bottom": 407
+          "left": 99,
+          "top": 296,
+          "right": 202,
+          "bottom": 404
         },
         {
-          "left": 91,
-          "top": 269,
-          "right": 213,
-          "bottom": 430
+          "left": 95,
+          "top": 283,
+          "right": 207,
+          "bottom": 417
         },
         {
-          "left": 71,
-          "top": 206,
-          "right": 240,
-          "bottom": 491
+          "left": 86,
+          "top": 256,
+          "right": 219,
+          "bottom": 443
         },
         {
-          "left": 34,
-          "top": 98,
-          "right": 283,
-          "bottom": 595
+          "left": 68,
+          "top": 198,
+          "right": 243,
+          "bottom": 499
         },
         {
-          "left": 22,
-          "top": 63,
-          "right": 296,
-          "bottom": 629
+          "left": 39,
+          "top": 110,
+          "right": 278,
+          "bottom": 584
+        },
+        {
+          "left": 26,
+          "top": 74,
+          "right": 292,
+          "bottom": 618
+        },
+        {
+          "left": 19,
+          "top": 55,
+          "right": 299,
+          "bottom": 637
         },
         {
           "left": 15,
-          "top": 44,
-          "right": 303,
-          "bottom": 648
+          "top": 42,
+          "right": 304,
+          "bottom": 649
         },
         {
-          "left": 11,
-          "top": 32,
-          "right": 308,
-          "bottom": 659
+          "left": 12,
+          "top": 33,
+          "right": 307,
+          "bottom": 658
         },
         {
-          "left": 8,
-          "top": 23,
-          "right": 311,
-          "bottom": 667
+          "left": 9,
+          "top": 27,
+          "right": 310,
+          "bottom": 664
+        },
+        {
+          "left": 7,
+          "top": 21,
+          "right": 312,
+          "bottom": 669
         },
         {
           "left": 6,
-          "top": 18,
-          "right": 313,
-          "bottom": 673
+          "top": 17,
+          "right": 314,
+          "bottom": 674
         },
         {
           "left": 5,
@@ -100,16 +117,22 @@
           "bottom": 677
         },
         {
-          "left": 3,
-          "top": 9,
+          "left": 4,
+          "top": 10,
           "right": 316,
-          "bottom": 681
+          "bottom": 680
+        },
+        {
+          "left": 3,
+          "top": 8,
+          "right": 317,
+          "bottom": 682
         },
         {
           "left": 2,
-          "top": 7,
-          "right": 317,
-          "bottom": 683
+          "top": 6,
+          "right": 318,
+          "bottom": 684
         },
         {
           "left": 2,
@@ -119,7 +142,7 @@
         },
         {
           "left": 1,
-          "top": 3,
+          "top": 4,
           "right": 319,
           "bottom": 687
         },
@@ -130,6 +153,18 @@
           "bottom": 688
         },
         {
+          "left": 1,
+          "top": 2,
+          "right": 319,
+          "bottom": 688
+        },
+        {
+          "left": 0,
+          "top": 1,
+          "right": 320,
+          "bottom": 689
+        },
+        {
           "left": 0,
           "top": 1,
           "right": 320,
@@ -159,7 +194,6 @@
       "name": "corner_radii",
       "type": "cornerRadii",
       "data_points": [
-        null,
         {
           "top_left_x": 10,
           "top_left_y": 10,
@@ -171,184 +205,244 @@
           "bottom_left_y": 20
         },
         {
-          "top_left_x": 9.762664,
-          "top_left_y": 9.762664,
-          "top_right_x": 9.762664,
-          "top_right_y": 9.762664,
-          "bottom_right_x": 19.525328,
-          "bottom_right_y": 19.525328,
-          "bottom_left_x": 19.525328,
-          "bottom_left_y": 19.525328
+          "top_left_x": 9.865689,
+          "top_left_y": 9.865689,
+          "top_right_x": 9.865689,
+          "top_right_y": 9.865689,
+          "bottom_right_x": 19.731379,
+          "bottom_right_y": 19.731379,
+          "bottom_left_x": 19.731379,
+          "bottom_left_y": 19.731379
         },
         {
-          "top_left_x": 8.969244,
-          "top_left_y": 8.969244,
-          "top_right_x": 8.969244,
-          "top_right_y": 8.969244,
-          "bottom_right_x": 17.938488,
-          "bottom_right_y": 17.938488,
-          "bottom_left_x": 17.938488,
-          "bottom_left_y": 17.938488
+          "top_left_x": 9.419104,
+          "top_left_y": 9.419104,
+          "top_right_x": 9.419104,
+          "top_right_y": 9.419104,
+          "bottom_right_x": 18.838207,
+          "bottom_right_y": 18.838207,
+          "bottom_left_x": 18.838207,
+          "bottom_left_y": 18.838207
         },
         {
-          "top_left_x": 6.8709626,
-          "top_left_y": 6.8709626,
-          "top_right_x": 6.8709626,
-          "top_right_y": 6.8709626,
-          "bottom_right_x": 13.741925,
-          "bottom_right_y": 13.741925,
-          "bottom_left_x": 13.741925,
-          "bottom_left_y": 13.741925
+          "top_left_x": 8.533693,
+          "top_left_y": 8.533693,
+          "top_right_x": 8.533693,
+          "top_right_y": 8.533693,
+          "bottom_right_x": 17.067387,
+          "bottom_right_y": 17.067387,
+          "bottom_left_x": 17.067387,
+          "bottom_left_y": 17.067387
         },
         {
-          "top_left_x": 3.260561,
-          "top_left_y": 3.260561,
-          "top_right_x": 3.260561,
-          "top_right_y": 3.260561,
-          "bottom_right_x": 6.521122,
-          "bottom_right_y": 6.521122,
-          "bottom_left_x": 6.521122,
-          "bottom_left_y": 6.521122
+          "top_left_x": 6.5919456,
+          "top_left_y": 6.5919456,
+          "top_right_x": 6.5919456,
+          "top_right_y": 6.5919456,
+          "bottom_right_x": 13.183891,
+          "bottom_right_y": 13.183891,
+          "bottom_left_x": 13.183891,
+          "bottom_left_y": 13.183891
         },
         {
-          "top_left_x": 2.0915751,
-          "top_left_y": 2.0915751,
-          "top_right_x": 2.0915751,
-          "top_right_y": 2.0915751,
-          "bottom_right_x": 4.1831503,
-          "bottom_right_y": 4.1831503,
-          "bottom_left_x": 4.1831503,
-          "bottom_left_y": 4.1831503
+          "top_left_x": 3.6674318,
+          "top_left_y": 3.6674318,
+          "top_right_x": 3.6674318,
+          "top_right_y": 3.6674318,
+          "bottom_right_x": 7.3348637,
+          "bottom_right_y": 7.3348637,
+          "bottom_left_x": 7.3348637,
+          "bottom_left_y": 7.3348637
         },
         {
-          "top_left_x": 1.4640827,
-          "top_left_y": 1.4640827,
-          "top_right_x": 1.4640827,
-          "top_right_y": 1.4640827,
-          "bottom_right_x": 2.9281654,
-          "bottom_right_y": 2.9281654,
-          "bottom_left_x": 2.9281654,
-          "bottom_left_y": 2.9281654
+          "top_left_x": 2.4832253,
+          "top_left_y": 2.4832253,
+          "top_right_x": 2.4832253,
+          "top_right_y": 2.4832253,
+          "bottom_right_x": 4.9664507,
+          "bottom_right_y": 4.9664507,
+          "bottom_left_x": 4.9664507,
+          "bottom_left_y": 4.9664507
         },
         {
-          "top_left_x": 1.057313,
-          "top_left_y": 1.057313,
-          "top_right_x": 1.057313,
-          "top_right_y": 1.057313,
-          "bottom_right_x": 2.114626,
-          "bottom_right_y": 2.114626,
-          "bottom_left_x": 2.114626,
-          "bottom_left_y": 2.114626
+          "top_left_x": 1.8252907,
+          "top_left_y": 1.8252907,
+          "top_right_x": 1.8252907,
+          "top_right_y": 1.8252907,
+          "bottom_right_x": 3.6505814,
+          "bottom_right_y": 3.6505814,
+          "bottom_left_x": 3.6505814,
+          "bottom_left_y": 3.6505814
         },
         {
-          "top_left_x": 0.7824335,
-          "top_left_y": 0.7824335,
-          "top_right_x": 0.7824335,
-          "top_right_y": 0.7824335,
-          "bottom_right_x": 1.564867,
-          "bottom_right_y": 1.564867,
-          "bottom_left_x": 1.564867,
-          "bottom_left_y": 1.564867
+          "top_left_x": 1.4077549,
+          "top_left_y": 1.4077549,
+          "top_right_x": 1.4077549,
+          "top_right_y": 1.4077549,
+          "bottom_right_x": 2.8155098,
+          "bottom_right_y": 2.8155098,
+          "bottom_left_x": 2.8155098,
+          "bottom_left_y": 2.8155098
         },
         {
-          "top_left_x": 0.5863056,
-          "top_left_y": 0.5863056,
-          "top_right_x": 0.5863056,
-          "top_right_y": 0.5863056,
-          "bottom_right_x": 1.1726112,
-          "bottom_right_y": 1.1726112,
-          "bottom_left_x": 1.1726112,
-          "bottom_left_y": 1.1726112
+          "top_left_x": 1.1067667,
+          "top_left_y": 1.1067667,
+          "top_right_x": 1.1067667,
+          "top_right_y": 1.1067667,
+          "bottom_right_x": 2.2135334,
+          "bottom_right_y": 2.2135334,
+          "bottom_left_x": 2.2135334,
+          "bottom_left_y": 2.2135334
         },
         {
-          "top_left_x": 0.4332962,
-          "top_left_y": 0.4332962,
-          "top_right_x": 0.4332962,
-          "top_right_y": 0.4332962,
-          "bottom_right_x": 0.8665924,
-          "bottom_right_y": 0.8665924,
-          "bottom_left_x": 0.8665924,
-          "bottom_left_y": 0.8665924
+          "top_left_x": 0.88593864,
+          "top_left_y": 0.88593864,
+          "top_right_x": 0.88593864,
+          "top_right_y": 0.88593864,
+          "bottom_right_x": 1.7718773,
+          "bottom_right_y": 1.7718773,
+          "bottom_left_x": 1.7718773,
+          "bottom_left_y": 1.7718773
         },
         {
-          "top_left_x": 0.3145876,
-          "top_left_y": 0.3145876,
-          "top_right_x": 0.3145876,
-          "top_right_y": 0.3145876,
-          "bottom_right_x": 0.6291752,
-          "bottom_right_y": 0.6291752,
-          "bottom_left_x": 0.6291752,
-          "bottom_left_y": 0.6291752
+          "top_left_x": 0.7069988,
+          "top_left_y": 0.7069988,
+          "top_right_x": 0.7069988,
+          "top_right_y": 0.7069988,
+          "bottom_right_x": 1.4139977,
+          "bottom_right_y": 1.4139977,
+          "bottom_left_x": 1.4139977,
+          "bottom_left_y": 1.4139977
         },
         {
-          "top_left_x": 0.22506618,
-          "top_left_y": 0.22506618,
-          "top_right_x": 0.22506618,
-          "top_right_y": 0.22506618,
-          "bottom_right_x": 0.45013237,
-          "bottom_right_y": 0.45013237,
-          "bottom_left_x": 0.45013237,
-          "bottom_left_y": 0.45013237
+          "top_left_x": 0.55613136,
+          "top_left_y": 0.55613136,
+          "top_right_x": 0.55613136,
+          "top_right_y": 0.55613136,
+          "bottom_right_x": 1.1122627,
+          "bottom_right_y": 1.1122627,
+          "bottom_left_x": 1.1122627,
+          "bottom_left_y": 1.1122627
         },
         {
-          "top_left_x": 0.15591621,
-          "top_left_y": 0.15591621,
-          "top_right_x": 0.15591621,
-          "top_right_y": 0.15591621,
-          "bottom_right_x": 0.31183243,
-          "bottom_right_y": 0.31183243,
-          "bottom_left_x": 0.31183243,
-          "bottom_left_y": 0.31183243
+          "top_left_x": 0.44889355,
+          "top_left_y": 0.44889355,
+          "top_right_x": 0.44889355,
+          "top_right_y": 0.44889355,
+          "bottom_right_x": 0.8977871,
+          "bottom_right_y": 0.8977871,
+          "bottom_left_x": 0.8977871,
+          "bottom_left_y": 0.8977871
         },
         {
-          "top_left_x": 0.100948334,
-          "top_left_y": 0.100948334,
-          "top_right_x": 0.100948334,
-          "top_right_y": 0.100948334,
-          "bottom_right_x": 0.20189667,
-          "bottom_right_y": 0.20189667,
-          "bottom_left_x": 0.20189667,
-          "bottom_left_y": 0.20189667
+          "top_left_x": 0.34557533,
+          "top_left_y": 0.34557533,
+          "top_right_x": 0.34557533,
+          "top_right_y": 0.34557533,
+          "bottom_right_x": 0.69115067,
+          "bottom_right_y": 0.69115067,
+          "bottom_left_x": 0.69115067,
+          "bottom_left_y": 0.69115067
         },
         {
-          "top_left_x": 0.06496239,
-          "top_left_y": 0.06496239,
-          "top_right_x": 0.06496239,
-          "top_right_y": 0.06496239,
-          "bottom_right_x": 0.12992477,
-          "bottom_right_y": 0.12992477,
-          "bottom_left_x": 0.12992477,
-          "bottom_left_y": 0.12992477
+          "top_left_x": 0.27671337,
+          "top_left_y": 0.27671337,
+          "top_right_x": 0.27671337,
+          "top_right_y": 0.27671337,
+          "bottom_right_x": 0.55342674,
+          "bottom_right_y": 0.55342674,
+          "bottom_left_x": 0.55342674,
+          "bottom_left_y": 0.55342674
         },
         {
-          "top_left_x": 0.03526497,
-          "top_left_y": 0.03526497,
-          "top_right_x": 0.03526497,
-          "top_right_y": 0.03526497,
-          "bottom_right_x": 0.07052994,
-          "bottom_right_y": 0.07052994,
-          "bottom_left_x": 0.07052994,
-          "bottom_left_y": 0.07052994
+          "top_left_x": 0.20785141,
+          "top_left_y": 0.20785141,
+          "top_right_x": 0.20785141,
+          "top_right_y": 0.20785141,
+          "bottom_right_x": 0.41570282,
+          "bottom_right_y": 0.41570282,
+          "bottom_left_x": 0.41570282,
+          "bottom_left_y": 0.41570282
         },
         {
-          "top_left_x": 0.014661789,
-          "top_left_y": 0.014661789,
-          "top_right_x": 0.014661789,
-          "top_right_y": 0.014661789,
-          "bottom_right_x": 0.029323578,
-          "bottom_right_y": 0.029323578,
-          "bottom_left_x": 0.029323578,
-          "bottom_left_y": 0.029323578
+          "top_left_x": 0.1601448,
+          "top_left_y": 0.1601448,
+          "top_right_x": 0.1601448,
+          "top_right_y": 0.1601448,
+          "bottom_right_x": 0.3202896,
+          "bottom_right_y": 0.3202896,
+          "bottom_left_x": 0.3202896,
+          "bottom_left_y": 0.3202896
         },
         {
-          "top_left_x": 0.0041856766,
-          "top_left_y": 0.0041856766,
-          "top_right_x": 0.0041856766,
-          "top_right_y": 0.0041856766,
-          "bottom_right_x": 0.008371353,
-          "bottom_right_y": 0.008371353,
-          "bottom_left_x": 0.008371353,
-          "bottom_left_y": 0.008371353
+          "top_left_x": 0.117860794,
+          "top_left_y": 0.117860794,
+          "top_right_x": 0.117860794,
+          "top_right_y": 0.117860794,
+          "bottom_right_x": 0.23572159,
+          "bottom_right_y": 0.23572159,
+          "bottom_left_x": 0.23572159,
+          "bottom_left_y": 0.23572159
+        },
+        {
+          "top_left_x": 0.08036041,
+          "top_left_y": 0.08036041,
+          "top_right_x": 0.08036041,
+          "top_right_y": 0.08036041,
+          "bottom_right_x": 0.16072083,
+          "bottom_right_y": 0.16072083,
+          "bottom_left_x": 0.16072083,
+          "bottom_left_y": 0.16072083
+        },
+        {
+          "top_left_x": 0.05836296,
+          "top_left_y": 0.05836296,
+          "top_right_x": 0.05836296,
+          "top_right_y": 0.05836296,
+          "bottom_right_x": 0.11672592,
+          "bottom_right_y": 0.11672592,
+          "bottom_left_x": 0.11672592,
+          "bottom_left_y": 0.11672592
+        },
+        {
+          "top_left_x": 0.03636551,
+          "top_left_y": 0.03636551,
+          "top_right_x": 0.03636551,
+          "top_right_y": 0.03636551,
+          "bottom_right_x": 0.07273102,
+          "bottom_right_y": 0.07273102,
+          "bottom_left_x": 0.07273102,
+          "bottom_left_y": 0.07273102
+        },
+        {
+          "top_left_x": 0.018137932,
+          "top_left_y": 0.018137932,
+          "top_right_x": 0.018137932,
+          "top_right_y": 0.018137932,
+          "bottom_right_x": 0.036275864,
+          "bottom_right_y": 0.036275864,
+          "bottom_left_x": 0.036275864,
+          "bottom_left_y": 0.036275864
+        },
+        {
+          "top_left_x": 0.0082063675,
+          "top_left_y": 0.0082063675,
+          "top_right_x": 0.0082063675,
+          "top_right_y": 0.0082063675,
+          "bottom_right_x": 0.016412735,
+          "bottom_right_y": 0.016412735,
+          "bottom_left_x": 0.016412735,
+          "bottom_left_y": 0.016412735
+        },
+        {
+          "top_left_x": 0.0031013489,
+          "top_left_y": 0.0031013489,
+          "top_right_x": 0.0031013489,
+          "top_right_y": 0.0031013489,
+          "bottom_right_x": 0.0062026978,
+          "bottom_right_y": 0.0062026978,
+          "bottom_left_x": 0.0062026978,
+          "bottom_left_y": 0.0062026978
         },
         {
           "top_left_x": 0,
@@ -367,12 +461,17 @@
       "type": "int",
       "data_points": [
         0,
-        0,
-        115,
-        178,
-        217,
-        241,
-        253,
+        96,
+        153,
+        192,
+        220,
+        238,
+        249,
+        254,
+        255,
+        255,
+        255,
+        255,
         255,
         255,
         255,
diff --git a/packages/SystemUI/tests/goldens/backgroundAnimationWithoutFade_whenLaunching_withSpring.json b/packages/SystemUI/tests/goldens/backgroundAnimationWithoutFade_whenLaunching_withSpring.json
new file mode 100644
index 0000000..18eedd4
--- /dev/null
+++ b/packages/SystemUI/tests/goldens/backgroundAnimationWithoutFade_whenLaunching_withSpring.json
@@ -0,0 +1,375 @@
+{
+  "frame_ids": [
+    0,
+    16,
+    32,
+    48,
+    64,
+    80,
+    96,
+    112,
+    128,
+    144,
+    160,
+    176,
+    192,
+    208,
+    224,
+    240,
+    256,
+    272,
+    288,
+    304
+  ],
+  "features": [
+    {
+      "name": "bounds",
+      "type": "rect",
+      "data_points": [
+        {
+          "left": 0,
+          "top": 0,
+          "right": 0,
+          "bottom": 0
+        },
+        {
+          "left": 94,
+          "top": 284,
+          "right": 206,
+          "bottom": 414
+        },
+        {
+          "left": 83,
+          "top": 251,
+          "right": 219,
+          "bottom": 447
+        },
+        {
+          "left": 70,
+          "top": 212,
+          "right": 234,
+          "bottom": 485
+        },
+        {
+          "left": 57,
+          "top": 173,
+          "right": 250,
+          "bottom": 522
+        },
+        {
+          "left": 46,
+          "top": 139,
+          "right": 264,
+          "bottom": 555
+        },
+        {
+          "left": 36,
+          "top": 109,
+          "right": 276,
+          "bottom": 584
+        },
+        {
+          "left": 28,
+          "top": 84,
+          "right": 285,
+          "bottom": 608
+        },
+        {
+          "left": 21,
+          "top": 65,
+          "right": 293,
+          "bottom": 627
+        },
+        {
+          "left": 16,
+          "top": 49,
+          "right": 300,
+          "bottom": 642
+        },
+        {
+          "left": 12,
+          "top": 36,
+          "right": 305,
+          "bottom": 653
+        },
+        {
+          "left": 9,
+          "top": 27,
+          "right": 308,
+          "bottom": 662
+        },
+        {
+          "left": 7,
+          "top": 20,
+          "right": 312,
+          "bottom": 669
+        },
+        {
+          "left": 5,
+          "top": 14,
+          "right": 314,
+          "bottom": 675
+        },
+        {
+          "left": 4,
+          "top": 11,
+          "right": 315,
+          "bottom": 678
+        },
+        {
+          "left": 3,
+          "top": 8,
+          "right": 316,
+          "bottom": 681
+        },
+        {
+          "left": 2,
+          "top": 5,
+          "right": 317,
+          "bottom": 684
+        },
+        {
+          "left": 1,
+          "top": 4,
+          "right": 318,
+          "bottom": 685
+        },
+        {
+          "left": 1,
+          "top": 3,
+          "right": 318,
+          "bottom": 686
+        },
+        {
+          "left": 0,
+          "top": 2,
+          "right": 319,
+          "bottom": 687
+        }
+      ]
+    },
+    {
+      "name": "corner_radii",
+      "type": "cornerRadii",
+      "data_points": [
+        null,
+        {
+          "top_left_x": 9.492916,
+          "top_left_y": 9.492916,
+          "top_right_x": 9.492916,
+          "top_right_y": 9.492916,
+          "bottom_right_x": 18.985832,
+          "bottom_right_y": 18.985832,
+          "bottom_left_x": 18.985832,
+          "bottom_left_y": 18.985832
+        },
+        {
+          "top_left_x": 8.381761,
+          "top_left_y": 8.381761,
+          "top_right_x": 8.381761,
+          "top_right_y": 8.381761,
+          "bottom_right_x": 16.763521,
+          "bottom_right_y": 16.763521,
+          "bottom_left_x": 16.763521,
+          "bottom_left_y": 16.763521
+        },
+        {
+          "top_left_x": 7.07397,
+          "top_left_y": 7.07397,
+          "top_right_x": 7.07397,
+          "top_right_y": 7.07397,
+          "bottom_right_x": 14.14794,
+          "bottom_right_y": 14.14794,
+          "bottom_left_x": 14.14794,
+          "bottom_left_y": 14.14794
+        },
+        {
+          "top_left_x": 5.7880254,
+          "top_left_y": 5.7880254,
+          "top_right_x": 5.7880254,
+          "top_right_y": 5.7880254,
+          "bottom_right_x": 11.576051,
+          "bottom_right_y": 11.576051,
+          "bottom_left_x": 11.576051,
+          "bottom_left_y": 11.576051
+        },
+        {
+          "top_left_x": 4.6295347,
+          "top_left_y": 4.6295347,
+          "top_right_x": 4.6295347,
+          "top_right_y": 4.6295347,
+          "bottom_right_x": 9.259069,
+          "bottom_right_y": 9.259069,
+          "bottom_left_x": 9.259069,
+          "bottom_left_y": 9.259069
+        },
+        {
+          "top_left_x": 3.638935,
+          "top_left_y": 3.638935,
+          "top_right_x": 3.638935,
+          "top_right_y": 3.638935,
+          "bottom_right_x": 7.27787,
+          "bottom_right_y": 7.27787,
+          "bottom_left_x": 7.27787,
+          "bottom_left_y": 7.27787
+        },
+        {
+          "top_left_x": 2.8209057,
+          "top_left_y": 2.8209057,
+          "top_right_x": 2.8209057,
+          "top_right_y": 2.8209057,
+          "bottom_right_x": 5.6418114,
+          "bottom_right_y": 5.6418114,
+          "bottom_left_x": 5.6418114,
+          "bottom_left_y": 5.6418114
+        },
+        {
+          "top_left_x": 2.1620893,
+          "top_left_y": 2.1620893,
+          "top_right_x": 2.1620893,
+          "top_right_y": 2.1620893,
+          "bottom_right_x": 4.3241787,
+          "bottom_right_y": 4.3241787,
+          "bottom_left_x": 4.3241787,
+          "bottom_left_y": 4.3241787
+        },
+        {
+          "top_left_x": 1.6414614,
+          "top_left_y": 1.6414614,
+          "top_right_x": 1.6414614,
+          "top_right_y": 1.6414614,
+          "bottom_right_x": 3.2829227,
+          "bottom_right_y": 3.2829227,
+          "bottom_left_x": 3.2829227,
+          "bottom_left_y": 3.2829227
+        },
+        {
+          "top_left_x": 1.2361269,
+          "top_left_y": 1.2361269,
+          "top_right_x": 1.2361269,
+          "top_right_y": 1.2361269,
+          "bottom_right_x": 2.4722538,
+          "bottom_right_y": 2.4722538,
+          "bottom_left_x": 2.4722538,
+          "bottom_left_y": 2.4722538
+        },
+        {
+          "top_left_x": 0.92435074,
+          "top_left_y": 0.92435074,
+          "top_right_x": 0.92435074,
+          "top_right_y": 0.92435074,
+          "bottom_right_x": 1.8487015,
+          "bottom_right_y": 1.8487015,
+          "bottom_left_x": 1.8487015,
+          "bottom_left_y": 1.8487015
+        },
+        {
+          "top_left_x": 0.68693924,
+          "top_left_y": 0.68693924,
+          "top_right_x": 0.68693924,
+          "top_right_y": 0.68693924,
+          "bottom_right_x": 1.3738785,
+          "bottom_right_y": 1.3738785,
+          "bottom_left_x": 1.3738785,
+          "bottom_left_y": 1.3738785
+        },
+        {
+          "top_left_x": 0.5076904,
+          "top_left_y": 0.5076904,
+          "top_right_x": 0.5076904,
+          "top_right_y": 0.5076904,
+          "bottom_right_x": 1.0153809,
+          "bottom_right_y": 1.0153809,
+          "bottom_left_x": 1.0153809,
+          "bottom_left_y": 1.0153809
+        },
+        {
+          "top_left_x": 0.3733511,
+          "top_left_y": 0.3733511,
+          "top_right_x": 0.3733511,
+          "top_right_y": 0.3733511,
+          "bottom_right_x": 0.7467022,
+          "bottom_right_y": 0.7467022,
+          "bottom_left_x": 0.7467022,
+          "bottom_left_y": 0.7467022
+        },
+        {
+          "top_left_x": 0.27331638,
+          "top_left_y": 0.27331638,
+          "top_right_x": 0.27331638,
+          "top_right_y": 0.27331638,
+          "bottom_right_x": 0.54663277,
+          "bottom_right_y": 0.54663277,
+          "bottom_left_x": 0.54663277,
+          "bottom_left_y": 0.54663277
+        },
+        {
+          "top_left_x": 0.19925308,
+          "top_left_y": 0.19925308,
+          "top_right_x": 0.19925308,
+          "top_right_y": 0.19925308,
+          "bottom_right_x": 0.39850616,
+          "bottom_right_y": 0.39850616,
+          "bottom_left_x": 0.39850616,
+          "bottom_left_y": 0.39850616
+        },
+        {
+          "top_left_x": 0.14470005,
+          "top_left_y": 0.14470005,
+          "top_right_x": 0.14470005,
+          "top_right_y": 0.14470005,
+          "bottom_right_x": 0.2894001,
+          "bottom_right_y": 0.2894001,
+          "bottom_left_x": 0.2894001,
+          "bottom_left_y": 0.2894001
+        },
+        {
+          "top_left_x": 0.10470486,
+          "top_left_y": 0.10470486,
+          "top_right_x": 0.10470486,
+          "top_right_y": 0.10470486,
+          "bottom_right_x": 0.20940971,
+          "bottom_right_y": 0.20940971,
+          "bottom_left_x": 0.20940971,
+          "bottom_left_y": 0.20940971
+        },
+        {
+          "top_left_x": 0.07550812,
+          "top_left_y": 0.07550812,
+          "top_right_x": 0.07550812,
+          "top_right_y": 0.07550812,
+          "bottom_right_x": 0.15101624,
+          "bottom_right_y": 0.15101624,
+          "bottom_left_x": 0.15101624,
+          "bottom_left_y": 0.15101624
+        }
+      ]
+    },
+    {
+      "name": "alpha",
+      "type": "int",
+      "data_points": [
+        0,
+        255,
+        255,
+        255,
+        255,
+        255,
+        255,
+        255,
+        255,
+        255,
+        249,
+        226,
+        192,
+        153,
+        112,
+        72,
+        34,
+        0,
+        0,
+        0
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/goldens/backgroundAnimationWithoutFade_whenReturning.json b/packages/SystemUI/tests/goldens/backgroundAnimationWithoutFade_whenReturning.json
index ea768c0..98005c5 100644
--- a/packages/SystemUI/tests/goldens/backgroundAnimationWithoutFade_whenReturning.json
+++ b/packages/SystemUI/tests/goldens/backgroundAnimationWithoutFade_whenReturning.json
@@ -1,25 +1,30 @@
 {
   "frame_ids": [
-    "before",
     0,
-    26,
-    52,
-    78,
-    105,
-    131,
-    157,
-    184,
-    210,
-    236,
-    263,
-    289,
-    315,
-    342,
-    368,
-    394,
-    421,
-    447,
-    473,
+    20,
+    40,
+    60,
+    80,
+    100,
+    120,
+    140,
+    160,
+    180,
+    200,
+    220,
+    240,
+    260,
+    280,
+    300,
+    320,
+    340,
+    360,
+    380,
+    400,
+    420,
+    440,
+    460,
+    480,
     500
   ],
   "features": [
@@ -28,70 +33,82 @@
       "type": "rect",
       "data_points": [
         {
-          "left": 0,
-          "top": 0,
-          "right": 0,
-          "bottom": 0
-        },
-        {
           "left": 100,
           "top": 300,
           "right": 200,
           "bottom": 400
         },
         {
-          "left": 98,
-          "top": 293,
-          "right": 203,
-          "bottom": 407
+          "left": 99,
+          "top": 296,
+          "right": 202,
+          "bottom": 404
         },
         {
-          "left": 91,
-          "top": 269,
-          "right": 213,
-          "bottom": 430
+          "left": 95,
+          "top": 283,
+          "right": 207,
+          "bottom": 417
         },
         {
-          "left": 71,
-          "top": 206,
-          "right": 240,
-          "bottom": 491
+          "left": 86,
+          "top": 256,
+          "right": 219,
+          "bottom": 443
         },
         {
-          "left": 34,
-          "top": 98,
-          "right": 283,
-          "bottom": 595
+          "left": 68,
+          "top": 198,
+          "right": 243,
+          "bottom": 499
         },
         {
-          "left": 22,
-          "top": 63,
-          "right": 296,
-          "bottom": 629
+          "left": 39,
+          "top": 110,
+          "right": 278,
+          "bottom": 584
+        },
+        {
+          "left": 26,
+          "top": 74,
+          "right": 292,
+          "bottom": 618
+        },
+        {
+          "left": 19,
+          "top": 55,
+          "right": 299,
+          "bottom": 637
         },
         {
           "left": 15,
-          "top": 44,
-          "right": 303,
-          "bottom": 648
+          "top": 42,
+          "right": 304,
+          "bottom": 649
         },
         {
-          "left": 11,
-          "top": 32,
-          "right": 308,
-          "bottom": 659
+          "left": 12,
+          "top": 33,
+          "right": 307,
+          "bottom": 658
         },
         {
-          "left": 8,
-          "top": 23,
-          "right": 311,
-          "bottom": 667
+          "left": 9,
+          "top": 27,
+          "right": 310,
+          "bottom": 664
+        },
+        {
+          "left": 7,
+          "top": 21,
+          "right": 312,
+          "bottom": 669
         },
         {
           "left": 6,
-          "top": 18,
-          "right": 313,
-          "bottom": 673
+          "top": 17,
+          "right": 314,
+          "bottom": 674
         },
         {
           "left": 5,
@@ -100,16 +117,22 @@
           "bottom": 677
         },
         {
-          "left": 3,
-          "top": 9,
+          "left": 4,
+          "top": 10,
           "right": 316,
-          "bottom": 681
+          "bottom": 680
+        },
+        {
+          "left": 3,
+          "top": 8,
+          "right": 317,
+          "bottom": 682
         },
         {
           "left": 2,
-          "top": 7,
-          "right": 317,
-          "bottom": 683
+          "top": 6,
+          "right": 318,
+          "bottom": 684
         },
         {
           "left": 2,
@@ -119,7 +142,7 @@
         },
         {
           "left": 1,
-          "top": 3,
+          "top": 4,
           "right": 319,
           "bottom": 687
         },
@@ -130,6 +153,18 @@
           "bottom": 688
         },
         {
+          "left": 1,
+          "top": 2,
+          "right": 319,
+          "bottom": 688
+        },
+        {
+          "left": 0,
+          "top": 1,
+          "right": 320,
+          "bottom": 689
+        },
+        {
           "left": 0,
           "top": 1,
           "right": 320,
@@ -159,7 +194,6 @@
       "name": "corner_radii",
       "type": "cornerRadii",
       "data_points": [
-        null,
         {
           "top_left_x": 10,
           "top_left_y": 10,
@@ -171,184 +205,244 @@
           "bottom_left_y": 20
         },
         {
-          "top_left_x": 9.762664,
-          "top_left_y": 9.762664,
-          "top_right_x": 9.762664,
-          "top_right_y": 9.762664,
-          "bottom_right_x": 19.525328,
-          "bottom_right_y": 19.525328,
-          "bottom_left_x": 19.525328,
-          "bottom_left_y": 19.525328
+          "top_left_x": 9.865689,
+          "top_left_y": 9.865689,
+          "top_right_x": 9.865689,
+          "top_right_y": 9.865689,
+          "bottom_right_x": 19.731379,
+          "bottom_right_y": 19.731379,
+          "bottom_left_x": 19.731379,
+          "bottom_left_y": 19.731379
         },
         {
-          "top_left_x": 8.969244,
-          "top_left_y": 8.969244,
-          "top_right_x": 8.969244,
-          "top_right_y": 8.969244,
-          "bottom_right_x": 17.938488,
-          "bottom_right_y": 17.938488,
-          "bottom_left_x": 17.938488,
-          "bottom_left_y": 17.938488
+          "top_left_x": 9.419104,
+          "top_left_y": 9.419104,
+          "top_right_x": 9.419104,
+          "top_right_y": 9.419104,
+          "bottom_right_x": 18.838207,
+          "bottom_right_y": 18.838207,
+          "bottom_left_x": 18.838207,
+          "bottom_left_y": 18.838207
         },
         {
-          "top_left_x": 6.8709626,
-          "top_left_y": 6.8709626,
-          "top_right_x": 6.8709626,
-          "top_right_y": 6.8709626,
-          "bottom_right_x": 13.741925,
-          "bottom_right_y": 13.741925,
-          "bottom_left_x": 13.741925,
-          "bottom_left_y": 13.741925
+          "top_left_x": 8.533693,
+          "top_left_y": 8.533693,
+          "top_right_x": 8.533693,
+          "top_right_y": 8.533693,
+          "bottom_right_x": 17.067387,
+          "bottom_right_y": 17.067387,
+          "bottom_left_x": 17.067387,
+          "bottom_left_y": 17.067387
         },
         {
-          "top_left_x": 3.260561,
-          "top_left_y": 3.260561,
-          "top_right_x": 3.260561,
-          "top_right_y": 3.260561,
-          "bottom_right_x": 6.521122,
-          "bottom_right_y": 6.521122,
-          "bottom_left_x": 6.521122,
-          "bottom_left_y": 6.521122
+          "top_left_x": 6.5919456,
+          "top_left_y": 6.5919456,
+          "top_right_x": 6.5919456,
+          "top_right_y": 6.5919456,
+          "bottom_right_x": 13.183891,
+          "bottom_right_y": 13.183891,
+          "bottom_left_x": 13.183891,
+          "bottom_left_y": 13.183891
         },
         {
-          "top_left_x": 2.0915751,
-          "top_left_y": 2.0915751,
-          "top_right_x": 2.0915751,
-          "top_right_y": 2.0915751,
-          "bottom_right_x": 4.1831503,
-          "bottom_right_y": 4.1831503,
-          "bottom_left_x": 4.1831503,
-          "bottom_left_y": 4.1831503
+          "top_left_x": 3.6674318,
+          "top_left_y": 3.6674318,
+          "top_right_x": 3.6674318,
+          "top_right_y": 3.6674318,
+          "bottom_right_x": 7.3348637,
+          "bottom_right_y": 7.3348637,
+          "bottom_left_x": 7.3348637,
+          "bottom_left_y": 7.3348637
         },
         {
-          "top_left_x": 1.4640827,
-          "top_left_y": 1.4640827,
-          "top_right_x": 1.4640827,
-          "top_right_y": 1.4640827,
-          "bottom_right_x": 2.9281654,
-          "bottom_right_y": 2.9281654,
-          "bottom_left_x": 2.9281654,
-          "bottom_left_y": 2.9281654
+          "top_left_x": 2.4832253,
+          "top_left_y": 2.4832253,
+          "top_right_x": 2.4832253,
+          "top_right_y": 2.4832253,
+          "bottom_right_x": 4.9664507,
+          "bottom_right_y": 4.9664507,
+          "bottom_left_x": 4.9664507,
+          "bottom_left_y": 4.9664507
         },
         {
-          "top_left_x": 1.057313,
-          "top_left_y": 1.057313,
-          "top_right_x": 1.057313,
-          "top_right_y": 1.057313,
-          "bottom_right_x": 2.114626,
-          "bottom_right_y": 2.114626,
-          "bottom_left_x": 2.114626,
-          "bottom_left_y": 2.114626
+          "top_left_x": 1.8252907,
+          "top_left_y": 1.8252907,
+          "top_right_x": 1.8252907,
+          "top_right_y": 1.8252907,
+          "bottom_right_x": 3.6505814,
+          "bottom_right_y": 3.6505814,
+          "bottom_left_x": 3.6505814,
+          "bottom_left_y": 3.6505814
         },
         {
-          "top_left_x": 0.7824335,
-          "top_left_y": 0.7824335,
-          "top_right_x": 0.7824335,
-          "top_right_y": 0.7824335,
-          "bottom_right_x": 1.564867,
-          "bottom_right_y": 1.564867,
-          "bottom_left_x": 1.564867,
-          "bottom_left_y": 1.564867
+          "top_left_x": 1.4077549,
+          "top_left_y": 1.4077549,
+          "top_right_x": 1.4077549,
+          "top_right_y": 1.4077549,
+          "bottom_right_x": 2.8155098,
+          "bottom_right_y": 2.8155098,
+          "bottom_left_x": 2.8155098,
+          "bottom_left_y": 2.8155098
         },
         {
-          "top_left_x": 0.5863056,
-          "top_left_y": 0.5863056,
-          "top_right_x": 0.5863056,
-          "top_right_y": 0.5863056,
-          "bottom_right_x": 1.1726112,
-          "bottom_right_y": 1.1726112,
-          "bottom_left_x": 1.1726112,
-          "bottom_left_y": 1.1726112
+          "top_left_x": 1.1067667,
+          "top_left_y": 1.1067667,
+          "top_right_x": 1.1067667,
+          "top_right_y": 1.1067667,
+          "bottom_right_x": 2.2135334,
+          "bottom_right_y": 2.2135334,
+          "bottom_left_x": 2.2135334,
+          "bottom_left_y": 2.2135334
         },
         {
-          "top_left_x": 0.4332962,
-          "top_left_y": 0.4332962,
-          "top_right_x": 0.4332962,
-          "top_right_y": 0.4332962,
-          "bottom_right_x": 0.8665924,
-          "bottom_right_y": 0.8665924,
-          "bottom_left_x": 0.8665924,
-          "bottom_left_y": 0.8665924
+          "top_left_x": 0.88593864,
+          "top_left_y": 0.88593864,
+          "top_right_x": 0.88593864,
+          "top_right_y": 0.88593864,
+          "bottom_right_x": 1.7718773,
+          "bottom_right_y": 1.7718773,
+          "bottom_left_x": 1.7718773,
+          "bottom_left_y": 1.7718773
         },
         {
-          "top_left_x": 0.3145876,
-          "top_left_y": 0.3145876,
-          "top_right_x": 0.3145876,
-          "top_right_y": 0.3145876,
-          "bottom_right_x": 0.6291752,
-          "bottom_right_y": 0.6291752,
-          "bottom_left_x": 0.6291752,
-          "bottom_left_y": 0.6291752
+          "top_left_x": 0.7069988,
+          "top_left_y": 0.7069988,
+          "top_right_x": 0.7069988,
+          "top_right_y": 0.7069988,
+          "bottom_right_x": 1.4139977,
+          "bottom_right_y": 1.4139977,
+          "bottom_left_x": 1.4139977,
+          "bottom_left_y": 1.4139977
         },
         {
-          "top_left_x": 0.22506618,
-          "top_left_y": 0.22506618,
-          "top_right_x": 0.22506618,
-          "top_right_y": 0.22506618,
-          "bottom_right_x": 0.45013237,
-          "bottom_right_y": 0.45013237,
-          "bottom_left_x": 0.45013237,
-          "bottom_left_y": 0.45013237
+          "top_left_x": 0.55613136,
+          "top_left_y": 0.55613136,
+          "top_right_x": 0.55613136,
+          "top_right_y": 0.55613136,
+          "bottom_right_x": 1.1122627,
+          "bottom_right_y": 1.1122627,
+          "bottom_left_x": 1.1122627,
+          "bottom_left_y": 1.1122627
         },
         {
-          "top_left_x": 0.15591621,
-          "top_left_y": 0.15591621,
-          "top_right_x": 0.15591621,
-          "top_right_y": 0.15591621,
-          "bottom_right_x": 0.31183243,
-          "bottom_right_y": 0.31183243,
-          "bottom_left_x": 0.31183243,
-          "bottom_left_y": 0.31183243
+          "top_left_x": 0.44889355,
+          "top_left_y": 0.44889355,
+          "top_right_x": 0.44889355,
+          "top_right_y": 0.44889355,
+          "bottom_right_x": 0.8977871,
+          "bottom_right_y": 0.8977871,
+          "bottom_left_x": 0.8977871,
+          "bottom_left_y": 0.8977871
         },
         {
-          "top_left_x": 0.100948334,
-          "top_left_y": 0.100948334,
-          "top_right_x": 0.100948334,
-          "top_right_y": 0.100948334,
-          "bottom_right_x": 0.20189667,
-          "bottom_right_y": 0.20189667,
-          "bottom_left_x": 0.20189667,
-          "bottom_left_y": 0.20189667
+          "top_left_x": 0.34557533,
+          "top_left_y": 0.34557533,
+          "top_right_x": 0.34557533,
+          "top_right_y": 0.34557533,
+          "bottom_right_x": 0.69115067,
+          "bottom_right_y": 0.69115067,
+          "bottom_left_x": 0.69115067,
+          "bottom_left_y": 0.69115067
         },
         {
-          "top_left_x": 0.06496239,
-          "top_left_y": 0.06496239,
-          "top_right_x": 0.06496239,
-          "top_right_y": 0.06496239,
-          "bottom_right_x": 0.12992477,
-          "bottom_right_y": 0.12992477,
-          "bottom_left_x": 0.12992477,
-          "bottom_left_y": 0.12992477
+          "top_left_x": 0.27671337,
+          "top_left_y": 0.27671337,
+          "top_right_x": 0.27671337,
+          "top_right_y": 0.27671337,
+          "bottom_right_x": 0.55342674,
+          "bottom_right_y": 0.55342674,
+          "bottom_left_x": 0.55342674,
+          "bottom_left_y": 0.55342674
         },
         {
-          "top_left_x": 0.03526497,
-          "top_left_y": 0.03526497,
-          "top_right_x": 0.03526497,
-          "top_right_y": 0.03526497,
-          "bottom_right_x": 0.07052994,
-          "bottom_right_y": 0.07052994,
-          "bottom_left_x": 0.07052994,
-          "bottom_left_y": 0.07052994
+          "top_left_x": 0.20785141,
+          "top_left_y": 0.20785141,
+          "top_right_x": 0.20785141,
+          "top_right_y": 0.20785141,
+          "bottom_right_x": 0.41570282,
+          "bottom_right_y": 0.41570282,
+          "bottom_left_x": 0.41570282,
+          "bottom_left_y": 0.41570282
         },
         {
-          "top_left_x": 0.014661789,
-          "top_left_y": 0.014661789,
-          "top_right_x": 0.014661789,
-          "top_right_y": 0.014661789,
-          "bottom_right_x": 0.029323578,
-          "bottom_right_y": 0.029323578,
-          "bottom_left_x": 0.029323578,
-          "bottom_left_y": 0.029323578
+          "top_left_x": 0.1601448,
+          "top_left_y": 0.1601448,
+          "top_right_x": 0.1601448,
+          "top_right_y": 0.1601448,
+          "bottom_right_x": 0.3202896,
+          "bottom_right_y": 0.3202896,
+          "bottom_left_x": 0.3202896,
+          "bottom_left_y": 0.3202896
         },
         {
-          "top_left_x": 0.0041856766,
-          "top_left_y": 0.0041856766,
-          "top_right_x": 0.0041856766,
-          "top_right_y": 0.0041856766,
-          "bottom_right_x": 0.008371353,
-          "bottom_right_y": 0.008371353,
-          "bottom_left_x": 0.008371353,
-          "bottom_left_y": 0.008371353
+          "top_left_x": 0.117860794,
+          "top_left_y": 0.117860794,
+          "top_right_x": 0.117860794,
+          "top_right_y": 0.117860794,
+          "bottom_right_x": 0.23572159,
+          "bottom_right_y": 0.23572159,
+          "bottom_left_x": 0.23572159,
+          "bottom_left_y": 0.23572159
+        },
+        {
+          "top_left_x": 0.08036041,
+          "top_left_y": 0.08036041,
+          "top_right_x": 0.08036041,
+          "top_right_y": 0.08036041,
+          "bottom_right_x": 0.16072083,
+          "bottom_right_y": 0.16072083,
+          "bottom_left_x": 0.16072083,
+          "bottom_left_y": 0.16072083
+        },
+        {
+          "top_left_x": 0.05836296,
+          "top_left_y": 0.05836296,
+          "top_right_x": 0.05836296,
+          "top_right_y": 0.05836296,
+          "bottom_right_x": 0.11672592,
+          "bottom_right_y": 0.11672592,
+          "bottom_left_x": 0.11672592,
+          "bottom_left_y": 0.11672592
+        },
+        {
+          "top_left_x": 0.03636551,
+          "top_left_y": 0.03636551,
+          "top_right_x": 0.03636551,
+          "top_right_y": 0.03636551,
+          "bottom_right_x": 0.07273102,
+          "bottom_right_y": 0.07273102,
+          "bottom_left_x": 0.07273102,
+          "bottom_left_y": 0.07273102
+        },
+        {
+          "top_left_x": 0.018137932,
+          "top_left_y": 0.018137932,
+          "top_right_x": 0.018137932,
+          "top_right_y": 0.018137932,
+          "bottom_right_x": 0.036275864,
+          "bottom_right_y": 0.036275864,
+          "bottom_left_x": 0.036275864,
+          "bottom_left_y": 0.036275864
+        },
+        {
+          "top_left_x": 0.0082063675,
+          "top_left_y": 0.0082063675,
+          "top_right_x": 0.0082063675,
+          "top_right_y": 0.0082063675,
+          "bottom_right_x": 0.016412735,
+          "bottom_right_y": 0.016412735,
+          "bottom_left_x": 0.016412735,
+          "bottom_left_y": 0.016412735
+        },
+        {
+          "top_left_x": 0.0031013489,
+          "top_left_y": 0.0031013489,
+          "top_right_x": 0.0031013489,
+          "top_right_y": 0.0031013489,
+          "bottom_right_x": 0.0062026978,
+          "bottom_right_y": 0.0062026978,
+          "bottom_left_x": 0.0062026978,
+          "bottom_left_y": 0.0062026978
         },
         {
           "top_left_x": 0,
@@ -366,20 +460,25 @@
       "name": "alpha",
       "type": "int",
       "data_points": [
+        255,
+        255,
+        255,
+        255,
+        255,
+        255,
+        255,
+        255,
+        233,
+        191,
+        153,
+        117,
+        85,
+        57,
+        33,
+        14,
+        3,
         0,
-        255,
-        255,
-        255,
-        255,
-        255,
-        255,
-        239,
-        183,
-        135,
-        91,
-        53,
-        23,
-        5,
+        0,
         0,
         0,
         0,
diff --git a/packages/SystemUI/tests/goldens/backgroundAnimationWithoutFade_whenReturning_withSpring.json b/packages/SystemUI/tests/goldens/backgroundAnimationWithoutFade_whenReturning_withSpring.json
new file mode 100644
index 0000000..18eedd4
--- /dev/null
+++ b/packages/SystemUI/tests/goldens/backgroundAnimationWithoutFade_whenReturning_withSpring.json
@@ -0,0 +1,375 @@
+{
+  "frame_ids": [
+    0,
+    16,
+    32,
+    48,
+    64,
+    80,
+    96,
+    112,
+    128,
+    144,
+    160,
+    176,
+    192,
+    208,
+    224,
+    240,
+    256,
+    272,
+    288,
+    304
+  ],
+  "features": [
+    {
+      "name": "bounds",
+      "type": "rect",
+      "data_points": [
+        {
+          "left": 0,
+          "top": 0,
+          "right": 0,
+          "bottom": 0
+        },
+        {
+          "left": 94,
+          "top": 284,
+          "right": 206,
+          "bottom": 414
+        },
+        {
+          "left": 83,
+          "top": 251,
+          "right": 219,
+          "bottom": 447
+        },
+        {
+          "left": 70,
+          "top": 212,
+          "right": 234,
+          "bottom": 485
+        },
+        {
+          "left": 57,
+          "top": 173,
+          "right": 250,
+          "bottom": 522
+        },
+        {
+          "left": 46,
+          "top": 139,
+          "right": 264,
+          "bottom": 555
+        },
+        {
+          "left": 36,
+          "top": 109,
+          "right": 276,
+          "bottom": 584
+        },
+        {
+          "left": 28,
+          "top": 84,
+          "right": 285,
+          "bottom": 608
+        },
+        {
+          "left": 21,
+          "top": 65,
+          "right": 293,
+          "bottom": 627
+        },
+        {
+          "left": 16,
+          "top": 49,
+          "right": 300,
+          "bottom": 642
+        },
+        {
+          "left": 12,
+          "top": 36,
+          "right": 305,
+          "bottom": 653
+        },
+        {
+          "left": 9,
+          "top": 27,
+          "right": 308,
+          "bottom": 662
+        },
+        {
+          "left": 7,
+          "top": 20,
+          "right": 312,
+          "bottom": 669
+        },
+        {
+          "left": 5,
+          "top": 14,
+          "right": 314,
+          "bottom": 675
+        },
+        {
+          "left": 4,
+          "top": 11,
+          "right": 315,
+          "bottom": 678
+        },
+        {
+          "left": 3,
+          "top": 8,
+          "right": 316,
+          "bottom": 681
+        },
+        {
+          "left": 2,
+          "top": 5,
+          "right": 317,
+          "bottom": 684
+        },
+        {
+          "left": 1,
+          "top": 4,
+          "right": 318,
+          "bottom": 685
+        },
+        {
+          "left": 1,
+          "top": 3,
+          "right": 318,
+          "bottom": 686
+        },
+        {
+          "left": 0,
+          "top": 2,
+          "right": 319,
+          "bottom": 687
+        }
+      ]
+    },
+    {
+      "name": "corner_radii",
+      "type": "cornerRadii",
+      "data_points": [
+        null,
+        {
+          "top_left_x": 9.492916,
+          "top_left_y": 9.492916,
+          "top_right_x": 9.492916,
+          "top_right_y": 9.492916,
+          "bottom_right_x": 18.985832,
+          "bottom_right_y": 18.985832,
+          "bottom_left_x": 18.985832,
+          "bottom_left_y": 18.985832
+        },
+        {
+          "top_left_x": 8.381761,
+          "top_left_y": 8.381761,
+          "top_right_x": 8.381761,
+          "top_right_y": 8.381761,
+          "bottom_right_x": 16.763521,
+          "bottom_right_y": 16.763521,
+          "bottom_left_x": 16.763521,
+          "bottom_left_y": 16.763521
+        },
+        {
+          "top_left_x": 7.07397,
+          "top_left_y": 7.07397,
+          "top_right_x": 7.07397,
+          "top_right_y": 7.07397,
+          "bottom_right_x": 14.14794,
+          "bottom_right_y": 14.14794,
+          "bottom_left_x": 14.14794,
+          "bottom_left_y": 14.14794
+        },
+        {
+          "top_left_x": 5.7880254,
+          "top_left_y": 5.7880254,
+          "top_right_x": 5.7880254,
+          "top_right_y": 5.7880254,
+          "bottom_right_x": 11.576051,
+          "bottom_right_y": 11.576051,
+          "bottom_left_x": 11.576051,
+          "bottom_left_y": 11.576051
+        },
+        {
+          "top_left_x": 4.6295347,
+          "top_left_y": 4.6295347,
+          "top_right_x": 4.6295347,
+          "top_right_y": 4.6295347,
+          "bottom_right_x": 9.259069,
+          "bottom_right_y": 9.259069,
+          "bottom_left_x": 9.259069,
+          "bottom_left_y": 9.259069
+        },
+        {
+          "top_left_x": 3.638935,
+          "top_left_y": 3.638935,
+          "top_right_x": 3.638935,
+          "top_right_y": 3.638935,
+          "bottom_right_x": 7.27787,
+          "bottom_right_y": 7.27787,
+          "bottom_left_x": 7.27787,
+          "bottom_left_y": 7.27787
+        },
+        {
+          "top_left_x": 2.8209057,
+          "top_left_y": 2.8209057,
+          "top_right_x": 2.8209057,
+          "top_right_y": 2.8209057,
+          "bottom_right_x": 5.6418114,
+          "bottom_right_y": 5.6418114,
+          "bottom_left_x": 5.6418114,
+          "bottom_left_y": 5.6418114
+        },
+        {
+          "top_left_x": 2.1620893,
+          "top_left_y": 2.1620893,
+          "top_right_x": 2.1620893,
+          "top_right_y": 2.1620893,
+          "bottom_right_x": 4.3241787,
+          "bottom_right_y": 4.3241787,
+          "bottom_left_x": 4.3241787,
+          "bottom_left_y": 4.3241787
+        },
+        {
+          "top_left_x": 1.6414614,
+          "top_left_y": 1.6414614,
+          "top_right_x": 1.6414614,
+          "top_right_y": 1.6414614,
+          "bottom_right_x": 3.2829227,
+          "bottom_right_y": 3.2829227,
+          "bottom_left_x": 3.2829227,
+          "bottom_left_y": 3.2829227
+        },
+        {
+          "top_left_x": 1.2361269,
+          "top_left_y": 1.2361269,
+          "top_right_x": 1.2361269,
+          "top_right_y": 1.2361269,
+          "bottom_right_x": 2.4722538,
+          "bottom_right_y": 2.4722538,
+          "bottom_left_x": 2.4722538,
+          "bottom_left_y": 2.4722538
+        },
+        {
+          "top_left_x": 0.92435074,
+          "top_left_y": 0.92435074,
+          "top_right_x": 0.92435074,
+          "top_right_y": 0.92435074,
+          "bottom_right_x": 1.8487015,
+          "bottom_right_y": 1.8487015,
+          "bottom_left_x": 1.8487015,
+          "bottom_left_y": 1.8487015
+        },
+        {
+          "top_left_x": 0.68693924,
+          "top_left_y": 0.68693924,
+          "top_right_x": 0.68693924,
+          "top_right_y": 0.68693924,
+          "bottom_right_x": 1.3738785,
+          "bottom_right_y": 1.3738785,
+          "bottom_left_x": 1.3738785,
+          "bottom_left_y": 1.3738785
+        },
+        {
+          "top_left_x": 0.5076904,
+          "top_left_y": 0.5076904,
+          "top_right_x": 0.5076904,
+          "top_right_y": 0.5076904,
+          "bottom_right_x": 1.0153809,
+          "bottom_right_y": 1.0153809,
+          "bottom_left_x": 1.0153809,
+          "bottom_left_y": 1.0153809
+        },
+        {
+          "top_left_x": 0.3733511,
+          "top_left_y": 0.3733511,
+          "top_right_x": 0.3733511,
+          "top_right_y": 0.3733511,
+          "bottom_right_x": 0.7467022,
+          "bottom_right_y": 0.7467022,
+          "bottom_left_x": 0.7467022,
+          "bottom_left_y": 0.7467022
+        },
+        {
+          "top_left_x": 0.27331638,
+          "top_left_y": 0.27331638,
+          "top_right_x": 0.27331638,
+          "top_right_y": 0.27331638,
+          "bottom_right_x": 0.54663277,
+          "bottom_right_y": 0.54663277,
+          "bottom_left_x": 0.54663277,
+          "bottom_left_y": 0.54663277
+        },
+        {
+          "top_left_x": 0.19925308,
+          "top_left_y": 0.19925308,
+          "top_right_x": 0.19925308,
+          "top_right_y": 0.19925308,
+          "bottom_right_x": 0.39850616,
+          "bottom_right_y": 0.39850616,
+          "bottom_left_x": 0.39850616,
+          "bottom_left_y": 0.39850616
+        },
+        {
+          "top_left_x": 0.14470005,
+          "top_left_y": 0.14470005,
+          "top_right_x": 0.14470005,
+          "top_right_y": 0.14470005,
+          "bottom_right_x": 0.2894001,
+          "bottom_right_y": 0.2894001,
+          "bottom_left_x": 0.2894001,
+          "bottom_left_y": 0.2894001
+        },
+        {
+          "top_left_x": 0.10470486,
+          "top_left_y": 0.10470486,
+          "top_right_x": 0.10470486,
+          "top_right_y": 0.10470486,
+          "bottom_right_x": 0.20940971,
+          "bottom_right_y": 0.20940971,
+          "bottom_left_x": 0.20940971,
+          "bottom_left_y": 0.20940971
+        },
+        {
+          "top_left_x": 0.07550812,
+          "top_left_y": 0.07550812,
+          "top_right_x": 0.07550812,
+          "top_right_y": 0.07550812,
+          "bottom_right_x": 0.15101624,
+          "bottom_right_y": 0.15101624,
+          "bottom_left_x": 0.15101624,
+          "bottom_left_y": 0.15101624
+        }
+      ]
+    },
+    {
+      "name": "alpha",
+      "type": "int",
+      "data_points": [
+        0,
+        255,
+        255,
+        255,
+        255,
+        255,
+        255,
+        255,
+        255,
+        255,
+        249,
+        226,
+        192,
+        153,
+        112,
+        72,
+        34,
+        0,
+        0,
+        0
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/goldens/backgroundAnimation_whenLaunching.json b/packages/SystemUI/tests/goldens/backgroundAnimation_whenLaunching.json
index 608e633..aa80445 100644
--- a/packages/SystemUI/tests/goldens/backgroundAnimation_whenLaunching.json
+++ b/packages/SystemUI/tests/goldens/backgroundAnimation_whenLaunching.json
@@ -1,25 +1,30 @@
 {
   "frame_ids": [
-    "before",
     0,
-    26,
-    52,
-    78,
-    105,
-    131,
-    157,
-    184,
-    210,
-    236,
-    263,
-    289,
-    315,
-    342,
-    368,
-    394,
-    421,
-    447,
-    473,
+    20,
+    40,
+    60,
+    80,
+    100,
+    120,
+    140,
+    160,
+    180,
+    200,
+    220,
+    240,
+    260,
+    280,
+    300,
+    320,
+    340,
+    360,
+    380,
+    400,
+    420,
+    440,
+    460,
+    480,
     500
   ],
   "features": [
@@ -28,70 +33,82 @@
       "type": "rect",
       "data_points": [
         {
-          "left": 0,
-          "top": 0,
-          "right": 0,
-          "bottom": 0
-        },
-        {
           "left": 100,
           "top": 300,
           "right": 200,
           "bottom": 400
         },
         {
-          "left": 98,
-          "top": 293,
-          "right": 203,
-          "bottom": 407
+          "left": 99,
+          "top": 296,
+          "right": 202,
+          "bottom": 404
         },
         {
-          "left": 91,
-          "top": 269,
-          "right": 213,
-          "bottom": 430
+          "left": 95,
+          "top": 283,
+          "right": 207,
+          "bottom": 417
         },
         {
-          "left": 71,
-          "top": 206,
-          "right": 240,
-          "bottom": 491
+          "left": 86,
+          "top": 256,
+          "right": 219,
+          "bottom": 443
         },
         {
-          "left": 34,
-          "top": 98,
-          "right": 283,
-          "bottom": 595
+          "left": 68,
+          "top": 198,
+          "right": 243,
+          "bottom": 499
         },
         {
-          "left": 22,
-          "top": 63,
-          "right": 296,
-          "bottom": 629
+          "left": 39,
+          "top": 110,
+          "right": 278,
+          "bottom": 584
+        },
+        {
+          "left": 26,
+          "top": 74,
+          "right": 292,
+          "bottom": 618
+        },
+        {
+          "left": 19,
+          "top": 55,
+          "right": 299,
+          "bottom": 637
         },
         {
           "left": 15,
-          "top": 44,
-          "right": 303,
-          "bottom": 648
+          "top": 42,
+          "right": 304,
+          "bottom": 649
         },
         {
-          "left": 11,
-          "top": 32,
-          "right": 308,
-          "bottom": 659
+          "left": 12,
+          "top": 33,
+          "right": 307,
+          "bottom": 658
         },
         {
-          "left": 8,
-          "top": 23,
-          "right": 311,
-          "bottom": 667
+          "left": 9,
+          "top": 27,
+          "right": 310,
+          "bottom": 664
+        },
+        {
+          "left": 7,
+          "top": 21,
+          "right": 312,
+          "bottom": 669
         },
         {
           "left": 6,
-          "top": 18,
-          "right": 313,
-          "bottom": 673
+          "top": 17,
+          "right": 314,
+          "bottom": 674
         },
         {
           "left": 5,
@@ -100,16 +117,22 @@
           "bottom": 677
         },
         {
-          "left": 3,
-          "top": 9,
+          "left": 4,
+          "top": 10,
           "right": 316,
-          "bottom": 681
+          "bottom": 680
+        },
+        {
+          "left": 3,
+          "top": 8,
+          "right": 317,
+          "bottom": 682
         },
         {
           "left": 2,
-          "top": 7,
-          "right": 317,
-          "bottom": 683
+          "top": 6,
+          "right": 318,
+          "bottom": 684
         },
         {
           "left": 2,
@@ -119,7 +142,7 @@
         },
         {
           "left": 1,
-          "top": 3,
+          "top": 4,
           "right": 319,
           "bottom": 687
         },
@@ -130,6 +153,18 @@
           "bottom": 688
         },
         {
+          "left": 1,
+          "top": 2,
+          "right": 319,
+          "bottom": 688
+        },
+        {
+          "left": 0,
+          "top": 1,
+          "right": 320,
+          "bottom": 689
+        },
+        {
           "left": 0,
           "top": 1,
           "right": 320,
@@ -159,7 +194,6 @@
       "name": "corner_radii",
       "type": "cornerRadii",
       "data_points": [
-        null,
         {
           "top_left_x": 10,
           "top_left_y": 10,
@@ -171,184 +205,244 @@
           "bottom_left_y": 20
         },
         {
-          "top_left_x": 9.762664,
-          "top_left_y": 9.762664,
-          "top_right_x": 9.762664,
-          "top_right_y": 9.762664,
-          "bottom_right_x": 19.525328,
-          "bottom_right_y": 19.525328,
-          "bottom_left_x": 19.525328,
-          "bottom_left_y": 19.525328
+          "top_left_x": 9.865689,
+          "top_left_y": 9.865689,
+          "top_right_x": 9.865689,
+          "top_right_y": 9.865689,
+          "bottom_right_x": 19.731379,
+          "bottom_right_y": 19.731379,
+          "bottom_left_x": 19.731379,
+          "bottom_left_y": 19.731379
         },
         {
-          "top_left_x": 8.969244,
-          "top_left_y": 8.969244,
-          "top_right_x": 8.969244,
-          "top_right_y": 8.969244,
-          "bottom_right_x": 17.938488,
-          "bottom_right_y": 17.938488,
-          "bottom_left_x": 17.938488,
-          "bottom_left_y": 17.938488
+          "top_left_x": 9.419104,
+          "top_left_y": 9.419104,
+          "top_right_x": 9.419104,
+          "top_right_y": 9.419104,
+          "bottom_right_x": 18.838207,
+          "bottom_right_y": 18.838207,
+          "bottom_left_x": 18.838207,
+          "bottom_left_y": 18.838207
         },
         {
-          "top_left_x": 6.8709626,
-          "top_left_y": 6.8709626,
-          "top_right_x": 6.8709626,
-          "top_right_y": 6.8709626,
-          "bottom_right_x": 13.741925,
-          "bottom_right_y": 13.741925,
-          "bottom_left_x": 13.741925,
-          "bottom_left_y": 13.741925
+          "top_left_x": 8.533693,
+          "top_left_y": 8.533693,
+          "top_right_x": 8.533693,
+          "top_right_y": 8.533693,
+          "bottom_right_x": 17.067387,
+          "bottom_right_y": 17.067387,
+          "bottom_left_x": 17.067387,
+          "bottom_left_y": 17.067387
         },
         {
-          "top_left_x": 3.260561,
-          "top_left_y": 3.260561,
-          "top_right_x": 3.260561,
-          "top_right_y": 3.260561,
-          "bottom_right_x": 6.521122,
-          "bottom_right_y": 6.521122,
-          "bottom_left_x": 6.521122,
-          "bottom_left_y": 6.521122
+          "top_left_x": 6.5919456,
+          "top_left_y": 6.5919456,
+          "top_right_x": 6.5919456,
+          "top_right_y": 6.5919456,
+          "bottom_right_x": 13.183891,
+          "bottom_right_y": 13.183891,
+          "bottom_left_x": 13.183891,
+          "bottom_left_y": 13.183891
         },
         {
-          "top_left_x": 2.0915751,
-          "top_left_y": 2.0915751,
-          "top_right_x": 2.0915751,
-          "top_right_y": 2.0915751,
-          "bottom_right_x": 4.1831503,
-          "bottom_right_y": 4.1831503,
-          "bottom_left_x": 4.1831503,
-          "bottom_left_y": 4.1831503
+          "top_left_x": 3.6674318,
+          "top_left_y": 3.6674318,
+          "top_right_x": 3.6674318,
+          "top_right_y": 3.6674318,
+          "bottom_right_x": 7.3348637,
+          "bottom_right_y": 7.3348637,
+          "bottom_left_x": 7.3348637,
+          "bottom_left_y": 7.3348637
         },
         {
-          "top_left_x": 1.4640827,
-          "top_left_y": 1.4640827,
-          "top_right_x": 1.4640827,
-          "top_right_y": 1.4640827,
-          "bottom_right_x": 2.9281654,
-          "bottom_right_y": 2.9281654,
-          "bottom_left_x": 2.9281654,
-          "bottom_left_y": 2.9281654
+          "top_left_x": 2.4832253,
+          "top_left_y": 2.4832253,
+          "top_right_x": 2.4832253,
+          "top_right_y": 2.4832253,
+          "bottom_right_x": 4.9664507,
+          "bottom_right_y": 4.9664507,
+          "bottom_left_x": 4.9664507,
+          "bottom_left_y": 4.9664507
         },
         {
-          "top_left_x": 1.057313,
-          "top_left_y": 1.057313,
-          "top_right_x": 1.057313,
-          "top_right_y": 1.057313,
-          "bottom_right_x": 2.114626,
-          "bottom_right_y": 2.114626,
-          "bottom_left_x": 2.114626,
-          "bottom_left_y": 2.114626
+          "top_left_x": 1.8252907,
+          "top_left_y": 1.8252907,
+          "top_right_x": 1.8252907,
+          "top_right_y": 1.8252907,
+          "bottom_right_x": 3.6505814,
+          "bottom_right_y": 3.6505814,
+          "bottom_left_x": 3.6505814,
+          "bottom_left_y": 3.6505814
         },
         {
-          "top_left_x": 0.7824335,
-          "top_left_y": 0.7824335,
-          "top_right_x": 0.7824335,
-          "top_right_y": 0.7824335,
-          "bottom_right_x": 1.564867,
-          "bottom_right_y": 1.564867,
-          "bottom_left_x": 1.564867,
-          "bottom_left_y": 1.564867
+          "top_left_x": 1.4077549,
+          "top_left_y": 1.4077549,
+          "top_right_x": 1.4077549,
+          "top_right_y": 1.4077549,
+          "bottom_right_x": 2.8155098,
+          "bottom_right_y": 2.8155098,
+          "bottom_left_x": 2.8155098,
+          "bottom_left_y": 2.8155098
         },
         {
-          "top_left_x": 0.5863056,
-          "top_left_y": 0.5863056,
-          "top_right_x": 0.5863056,
-          "top_right_y": 0.5863056,
-          "bottom_right_x": 1.1726112,
-          "bottom_right_y": 1.1726112,
-          "bottom_left_x": 1.1726112,
-          "bottom_left_y": 1.1726112
+          "top_left_x": 1.1067667,
+          "top_left_y": 1.1067667,
+          "top_right_x": 1.1067667,
+          "top_right_y": 1.1067667,
+          "bottom_right_x": 2.2135334,
+          "bottom_right_y": 2.2135334,
+          "bottom_left_x": 2.2135334,
+          "bottom_left_y": 2.2135334
         },
         {
-          "top_left_x": 0.4332962,
-          "top_left_y": 0.4332962,
-          "top_right_x": 0.4332962,
-          "top_right_y": 0.4332962,
-          "bottom_right_x": 0.8665924,
-          "bottom_right_y": 0.8665924,
-          "bottom_left_x": 0.8665924,
-          "bottom_left_y": 0.8665924
+          "top_left_x": 0.88593864,
+          "top_left_y": 0.88593864,
+          "top_right_x": 0.88593864,
+          "top_right_y": 0.88593864,
+          "bottom_right_x": 1.7718773,
+          "bottom_right_y": 1.7718773,
+          "bottom_left_x": 1.7718773,
+          "bottom_left_y": 1.7718773
         },
         {
-          "top_left_x": 0.3145876,
-          "top_left_y": 0.3145876,
-          "top_right_x": 0.3145876,
-          "top_right_y": 0.3145876,
-          "bottom_right_x": 0.6291752,
-          "bottom_right_y": 0.6291752,
-          "bottom_left_x": 0.6291752,
-          "bottom_left_y": 0.6291752
+          "top_left_x": 0.7069988,
+          "top_left_y": 0.7069988,
+          "top_right_x": 0.7069988,
+          "top_right_y": 0.7069988,
+          "bottom_right_x": 1.4139977,
+          "bottom_right_y": 1.4139977,
+          "bottom_left_x": 1.4139977,
+          "bottom_left_y": 1.4139977
         },
         {
-          "top_left_x": 0.22506618,
-          "top_left_y": 0.22506618,
-          "top_right_x": 0.22506618,
-          "top_right_y": 0.22506618,
-          "bottom_right_x": 0.45013237,
-          "bottom_right_y": 0.45013237,
-          "bottom_left_x": 0.45013237,
-          "bottom_left_y": 0.45013237
+          "top_left_x": 0.55613136,
+          "top_left_y": 0.55613136,
+          "top_right_x": 0.55613136,
+          "top_right_y": 0.55613136,
+          "bottom_right_x": 1.1122627,
+          "bottom_right_y": 1.1122627,
+          "bottom_left_x": 1.1122627,
+          "bottom_left_y": 1.1122627
         },
         {
-          "top_left_x": 0.15591621,
-          "top_left_y": 0.15591621,
-          "top_right_x": 0.15591621,
-          "top_right_y": 0.15591621,
-          "bottom_right_x": 0.31183243,
-          "bottom_right_y": 0.31183243,
-          "bottom_left_x": 0.31183243,
-          "bottom_left_y": 0.31183243
+          "top_left_x": 0.44889355,
+          "top_left_y": 0.44889355,
+          "top_right_x": 0.44889355,
+          "top_right_y": 0.44889355,
+          "bottom_right_x": 0.8977871,
+          "bottom_right_y": 0.8977871,
+          "bottom_left_x": 0.8977871,
+          "bottom_left_y": 0.8977871
         },
         {
-          "top_left_x": 0.100948334,
-          "top_left_y": 0.100948334,
-          "top_right_x": 0.100948334,
-          "top_right_y": 0.100948334,
-          "bottom_right_x": 0.20189667,
-          "bottom_right_y": 0.20189667,
-          "bottom_left_x": 0.20189667,
-          "bottom_left_y": 0.20189667
+          "top_left_x": 0.34557533,
+          "top_left_y": 0.34557533,
+          "top_right_x": 0.34557533,
+          "top_right_y": 0.34557533,
+          "bottom_right_x": 0.69115067,
+          "bottom_right_y": 0.69115067,
+          "bottom_left_x": 0.69115067,
+          "bottom_left_y": 0.69115067
         },
         {
-          "top_left_x": 0.06496239,
-          "top_left_y": 0.06496239,
-          "top_right_x": 0.06496239,
-          "top_right_y": 0.06496239,
-          "bottom_right_x": 0.12992477,
-          "bottom_right_y": 0.12992477,
-          "bottom_left_x": 0.12992477,
-          "bottom_left_y": 0.12992477
+          "top_left_x": 0.27671337,
+          "top_left_y": 0.27671337,
+          "top_right_x": 0.27671337,
+          "top_right_y": 0.27671337,
+          "bottom_right_x": 0.55342674,
+          "bottom_right_y": 0.55342674,
+          "bottom_left_x": 0.55342674,
+          "bottom_left_y": 0.55342674
         },
         {
-          "top_left_x": 0.03526497,
-          "top_left_y": 0.03526497,
-          "top_right_x": 0.03526497,
-          "top_right_y": 0.03526497,
-          "bottom_right_x": 0.07052994,
-          "bottom_right_y": 0.07052994,
-          "bottom_left_x": 0.07052994,
-          "bottom_left_y": 0.07052994
+          "top_left_x": 0.20785141,
+          "top_left_y": 0.20785141,
+          "top_right_x": 0.20785141,
+          "top_right_y": 0.20785141,
+          "bottom_right_x": 0.41570282,
+          "bottom_right_y": 0.41570282,
+          "bottom_left_x": 0.41570282,
+          "bottom_left_y": 0.41570282
         },
         {
-          "top_left_x": 0.014661789,
-          "top_left_y": 0.014661789,
-          "top_right_x": 0.014661789,
-          "top_right_y": 0.014661789,
-          "bottom_right_x": 0.029323578,
-          "bottom_right_y": 0.029323578,
-          "bottom_left_x": 0.029323578,
-          "bottom_left_y": 0.029323578
+          "top_left_x": 0.1601448,
+          "top_left_y": 0.1601448,
+          "top_right_x": 0.1601448,
+          "top_right_y": 0.1601448,
+          "bottom_right_x": 0.3202896,
+          "bottom_right_y": 0.3202896,
+          "bottom_left_x": 0.3202896,
+          "bottom_left_y": 0.3202896
         },
         {
-          "top_left_x": 0.0041856766,
-          "top_left_y": 0.0041856766,
-          "top_right_x": 0.0041856766,
-          "top_right_y": 0.0041856766,
-          "bottom_right_x": 0.008371353,
-          "bottom_right_y": 0.008371353,
-          "bottom_left_x": 0.008371353,
-          "bottom_left_y": 0.008371353
+          "top_left_x": 0.117860794,
+          "top_left_y": 0.117860794,
+          "top_right_x": 0.117860794,
+          "top_right_y": 0.117860794,
+          "bottom_right_x": 0.23572159,
+          "bottom_right_y": 0.23572159,
+          "bottom_left_x": 0.23572159,
+          "bottom_left_y": 0.23572159
+        },
+        {
+          "top_left_x": 0.08036041,
+          "top_left_y": 0.08036041,
+          "top_right_x": 0.08036041,
+          "top_right_y": 0.08036041,
+          "bottom_right_x": 0.16072083,
+          "bottom_right_y": 0.16072083,
+          "bottom_left_x": 0.16072083,
+          "bottom_left_y": 0.16072083
+        },
+        {
+          "top_left_x": 0.05836296,
+          "top_left_y": 0.05836296,
+          "top_right_x": 0.05836296,
+          "top_right_y": 0.05836296,
+          "bottom_right_x": 0.11672592,
+          "bottom_right_y": 0.11672592,
+          "bottom_left_x": 0.11672592,
+          "bottom_left_y": 0.11672592
+        },
+        {
+          "top_left_x": 0.03636551,
+          "top_left_y": 0.03636551,
+          "top_right_x": 0.03636551,
+          "top_right_y": 0.03636551,
+          "bottom_right_x": 0.07273102,
+          "bottom_right_y": 0.07273102,
+          "bottom_left_x": 0.07273102,
+          "bottom_left_y": 0.07273102
+        },
+        {
+          "top_left_x": 0.018137932,
+          "top_left_y": 0.018137932,
+          "top_right_x": 0.018137932,
+          "top_right_y": 0.018137932,
+          "bottom_right_x": 0.036275864,
+          "bottom_right_y": 0.036275864,
+          "bottom_left_x": 0.036275864,
+          "bottom_left_y": 0.036275864
+        },
+        {
+          "top_left_x": 0.0082063675,
+          "top_left_y": 0.0082063675,
+          "top_right_x": 0.0082063675,
+          "top_right_y": 0.0082063675,
+          "bottom_right_x": 0.016412735,
+          "bottom_right_y": 0.016412735,
+          "bottom_left_x": 0.016412735,
+          "bottom_left_y": 0.016412735
+        },
+        {
+          "top_left_x": 0.0031013489,
+          "top_left_y": 0.0031013489,
+          "top_right_x": 0.0031013489,
+          "top_right_y": 0.0031013489,
+          "bottom_right_x": 0.0062026978,
+          "bottom_right_y": 0.0062026978,
+          "bottom_left_x": 0.0062026978,
+          "bottom_left_y": 0.0062026978
         },
         {
           "top_left_x": 0,
@@ -367,19 +461,24 @@
       "type": "int",
       "data_points": [
         0,
+        96,
+        153,
+        192,
+        220,
+        238,
+        249,
+        254,
+        233,
+        191,
+        153,
+        117,
+        85,
+        57,
+        33,
+        14,
+        3,
         0,
-        115,
-        178,
-        217,
-        241,
-        253,
-        239,
-        183,
-        135,
-        91,
-        53,
-        23,
-        5,
+        0,
         0,
         0,
         0,
diff --git a/packages/SystemUI/tests/goldens/backgroundAnimation_whenLaunching_withSpring.json b/packages/SystemUI/tests/goldens/backgroundAnimation_whenLaunching_withSpring.json
new file mode 100644
index 0000000..a840d3c
--- /dev/null
+++ b/packages/SystemUI/tests/goldens/backgroundAnimation_whenLaunching_withSpring.json
@@ -0,0 +1,375 @@
+{
+  "frame_ids": [
+    0,
+    16,
+    32,
+    48,
+    64,
+    80,
+    96,
+    112,
+    128,
+    144,
+    160,
+    176,
+    192,
+    208,
+    224,
+    240,
+    256,
+    272,
+    288,
+    304
+  ],
+  "features": [
+    {
+      "name": "bounds",
+      "type": "rect",
+      "data_points": [
+        {
+          "left": 0,
+          "top": 0,
+          "right": 0,
+          "bottom": 0
+        },
+        {
+          "left": 94,
+          "top": 284,
+          "right": 206,
+          "bottom": 414
+        },
+        {
+          "left": 83,
+          "top": 251,
+          "right": 219,
+          "bottom": 447
+        },
+        {
+          "left": 70,
+          "top": 212,
+          "right": 234,
+          "bottom": 485
+        },
+        {
+          "left": 57,
+          "top": 173,
+          "right": 250,
+          "bottom": 522
+        },
+        {
+          "left": 46,
+          "top": 139,
+          "right": 264,
+          "bottom": 555
+        },
+        {
+          "left": 36,
+          "top": 109,
+          "right": 276,
+          "bottom": 584
+        },
+        {
+          "left": 28,
+          "top": 84,
+          "right": 285,
+          "bottom": 608
+        },
+        {
+          "left": 21,
+          "top": 65,
+          "right": 293,
+          "bottom": 627
+        },
+        {
+          "left": 16,
+          "top": 49,
+          "right": 300,
+          "bottom": 642
+        },
+        {
+          "left": 12,
+          "top": 36,
+          "right": 305,
+          "bottom": 653
+        },
+        {
+          "left": 9,
+          "top": 27,
+          "right": 308,
+          "bottom": 662
+        },
+        {
+          "left": 7,
+          "top": 20,
+          "right": 312,
+          "bottom": 669
+        },
+        {
+          "left": 5,
+          "top": 14,
+          "right": 314,
+          "bottom": 675
+        },
+        {
+          "left": 4,
+          "top": 11,
+          "right": 315,
+          "bottom": 678
+        },
+        {
+          "left": 3,
+          "top": 8,
+          "right": 316,
+          "bottom": 681
+        },
+        {
+          "left": 2,
+          "top": 5,
+          "right": 317,
+          "bottom": 684
+        },
+        {
+          "left": 1,
+          "top": 4,
+          "right": 318,
+          "bottom": 685
+        },
+        {
+          "left": 1,
+          "top": 3,
+          "right": 318,
+          "bottom": 686
+        },
+        {
+          "left": 0,
+          "top": 2,
+          "right": 319,
+          "bottom": 687
+        }
+      ]
+    },
+    {
+      "name": "corner_radii",
+      "type": "cornerRadii",
+      "data_points": [
+        null,
+        {
+          "top_left_x": 9.492916,
+          "top_left_y": 9.492916,
+          "top_right_x": 9.492916,
+          "top_right_y": 9.492916,
+          "bottom_right_x": 18.985832,
+          "bottom_right_y": 18.985832,
+          "bottom_left_x": 18.985832,
+          "bottom_left_y": 18.985832
+        },
+        {
+          "top_left_x": 8.381761,
+          "top_left_y": 8.381761,
+          "top_right_x": 8.381761,
+          "top_right_y": 8.381761,
+          "bottom_right_x": 16.763521,
+          "bottom_right_y": 16.763521,
+          "bottom_left_x": 16.763521,
+          "bottom_left_y": 16.763521
+        },
+        {
+          "top_left_x": 7.07397,
+          "top_left_y": 7.07397,
+          "top_right_x": 7.07397,
+          "top_right_y": 7.07397,
+          "bottom_right_x": 14.14794,
+          "bottom_right_y": 14.14794,
+          "bottom_left_x": 14.14794,
+          "bottom_left_y": 14.14794
+        },
+        {
+          "top_left_x": 5.7880254,
+          "top_left_y": 5.7880254,
+          "top_right_x": 5.7880254,
+          "top_right_y": 5.7880254,
+          "bottom_right_x": 11.576051,
+          "bottom_right_y": 11.576051,
+          "bottom_left_x": 11.576051,
+          "bottom_left_y": 11.576051
+        },
+        {
+          "top_left_x": 4.6295347,
+          "top_left_y": 4.6295347,
+          "top_right_x": 4.6295347,
+          "top_right_y": 4.6295347,
+          "bottom_right_x": 9.259069,
+          "bottom_right_y": 9.259069,
+          "bottom_left_x": 9.259069,
+          "bottom_left_y": 9.259069
+        },
+        {
+          "top_left_x": 3.638935,
+          "top_left_y": 3.638935,
+          "top_right_x": 3.638935,
+          "top_right_y": 3.638935,
+          "bottom_right_x": 7.27787,
+          "bottom_right_y": 7.27787,
+          "bottom_left_x": 7.27787,
+          "bottom_left_y": 7.27787
+        },
+        {
+          "top_left_x": 2.8209057,
+          "top_left_y": 2.8209057,
+          "top_right_x": 2.8209057,
+          "top_right_y": 2.8209057,
+          "bottom_right_x": 5.6418114,
+          "bottom_right_y": 5.6418114,
+          "bottom_left_x": 5.6418114,
+          "bottom_left_y": 5.6418114
+        },
+        {
+          "top_left_x": 2.1620893,
+          "top_left_y": 2.1620893,
+          "top_right_x": 2.1620893,
+          "top_right_y": 2.1620893,
+          "bottom_right_x": 4.3241787,
+          "bottom_right_y": 4.3241787,
+          "bottom_left_x": 4.3241787,
+          "bottom_left_y": 4.3241787
+        },
+        {
+          "top_left_x": 1.6414614,
+          "top_left_y": 1.6414614,
+          "top_right_x": 1.6414614,
+          "top_right_y": 1.6414614,
+          "bottom_right_x": 3.2829227,
+          "bottom_right_y": 3.2829227,
+          "bottom_left_x": 3.2829227,
+          "bottom_left_y": 3.2829227
+        },
+        {
+          "top_left_x": 1.2361269,
+          "top_left_y": 1.2361269,
+          "top_right_x": 1.2361269,
+          "top_right_y": 1.2361269,
+          "bottom_right_x": 2.4722538,
+          "bottom_right_y": 2.4722538,
+          "bottom_left_x": 2.4722538,
+          "bottom_left_y": 2.4722538
+        },
+        {
+          "top_left_x": 0.92435074,
+          "top_left_y": 0.92435074,
+          "top_right_x": 0.92435074,
+          "top_right_y": 0.92435074,
+          "bottom_right_x": 1.8487015,
+          "bottom_right_y": 1.8487015,
+          "bottom_left_x": 1.8487015,
+          "bottom_left_y": 1.8487015
+        },
+        {
+          "top_left_x": 0.68693924,
+          "top_left_y": 0.68693924,
+          "top_right_x": 0.68693924,
+          "top_right_y": 0.68693924,
+          "bottom_right_x": 1.3738785,
+          "bottom_right_y": 1.3738785,
+          "bottom_left_x": 1.3738785,
+          "bottom_left_y": 1.3738785
+        },
+        {
+          "top_left_x": 0.5076904,
+          "top_left_y": 0.5076904,
+          "top_right_x": 0.5076904,
+          "top_right_y": 0.5076904,
+          "bottom_right_x": 1.0153809,
+          "bottom_right_y": 1.0153809,
+          "bottom_left_x": 1.0153809,
+          "bottom_left_y": 1.0153809
+        },
+        {
+          "top_left_x": 0.3733511,
+          "top_left_y": 0.3733511,
+          "top_right_x": 0.3733511,
+          "top_right_y": 0.3733511,
+          "bottom_right_x": 0.7467022,
+          "bottom_right_y": 0.7467022,
+          "bottom_left_x": 0.7467022,
+          "bottom_left_y": 0.7467022
+        },
+        {
+          "top_left_x": 0.27331638,
+          "top_left_y": 0.27331638,
+          "top_right_x": 0.27331638,
+          "top_right_y": 0.27331638,
+          "bottom_right_x": 0.54663277,
+          "bottom_right_y": 0.54663277,
+          "bottom_left_x": 0.54663277,
+          "bottom_left_y": 0.54663277
+        },
+        {
+          "top_left_x": 0.19925308,
+          "top_left_y": 0.19925308,
+          "top_right_x": 0.19925308,
+          "top_right_y": 0.19925308,
+          "bottom_right_x": 0.39850616,
+          "bottom_right_y": 0.39850616,
+          "bottom_left_x": 0.39850616,
+          "bottom_left_y": 0.39850616
+        },
+        {
+          "top_left_x": 0.14470005,
+          "top_left_y": 0.14470005,
+          "top_right_x": 0.14470005,
+          "top_right_y": 0.14470005,
+          "bottom_right_x": 0.2894001,
+          "bottom_right_y": 0.2894001,
+          "bottom_left_x": 0.2894001,
+          "bottom_left_y": 0.2894001
+        },
+        {
+          "top_left_x": 0.10470486,
+          "top_left_y": 0.10470486,
+          "top_right_x": 0.10470486,
+          "top_right_y": 0.10470486,
+          "bottom_right_x": 0.20940971,
+          "bottom_right_y": 0.20940971,
+          "bottom_left_x": 0.20940971,
+          "bottom_left_y": 0.20940971
+        },
+        {
+          "top_left_x": 0.07550812,
+          "top_left_y": 0.07550812,
+          "top_right_x": 0.07550812,
+          "top_right_y": 0.07550812,
+          "bottom_right_x": 0.15101624,
+          "bottom_right_y": 0.15101624,
+          "bottom_left_x": 0.15101624,
+          "bottom_left_y": 0.15101624
+        }
+      ]
+    },
+    {
+      "name": "alpha",
+      "type": "int",
+      "data_points": [
+        0,
+        45,
+        126,
+        190,
+        228,
+        246,
+        253,
+        255,
+        255,
+        255,
+        249,
+        226,
+        192,
+        153,
+        112,
+        72,
+        34,
+        0,
+        0,
+        0
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/goldens/backgroundAnimation_whenReturning.json b/packages/SystemUI/tests/goldens/backgroundAnimation_whenReturning.json
index 608e633..aa80445 100644
--- a/packages/SystemUI/tests/goldens/backgroundAnimation_whenReturning.json
+++ b/packages/SystemUI/tests/goldens/backgroundAnimation_whenReturning.json
@@ -1,25 +1,30 @@
 {
   "frame_ids": [
-    "before",
     0,
-    26,
-    52,
-    78,
-    105,
-    131,
-    157,
-    184,
-    210,
-    236,
-    263,
-    289,
-    315,
-    342,
-    368,
-    394,
-    421,
-    447,
-    473,
+    20,
+    40,
+    60,
+    80,
+    100,
+    120,
+    140,
+    160,
+    180,
+    200,
+    220,
+    240,
+    260,
+    280,
+    300,
+    320,
+    340,
+    360,
+    380,
+    400,
+    420,
+    440,
+    460,
+    480,
     500
   ],
   "features": [
@@ -28,70 +33,82 @@
       "type": "rect",
       "data_points": [
         {
-          "left": 0,
-          "top": 0,
-          "right": 0,
-          "bottom": 0
-        },
-        {
           "left": 100,
           "top": 300,
           "right": 200,
           "bottom": 400
         },
         {
-          "left": 98,
-          "top": 293,
-          "right": 203,
-          "bottom": 407
+          "left": 99,
+          "top": 296,
+          "right": 202,
+          "bottom": 404
         },
         {
-          "left": 91,
-          "top": 269,
-          "right": 213,
-          "bottom": 430
+          "left": 95,
+          "top": 283,
+          "right": 207,
+          "bottom": 417
         },
         {
-          "left": 71,
-          "top": 206,
-          "right": 240,
-          "bottom": 491
+          "left": 86,
+          "top": 256,
+          "right": 219,
+          "bottom": 443
         },
         {
-          "left": 34,
-          "top": 98,
-          "right": 283,
-          "bottom": 595
+          "left": 68,
+          "top": 198,
+          "right": 243,
+          "bottom": 499
         },
         {
-          "left": 22,
-          "top": 63,
-          "right": 296,
-          "bottom": 629
+          "left": 39,
+          "top": 110,
+          "right": 278,
+          "bottom": 584
+        },
+        {
+          "left": 26,
+          "top": 74,
+          "right": 292,
+          "bottom": 618
+        },
+        {
+          "left": 19,
+          "top": 55,
+          "right": 299,
+          "bottom": 637
         },
         {
           "left": 15,
-          "top": 44,
-          "right": 303,
-          "bottom": 648
+          "top": 42,
+          "right": 304,
+          "bottom": 649
         },
         {
-          "left": 11,
-          "top": 32,
-          "right": 308,
-          "bottom": 659
+          "left": 12,
+          "top": 33,
+          "right": 307,
+          "bottom": 658
         },
         {
-          "left": 8,
-          "top": 23,
-          "right": 311,
-          "bottom": 667
+          "left": 9,
+          "top": 27,
+          "right": 310,
+          "bottom": 664
+        },
+        {
+          "left": 7,
+          "top": 21,
+          "right": 312,
+          "bottom": 669
         },
         {
           "left": 6,
-          "top": 18,
-          "right": 313,
-          "bottom": 673
+          "top": 17,
+          "right": 314,
+          "bottom": 674
         },
         {
           "left": 5,
@@ -100,16 +117,22 @@
           "bottom": 677
         },
         {
-          "left": 3,
-          "top": 9,
+          "left": 4,
+          "top": 10,
           "right": 316,
-          "bottom": 681
+          "bottom": 680
+        },
+        {
+          "left": 3,
+          "top": 8,
+          "right": 317,
+          "bottom": 682
         },
         {
           "left": 2,
-          "top": 7,
-          "right": 317,
-          "bottom": 683
+          "top": 6,
+          "right": 318,
+          "bottom": 684
         },
         {
           "left": 2,
@@ -119,7 +142,7 @@
         },
         {
           "left": 1,
-          "top": 3,
+          "top": 4,
           "right": 319,
           "bottom": 687
         },
@@ -130,6 +153,18 @@
           "bottom": 688
         },
         {
+          "left": 1,
+          "top": 2,
+          "right": 319,
+          "bottom": 688
+        },
+        {
+          "left": 0,
+          "top": 1,
+          "right": 320,
+          "bottom": 689
+        },
+        {
           "left": 0,
           "top": 1,
           "right": 320,
@@ -159,7 +194,6 @@
       "name": "corner_radii",
       "type": "cornerRadii",
       "data_points": [
-        null,
         {
           "top_left_x": 10,
           "top_left_y": 10,
@@ -171,184 +205,244 @@
           "bottom_left_y": 20
         },
         {
-          "top_left_x": 9.762664,
-          "top_left_y": 9.762664,
-          "top_right_x": 9.762664,
-          "top_right_y": 9.762664,
-          "bottom_right_x": 19.525328,
-          "bottom_right_y": 19.525328,
-          "bottom_left_x": 19.525328,
-          "bottom_left_y": 19.525328
+          "top_left_x": 9.865689,
+          "top_left_y": 9.865689,
+          "top_right_x": 9.865689,
+          "top_right_y": 9.865689,
+          "bottom_right_x": 19.731379,
+          "bottom_right_y": 19.731379,
+          "bottom_left_x": 19.731379,
+          "bottom_left_y": 19.731379
         },
         {
-          "top_left_x": 8.969244,
-          "top_left_y": 8.969244,
-          "top_right_x": 8.969244,
-          "top_right_y": 8.969244,
-          "bottom_right_x": 17.938488,
-          "bottom_right_y": 17.938488,
-          "bottom_left_x": 17.938488,
-          "bottom_left_y": 17.938488
+          "top_left_x": 9.419104,
+          "top_left_y": 9.419104,
+          "top_right_x": 9.419104,
+          "top_right_y": 9.419104,
+          "bottom_right_x": 18.838207,
+          "bottom_right_y": 18.838207,
+          "bottom_left_x": 18.838207,
+          "bottom_left_y": 18.838207
         },
         {
-          "top_left_x": 6.8709626,
-          "top_left_y": 6.8709626,
-          "top_right_x": 6.8709626,
-          "top_right_y": 6.8709626,
-          "bottom_right_x": 13.741925,
-          "bottom_right_y": 13.741925,
-          "bottom_left_x": 13.741925,
-          "bottom_left_y": 13.741925
+          "top_left_x": 8.533693,
+          "top_left_y": 8.533693,
+          "top_right_x": 8.533693,
+          "top_right_y": 8.533693,
+          "bottom_right_x": 17.067387,
+          "bottom_right_y": 17.067387,
+          "bottom_left_x": 17.067387,
+          "bottom_left_y": 17.067387
         },
         {
-          "top_left_x": 3.260561,
-          "top_left_y": 3.260561,
-          "top_right_x": 3.260561,
-          "top_right_y": 3.260561,
-          "bottom_right_x": 6.521122,
-          "bottom_right_y": 6.521122,
-          "bottom_left_x": 6.521122,
-          "bottom_left_y": 6.521122
+          "top_left_x": 6.5919456,
+          "top_left_y": 6.5919456,
+          "top_right_x": 6.5919456,
+          "top_right_y": 6.5919456,
+          "bottom_right_x": 13.183891,
+          "bottom_right_y": 13.183891,
+          "bottom_left_x": 13.183891,
+          "bottom_left_y": 13.183891
         },
         {
-          "top_left_x": 2.0915751,
-          "top_left_y": 2.0915751,
-          "top_right_x": 2.0915751,
-          "top_right_y": 2.0915751,
-          "bottom_right_x": 4.1831503,
-          "bottom_right_y": 4.1831503,
-          "bottom_left_x": 4.1831503,
-          "bottom_left_y": 4.1831503
+          "top_left_x": 3.6674318,
+          "top_left_y": 3.6674318,
+          "top_right_x": 3.6674318,
+          "top_right_y": 3.6674318,
+          "bottom_right_x": 7.3348637,
+          "bottom_right_y": 7.3348637,
+          "bottom_left_x": 7.3348637,
+          "bottom_left_y": 7.3348637
         },
         {
-          "top_left_x": 1.4640827,
-          "top_left_y": 1.4640827,
-          "top_right_x": 1.4640827,
-          "top_right_y": 1.4640827,
-          "bottom_right_x": 2.9281654,
-          "bottom_right_y": 2.9281654,
-          "bottom_left_x": 2.9281654,
-          "bottom_left_y": 2.9281654
+          "top_left_x": 2.4832253,
+          "top_left_y": 2.4832253,
+          "top_right_x": 2.4832253,
+          "top_right_y": 2.4832253,
+          "bottom_right_x": 4.9664507,
+          "bottom_right_y": 4.9664507,
+          "bottom_left_x": 4.9664507,
+          "bottom_left_y": 4.9664507
         },
         {
-          "top_left_x": 1.057313,
-          "top_left_y": 1.057313,
-          "top_right_x": 1.057313,
-          "top_right_y": 1.057313,
-          "bottom_right_x": 2.114626,
-          "bottom_right_y": 2.114626,
-          "bottom_left_x": 2.114626,
-          "bottom_left_y": 2.114626
+          "top_left_x": 1.8252907,
+          "top_left_y": 1.8252907,
+          "top_right_x": 1.8252907,
+          "top_right_y": 1.8252907,
+          "bottom_right_x": 3.6505814,
+          "bottom_right_y": 3.6505814,
+          "bottom_left_x": 3.6505814,
+          "bottom_left_y": 3.6505814
         },
         {
-          "top_left_x": 0.7824335,
-          "top_left_y": 0.7824335,
-          "top_right_x": 0.7824335,
-          "top_right_y": 0.7824335,
-          "bottom_right_x": 1.564867,
-          "bottom_right_y": 1.564867,
-          "bottom_left_x": 1.564867,
-          "bottom_left_y": 1.564867
+          "top_left_x": 1.4077549,
+          "top_left_y": 1.4077549,
+          "top_right_x": 1.4077549,
+          "top_right_y": 1.4077549,
+          "bottom_right_x": 2.8155098,
+          "bottom_right_y": 2.8155098,
+          "bottom_left_x": 2.8155098,
+          "bottom_left_y": 2.8155098
         },
         {
-          "top_left_x": 0.5863056,
-          "top_left_y": 0.5863056,
-          "top_right_x": 0.5863056,
-          "top_right_y": 0.5863056,
-          "bottom_right_x": 1.1726112,
-          "bottom_right_y": 1.1726112,
-          "bottom_left_x": 1.1726112,
-          "bottom_left_y": 1.1726112
+          "top_left_x": 1.1067667,
+          "top_left_y": 1.1067667,
+          "top_right_x": 1.1067667,
+          "top_right_y": 1.1067667,
+          "bottom_right_x": 2.2135334,
+          "bottom_right_y": 2.2135334,
+          "bottom_left_x": 2.2135334,
+          "bottom_left_y": 2.2135334
         },
         {
-          "top_left_x": 0.4332962,
-          "top_left_y": 0.4332962,
-          "top_right_x": 0.4332962,
-          "top_right_y": 0.4332962,
-          "bottom_right_x": 0.8665924,
-          "bottom_right_y": 0.8665924,
-          "bottom_left_x": 0.8665924,
-          "bottom_left_y": 0.8665924
+          "top_left_x": 0.88593864,
+          "top_left_y": 0.88593864,
+          "top_right_x": 0.88593864,
+          "top_right_y": 0.88593864,
+          "bottom_right_x": 1.7718773,
+          "bottom_right_y": 1.7718773,
+          "bottom_left_x": 1.7718773,
+          "bottom_left_y": 1.7718773
         },
         {
-          "top_left_x": 0.3145876,
-          "top_left_y": 0.3145876,
-          "top_right_x": 0.3145876,
-          "top_right_y": 0.3145876,
-          "bottom_right_x": 0.6291752,
-          "bottom_right_y": 0.6291752,
-          "bottom_left_x": 0.6291752,
-          "bottom_left_y": 0.6291752
+          "top_left_x": 0.7069988,
+          "top_left_y": 0.7069988,
+          "top_right_x": 0.7069988,
+          "top_right_y": 0.7069988,
+          "bottom_right_x": 1.4139977,
+          "bottom_right_y": 1.4139977,
+          "bottom_left_x": 1.4139977,
+          "bottom_left_y": 1.4139977
         },
         {
-          "top_left_x": 0.22506618,
-          "top_left_y": 0.22506618,
-          "top_right_x": 0.22506618,
-          "top_right_y": 0.22506618,
-          "bottom_right_x": 0.45013237,
-          "bottom_right_y": 0.45013237,
-          "bottom_left_x": 0.45013237,
-          "bottom_left_y": 0.45013237
+          "top_left_x": 0.55613136,
+          "top_left_y": 0.55613136,
+          "top_right_x": 0.55613136,
+          "top_right_y": 0.55613136,
+          "bottom_right_x": 1.1122627,
+          "bottom_right_y": 1.1122627,
+          "bottom_left_x": 1.1122627,
+          "bottom_left_y": 1.1122627
         },
         {
-          "top_left_x": 0.15591621,
-          "top_left_y": 0.15591621,
-          "top_right_x": 0.15591621,
-          "top_right_y": 0.15591621,
-          "bottom_right_x": 0.31183243,
-          "bottom_right_y": 0.31183243,
-          "bottom_left_x": 0.31183243,
-          "bottom_left_y": 0.31183243
+          "top_left_x": 0.44889355,
+          "top_left_y": 0.44889355,
+          "top_right_x": 0.44889355,
+          "top_right_y": 0.44889355,
+          "bottom_right_x": 0.8977871,
+          "bottom_right_y": 0.8977871,
+          "bottom_left_x": 0.8977871,
+          "bottom_left_y": 0.8977871
         },
         {
-          "top_left_x": 0.100948334,
-          "top_left_y": 0.100948334,
-          "top_right_x": 0.100948334,
-          "top_right_y": 0.100948334,
-          "bottom_right_x": 0.20189667,
-          "bottom_right_y": 0.20189667,
-          "bottom_left_x": 0.20189667,
-          "bottom_left_y": 0.20189667
+          "top_left_x": 0.34557533,
+          "top_left_y": 0.34557533,
+          "top_right_x": 0.34557533,
+          "top_right_y": 0.34557533,
+          "bottom_right_x": 0.69115067,
+          "bottom_right_y": 0.69115067,
+          "bottom_left_x": 0.69115067,
+          "bottom_left_y": 0.69115067
         },
         {
-          "top_left_x": 0.06496239,
-          "top_left_y": 0.06496239,
-          "top_right_x": 0.06496239,
-          "top_right_y": 0.06496239,
-          "bottom_right_x": 0.12992477,
-          "bottom_right_y": 0.12992477,
-          "bottom_left_x": 0.12992477,
-          "bottom_left_y": 0.12992477
+          "top_left_x": 0.27671337,
+          "top_left_y": 0.27671337,
+          "top_right_x": 0.27671337,
+          "top_right_y": 0.27671337,
+          "bottom_right_x": 0.55342674,
+          "bottom_right_y": 0.55342674,
+          "bottom_left_x": 0.55342674,
+          "bottom_left_y": 0.55342674
         },
         {
-          "top_left_x": 0.03526497,
-          "top_left_y": 0.03526497,
-          "top_right_x": 0.03526497,
-          "top_right_y": 0.03526497,
-          "bottom_right_x": 0.07052994,
-          "bottom_right_y": 0.07052994,
-          "bottom_left_x": 0.07052994,
-          "bottom_left_y": 0.07052994
+          "top_left_x": 0.20785141,
+          "top_left_y": 0.20785141,
+          "top_right_x": 0.20785141,
+          "top_right_y": 0.20785141,
+          "bottom_right_x": 0.41570282,
+          "bottom_right_y": 0.41570282,
+          "bottom_left_x": 0.41570282,
+          "bottom_left_y": 0.41570282
         },
         {
-          "top_left_x": 0.014661789,
-          "top_left_y": 0.014661789,
-          "top_right_x": 0.014661789,
-          "top_right_y": 0.014661789,
-          "bottom_right_x": 0.029323578,
-          "bottom_right_y": 0.029323578,
-          "bottom_left_x": 0.029323578,
-          "bottom_left_y": 0.029323578
+          "top_left_x": 0.1601448,
+          "top_left_y": 0.1601448,
+          "top_right_x": 0.1601448,
+          "top_right_y": 0.1601448,
+          "bottom_right_x": 0.3202896,
+          "bottom_right_y": 0.3202896,
+          "bottom_left_x": 0.3202896,
+          "bottom_left_y": 0.3202896
         },
         {
-          "top_left_x": 0.0041856766,
-          "top_left_y": 0.0041856766,
-          "top_right_x": 0.0041856766,
-          "top_right_y": 0.0041856766,
-          "bottom_right_x": 0.008371353,
-          "bottom_right_y": 0.008371353,
-          "bottom_left_x": 0.008371353,
-          "bottom_left_y": 0.008371353
+          "top_left_x": 0.117860794,
+          "top_left_y": 0.117860794,
+          "top_right_x": 0.117860794,
+          "top_right_y": 0.117860794,
+          "bottom_right_x": 0.23572159,
+          "bottom_right_y": 0.23572159,
+          "bottom_left_x": 0.23572159,
+          "bottom_left_y": 0.23572159
+        },
+        {
+          "top_left_x": 0.08036041,
+          "top_left_y": 0.08036041,
+          "top_right_x": 0.08036041,
+          "top_right_y": 0.08036041,
+          "bottom_right_x": 0.16072083,
+          "bottom_right_y": 0.16072083,
+          "bottom_left_x": 0.16072083,
+          "bottom_left_y": 0.16072083
+        },
+        {
+          "top_left_x": 0.05836296,
+          "top_left_y": 0.05836296,
+          "top_right_x": 0.05836296,
+          "top_right_y": 0.05836296,
+          "bottom_right_x": 0.11672592,
+          "bottom_right_y": 0.11672592,
+          "bottom_left_x": 0.11672592,
+          "bottom_left_y": 0.11672592
+        },
+        {
+          "top_left_x": 0.03636551,
+          "top_left_y": 0.03636551,
+          "top_right_x": 0.03636551,
+          "top_right_y": 0.03636551,
+          "bottom_right_x": 0.07273102,
+          "bottom_right_y": 0.07273102,
+          "bottom_left_x": 0.07273102,
+          "bottom_left_y": 0.07273102
+        },
+        {
+          "top_left_x": 0.018137932,
+          "top_left_y": 0.018137932,
+          "top_right_x": 0.018137932,
+          "top_right_y": 0.018137932,
+          "bottom_right_x": 0.036275864,
+          "bottom_right_y": 0.036275864,
+          "bottom_left_x": 0.036275864,
+          "bottom_left_y": 0.036275864
+        },
+        {
+          "top_left_x": 0.0082063675,
+          "top_left_y": 0.0082063675,
+          "top_right_x": 0.0082063675,
+          "top_right_y": 0.0082063675,
+          "bottom_right_x": 0.016412735,
+          "bottom_right_y": 0.016412735,
+          "bottom_left_x": 0.016412735,
+          "bottom_left_y": 0.016412735
+        },
+        {
+          "top_left_x": 0.0031013489,
+          "top_left_y": 0.0031013489,
+          "top_right_x": 0.0031013489,
+          "top_right_y": 0.0031013489,
+          "bottom_right_x": 0.0062026978,
+          "bottom_right_y": 0.0062026978,
+          "bottom_left_x": 0.0062026978,
+          "bottom_left_y": 0.0062026978
         },
         {
           "top_left_x": 0,
@@ -367,19 +461,24 @@
       "type": "int",
       "data_points": [
         0,
+        96,
+        153,
+        192,
+        220,
+        238,
+        249,
+        254,
+        233,
+        191,
+        153,
+        117,
+        85,
+        57,
+        33,
+        14,
+        3,
         0,
-        115,
-        178,
-        217,
-        241,
-        253,
-        239,
-        183,
-        135,
-        91,
-        53,
-        23,
-        5,
+        0,
         0,
         0,
         0,
diff --git a/packages/SystemUI/tests/goldens/backgroundAnimation_whenReturning_withSpring.json b/packages/SystemUI/tests/goldens/backgroundAnimation_whenReturning_withSpring.json
new file mode 100644
index 0000000..a840d3c
--- /dev/null
+++ b/packages/SystemUI/tests/goldens/backgroundAnimation_whenReturning_withSpring.json
@@ -0,0 +1,375 @@
+{
+  "frame_ids": [
+    0,
+    16,
+    32,
+    48,
+    64,
+    80,
+    96,
+    112,
+    128,
+    144,
+    160,
+    176,
+    192,
+    208,
+    224,
+    240,
+    256,
+    272,
+    288,
+    304
+  ],
+  "features": [
+    {
+      "name": "bounds",
+      "type": "rect",
+      "data_points": [
+        {
+          "left": 0,
+          "top": 0,
+          "right": 0,
+          "bottom": 0
+        },
+        {
+          "left": 94,
+          "top": 284,
+          "right": 206,
+          "bottom": 414
+        },
+        {
+          "left": 83,
+          "top": 251,
+          "right": 219,
+          "bottom": 447
+        },
+        {
+          "left": 70,
+          "top": 212,
+          "right": 234,
+          "bottom": 485
+        },
+        {
+          "left": 57,
+          "top": 173,
+          "right": 250,
+          "bottom": 522
+        },
+        {
+          "left": 46,
+          "top": 139,
+          "right": 264,
+          "bottom": 555
+        },
+        {
+          "left": 36,
+          "top": 109,
+          "right": 276,
+          "bottom": 584
+        },
+        {
+          "left": 28,
+          "top": 84,
+          "right": 285,
+          "bottom": 608
+        },
+        {
+          "left": 21,
+          "top": 65,
+          "right": 293,
+          "bottom": 627
+        },
+        {
+          "left": 16,
+          "top": 49,
+          "right": 300,
+          "bottom": 642
+        },
+        {
+          "left": 12,
+          "top": 36,
+          "right": 305,
+          "bottom": 653
+        },
+        {
+          "left": 9,
+          "top": 27,
+          "right": 308,
+          "bottom": 662
+        },
+        {
+          "left": 7,
+          "top": 20,
+          "right": 312,
+          "bottom": 669
+        },
+        {
+          "left": 5,
+          "top": 14,
+          "right": 314,
+          "bottom": 675
+        },
+        {
+          "left": 4,
+          "top": 11,
+          "right": 315,
+          "bottom": 678
+        },
+        {
+          "left": 3,
+          "top": 8,
+          "right": 316,
+          "bottom": 681
+        },
+        {
+          "left": 2,
+          "top": 5,
+          "right": 317,
+          "bottom": 684
+        },
+        {
+          "left": 1,
+          "top": 4,
+          "right": 318,
+          "bottom": 685
+        },
+        {
+          "left": 1,
+          "top": 3,
+          "right": 318,
+          "bottom": 686
+        },
+        {
+          "left": 0,
+          "top": 2,
+          "right": 319,
+          "bottom": 687
+        }
+      ]
+    },
+    {
+      "name": "corner_radii",
+      "type": "cornerRadii",
+      "data_points": [
+        null,
+        {
+          "top_left_x": 9.492916,
+          "top_left_y": 9.492916,
+          "top_right_x": 9.492916,
+          "top_right_y": 9.492916,
+          "bottom_right_x": 18.985832,
+          "bottom_right_y": 18.985832,
+          "bottom_left_x": 18.985832,
+          "bottom_left_y": 18.985832
+        },
+        {
+          "top_left_x": 8.381761,
+          "top_left_y": 8.381761,
+          "top_right_x": 8.381761,
+          "top_right_y": 8.381761,
+          "bottom_right_x": 16.763521,
+          "bottom_right_y": 16.763521,
+          "bottom_left_x": 16.763521,
+          "bottom_left_y": 16.763521
+        },
+        {
+          "top_left_x": 7.07397,
+          "top_left_y": 7.07397,
+          "top_right_x": 7.07397,
+          "top_right_y": 7.07397,
+          "bottom_right_x": 14.14794,
+          "bottom_right_y": 14.14794,
+          "bottom_left_x": 14.14794,
+          "bottom_left_y": 14.14794
+        },
+        {
+          "top_left_x": 5.7880254,
+          "top_left_y": 5.7880254,
+          "top_right_x": 5.7880254,
+          "top_right_y": 5.7880254,
+          "bottom_right_x": 11.576051,
+          "bottom_right_y": 11.576051,
+          "bottom_left_x": 11.576051,
+          "bottom_left_y": 11.576051
+        },
+        {
+          "top_left_x": 4.6295347,
+          "top_left_y": 4.6295347,
+          "top_right_x": 4.6295347,
+          "top_right_y": 4.6295347,
+          "bottom_right_x": 9.259069,
+          "bottom_right_y": 9.259069,
+          "bottom_left_x": 9.259069,
+          "bottom_left_y": 9.259069
+        },
+        {
+          "top_left_x": 3.638935,
+          "top_left_y": 3.638935,
+          "top_right_x": 3.638935,
+          "top_right_y": 3.638935,
+          "bottom_right_x": 7.27787,
+          "bottom_right_y": 7.27787,
+          "bottom_left_x": 7.27787,
+          "bottom_left_y": 7.27787
+        },
+        {
+          "top_left_x": 2.8209057,
+          "top_left_y": 2.8209057,
+          "top_right_x": 2.8209057,
+          "top_right_y": 2.8209057,
+          "bottom_right_x": 5.6418114,
+          "bottom_right_y": 5.6418114,
+          "bottom_left_x": 5.6418114,
+          "bottom_left_y": 5.6418114
+        },
+        {
+          "top_left_x": 2.1620893,
+          "top_left_y": 2.1620893,
+          "top_right_x": 2.1620893,
+          "top_right_y": 2.1620893,
+          "bottom_right_x": 4.3241787,
+          "bottom_right_y": 4.3241787,
+          "bottom_left_x": 4.3241787,
+          "bottom_left_y": 4.3241787
+        },
+        {
+          "top_left_x": 1.6414614,
+          "top_left_y": 1.6414614,
+          "top_right_x": 1.6414614,
+          "top_right_y": 1.6414614,
+          "bottom_right_x": 3.2829227,
+          "bottom_right_y": 3.2829227,
+          "bottom_left_x": 3.2829227,
+          "bottom_left_y": 3.2829227
+        },
+        {
+          "top_left_x": 1.2361269,
+          "top_left_y": 1.2361269,
+          "top_right_x": 1.2361269,
+          "top_right_y": 1.2361269,
+          "bottom_right_x": 2.4722538,
+          "bottom_right_y": 2.4722538,
+          "bottom_left_x": 2.4722538,
+          "bottom_left_y": 2.4722538
+        },
+        {
+          "top_left_x": 0.92435074,
+          "top_left_y": 0.92435074,
+          "top_right_x": 0.92435074,
+          "top_right_y": 0.92435074,
+          "bottom_right_x": 1.8487015,
+          "bottom_right_y": 1.8487015,
+          "bottom_left_x": 1.8487015,
+          "bottom_left_y": 1.8487015
+        },
+        {
+          "top_left_x": 0.68693924,
+          "top_left_y": 0.68693924,
+          "top_right_x": 0.68693924,
+          "top_right_y": 0.68693924,
+          "bottom_right_x": 1.3738785,
+          "bottom_right_y": 1.3738785,
+          "bottom_left_x": 1.3738785,
+          "bottom_left_y": 1.3738785
+        },
+        {
+          "top_left_x": 0.5076904,
+          "top_left_y": 0.5076904,
+          "top_right_x": 0.5076904,
+          "top_right_y": 0.5076904,
+          "bottom_right_x": 1.0153809,
+          "bottom_right_y": 1.0153809,
+          "bottom_left_x": 1.0153809,
+          "bottom_left_y": 1.0153809
+        },
+        {
+          "top_left_x": 0.3733511,
+          "top_left_y": 0.3733511,
+          "top_right_x": 0.3733511,
+          "top_right_y": 0.3733511,
+          "bottom_right_x": 0.7467022,
+          "bottom_right_y": 0.7467022,
+          "bottom_left_x": 0.7467022,
+          "bottom_left_y": 0.7467022
+        },
+        {
+          "top_left_x": 0.27331638,
+          "top_left_y": 0.27331638,
+          "top_right_x": 0.27331638,
+          "top_right_y": 0.27331638,
+          "bottom_right_x": 0.54663277,
+          "bottom_right_y": 0.54663277,
+          "bottom_left_x": 0.54663277,
+          "bottom_left_y": 0.54663277
+        },
+        {
+          "top_left_x": 0.19925308,
+          "top_left_y": 0.19925308,
+          "top_right_x": 0.19925308,
+          "top_right_y": 0.19925308,
+          "bottom_right_x": 0.39850616,
+          "bottom_right_y": 0.39850616,
+          "bottom_left_x": 0.39850616,
+          "bottom_left_y": 0.39850616
+        },
+        {
+          "top_left_x": 0.14470005,
+          "top_left_y": 0.14470005,
+          "top_right_x": 0.14470005,
+          "top_right_y": 0.14470005,
+          "bottom_right_x": 0.2894001,
+          "bottom_right_y": 0.2894001,
+          "bottom_left_x": 0.2894001,
+          "bottom_left_y": 0.2894001
+        },
+        {
+          "top_left_x": 0.10470486,
+          "top_left_y": 0.10470486,
+          "top_right_x": 0.10470486,
+          "top_right_y": 0.10470486,
+          "bottom_right_x": 0.20940971,
+          "bottom_right_y": 0.20940971,
+          "bottom_left_x": 0.20940971,
+          "bottom_left_y": 0.20940971
+        },
+        {
+          "top_left_x": 0.07550812,
+          "top_left_y": 0.07550812,
+          "top_right_x": 0.07550812,
+          "top_right_y": 0.07550812,
+          "bottom_right_x": 0.15101624,
+          "bottom_right_y": 0.15101624,
+          "bottom_left_x": 0.15101624,
+          "bottom_left_y": 0.15101624
+        }
+      ]
+    },
+    {
+      "name": "alpha",
+      "type": "int",
+      "data_points": [
+        0,
+        45,
+        126,
+        190,
+        228,
+        246,
+        253,
+        255,
+        255,
+        255,
+        249,
+        226,
+        192,
+        153,
+        112,
+        72,
+        34,
+        0,
+        0,
+        0
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuControllerTest.java
index 5e37d4c..51a7b5f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuControllerTest.java
@@ -338,6 +338,25 @@
         assertThat(mController.mFloatingMenu).isInstanceOf(MenuViewLayerController.class);
     }
 
+    @Test
+    public void onUserInitializationComplete_destroysOldWidget() {
+        enableAccessibilityFloatingMenuConfig();
+        mController = setUpController();
+
+        captureKeyguardUpdateMonitorCallback();
+        mKeyguardCallback.onUserUnlocked();
+        mKeyguardCallback.onKeyguardVisibilityChanged(false);
+
+        IAccessibilityFloatingMenu floatingMenu = mController.mFloatingMenu;
+
+        mController.mUserInitializationCompleteCallback
+                .onUserInitializationComplete(mContext.getUserId());
+        mTestableLooper.processAllMessages();
+
+        assertThat(mController.mFloatingMenu).isNotNull();
+        assertThat(mController.mFloatingMenu).isNotSameInstanceAs(floatingMenu);
+    }
+
     private AccessibilityFloatingMenuController setUpController() {
         final WindowManager windowManager = mContext.getSystemService(WindowManager.class);
         final ViewCaptureAwareWindowManager viewCaptureAwareWindowManager =
diff --git a/packages/SystemUI/tests/src/com/android/systemui/animation/TransitionAnimatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/animation/TransitionAnimatorTest.kt
index 6c42662..8b427fb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/animation/TransitionAnimatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/animation/TransitionAnimatorTest.kt
@@ -16,50 +16,44 @@
 
 package com.android.systemui.animation
 
-import android.animation.AnimatorSet
+import android.animation.AnimatorRuleRecordingSpec
+import android.animation.AnimatorTestRuleToolkit
+import android.animation.MotionControl
+import android.animation.recordMotion
 import android.graphics.drawable.GradientDrawable
 import android.platform.test.annotations.MotionTest
 import android.view.ViewGroup
 import android.widget.FrameLayout
 import androidx.test.ext.junit.rules.ActivityScenarioRule
-import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
+import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.activity.EmptyTestActivity
 import com.android.systemui.concurrency.fakeExecutor
 import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.testScope
+import kotlin.test.assertTrue
 import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
 import platform.test.motion.MotionTestRule
 import platform.test.motion.RecordedMotion
-import platform.test.motion.view.AnimationSampling.Companion.evenlySampled
 import platform.test.motion.view.DrawableFeatureCaptures
-import platform.test.motion.view.ViewRecordingSpec.Companion.captureWithoutScreenshot
-import platform.test.motion.view.ViewToolkit
-import platform.test.motion.view.record
-import platform.test.screenshot.DeviceEmulationRule
-import platform.test.screenshot.DeviceEmulationSpec
-import platform.test.screenshot.DisplaySpec
+import platform.test.runner.parameterized.ParameterizedAndroidJunit4
+import platform.test.runner.parameterized.Parameters
 import platform.test.screenshot.GoldenPathManager
 import platform.test.screenshot.PathConfig
 
 @SmallTest
 @MotionTest
-@RunWith(AndroidJUnit4::class)
-class TransitionAnimatorTest : SysuiTestCase() {
+@RunWith(ParameterizedAndroidJunit4::class)
+class TransitionAnimatorTest(val useSpring: Boolean) : SysuiTestCase() {
     companion object {
         private const val GOLDENS_PATH = "frameworks/base/packages/SystemUI/tests/goldens"
 
-        private val emulationSpec =
-            DeviceEmulationSpec(
-                DisplaySpec(
-                    "phone",
-                    width = 320,
-                    height = 690,
-                    densityDpi = 160,
-                )
-            )
+        @get:Parameters(name = "{0}")
+        @JvmStatic
+        val useSpringValues = booleanArrayOf(false, true).toList()
     }
 
     private val kosmos = Kosmos()
@@ -68,32 +62,51 @@
         TransitionAnimator(
             kosmos.fakeExecutor,
             ActivityTransitionAnimator.TIMINGS,
-            ActivityTransitionAnimator.INTERPOLATORS
+            ActivityTransitionAnimator.INTERPOLATORS,
+            ActivityTransitionAnimator.SPRING_TIMINGS,
+            ActivityTransitionAnimator.SPRING_INTERPOLATORS,
         )
+    private val withSpring =
+        if (useSpring) {
+            "_withSpring"
+        } else {
+            ""
+        }
 
-    @get:Rule(order = 0) val deviceEmulationRule = DeviceEmulationRule(emulationSpec)
     @get:Rule(order = 1) val activityRule = ActivityScenarioRule(EmptyTestActivity::class.java)
-    @get:Rule(order = 2)
-    val motionRule = MotionTestRule(ViewToolkit { activityRule.scenario }, pathManager)
+    @get:Rule(order = 2) val animatorTestRule = android.animation.AnimatorTestRule(this)
+    @get:Rule(order = 3)
+    val motionRule =
+        MotionTestRule(AnimatorTestRuleToolkit(animatorTestRule, kosmos.testScope), pathManager)
 
     @Test
     fun backgroundAnimation_whenLaunching() {
         val backgroundLayer = GradientDrawable().apply { alpha = 0 }
-        val animator = setUpTest(backgroundLayer, isLaunching = true)
+        val animator =
+            setUpTest(backgroundLayer, isLaunching = true).apply {
+                getInstrumentation().runOnMainSync { start() }
+            }
 
         val recordedMotion = recordMotion(backgroundLayer, animator)
 
-        motionRule.assertThat(recordedMotion).timeSeriesMatchesGolden()
+        motionRule
+            .assertThat(recordedMotion)
+            .timeSeriesMatchesGolden("backgroundAnimation_whenLaunching$withSpring")
     }
 
     @Test
     fun backgroundAnimation_whenReturning() {
         val backgroundLayer = GradientDrawable().apply { alpha = 0 }
-        val animator = setUpTest(backgroundLayer, isLaunching = false)
+        val animator =
+            setUpTest(backgroundLayer, isLaunching = false).apply {
+                getInstrumentation().runOnMainSync { start() }
+            }
 
         val recordedMotion = recordMotion(backgroundLayer, animator)
 
-        motionRule.assertThat(recordedMotion).timeSeriesMatchesGolden()
+        motionRule
+            .assertThat(recordedMotion)
+            .timeSeriesMatchesGolden("backgroundAnimation_whenReturning$withSpring")
     }
 
     @Test
@@ -101,10 +114,13 @@
         val backgroundLayer = GradientDrawable().apply { alpha = 0 }
         val animator =
             setUpTest(backgroundLayer, isLaunching = true, fadeWindowBackgroundLayer = false)
+                .apply { getInstrumentation().runOnMainSync { start() } }
 
         val recordedMotion = recordMotion(backgroundLayer, animator)
 
-        motionRule.assertThat(recordedMotion).timeSeriesMatchesGolden()
+        motionRule
+            .assertThat(recordedMotion)
+            .timeSeriesMatchesGolden("backgroundAnimationWithoutFade_whenLaunching$withSpring")
     }
 
     @Test
@@ -112,17 +128,20 @@
         val backgroundLayer = GradientDrawable().apply { alpha = 0 }
         val animator =
             setUpTest(backgroundLayer, isLaunching = false, fadeWindowBackgroundLayer = false)
+                .apply { getInstrumentation().runOnMainSync { start() } }
 
         val recordedMotion = recordMotion(backgroundLayer, animator)
 
-        motionRule.assertThat(recordedMotion).timeSeriesMatchesGolden()
+        motionRule
+            .assertThat(recordedMotion)
+            .timeSeriesMatchesGolden("backgroundAnimationWithoutFade_whenReturning$withSpring")
     }
 
     private fun setUpTest(
         backgroundLayer: GradientDrawable,
         isLaunching: Boolean,
         fadeWindowBackgroundLayer: Boolean = true,
-    ): AnimatorSet {
+    ): TransitionAnimator.Animation {
         lateinit var transitionContainer: ViewGroup
         activityRule.scenario.onActivity { activity ->
             transitionContainer = FrameLayout(activity).apply { setBackgroundColor(0x00FF00) }
@@ -131,17 +150,14 @@
         waitForIdleSync()
 
         val controller = TestController(transitionContainer, isLaunching)
-        val animator =
-            transitionAnimator.createAnimator(
-                controller,
-                createEndState(transitionContainer),
-                backgroundLayer,
-                fadeWindowBackgroundLayer
-            )
-        return AnimatorSet().apply {
-            duration = animator.duration
-            play(animator)
-        }
+        return transitionAnimator.createAnimation(
+            controller,
+            controller.createAnimatorState(),
+            createEndState(transitionContainer),
+            backgroundLayer,
+            fadeWindowBackgroundLayer,
+            useSpring,
+        )
     }
 
     private fun createEndState(container: ViewGroup): TransitionAnimator.State {
@@ -150,25 +166,44 @@
         return TransitionAnimator.State(
             left = containerLocation[0],
             top = containerLocation[1],
-            right = containerLocation[0] + emulationSpec.display.width,
-            bottom = containerLocation[1] + emulationSpec.display.height,
+            right = containerLocation[0] + 320,
+            bottom = containerLocation[1] + 690,
             topCornerRadius = 0f,
-            bottomCornerRadius = 0f
+            bottomCornerRadius = 0f,
         )
     }
 
     private fun recordMotion(
         backgroundLayer: GradientDrawable,
-        animator: AnimatorSet
+        animation: TransitionAnimator.Animation,
     ): RecordedMotion {
-        return motionRule.record(
-            animator,
-            backgroundLayer.captureWithoutScreenshot(evenlySampled(20)) {
-                feature(DrawableFeatureCaptures.bounds, "bounds")
-                feature(DrawableFeatureCaptures.cornerRadii, "corner_radii")
-                feature(DrawableFeatureCaptures.alpha, "alpha")
+        fun record(motionControl: MotionControl, sampleIntervalMs: Long): RecordedMotion {
+            return motionRule.recordMotion(
+                AnimatorRuleRecordingSpec(backgroundLayer, motionControl, sampleIntervalMs) {
+                    feature(DrawableFeatureCaptures.bounds, "bounds")
+                    feature(DrawableFeatureCaptures.cornerRadii, "corner_radii")
+                    feature(DrawableFeatureCaptures.alpha, "alpha")
+                }
+            )
+        }
+
+        val motionControl: MotionControl
+        val sampleIntervalMs: Long
+        if (useSpring) {
+            assertTrue { animation is TransitionAnimator.MultiSpringAnimation }
+            motionControl = MotionControl {
+                awaitCondition { (animation as TransitionAnimator.MultiSpringAnimation).isDone }
             }
-        )
+            sampleIntervalMs = 16L
+        } else {
+            assertTrue { animation is TransitionAnimator.InterpolatedAnimation }
+            motionControl = MotionControl { awaitFrames(count = 26) }
+            sampleIntervalMs = 20L
+        }
+
+        var recording: RecordedMotion? = null
+        getInstrumentation().runOnMainSync { recording = record(motionControl, sampleIntervalMs) }
+        return recording!!
     }
 }
 
@@ -178,7 +213,7 @@
  */
 private class TestController(
     override var transitionContainer: ViewGroup,
-    override val isLaunching: Boolean
+    override val isLaunching: Boolean,
 ) : TransitionAnimator.Controller {
     override fun createAnimatorState(): TransitionAnimator.State {
         val containerLocation = IntArray(2)
@@ -189,7 +224,7 @@
             right = containerLocation[0] + 200,
             bottom = containerLocation[1] + 400,
             topCornerRadius = 10f,
-            bottomCornerRadius = 20f
+            bottomCornerRadius = 20f,
         )
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/appops/AppOpsControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/appops/AppOpsControllerTest.java
index 476d6e3..7c08928 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/appops/AppOpsControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/appops/AppOpsControllerTest.java
@@ -103,11 +103,10 @@
     @Mock()
     private BroadcastDispatcher mDispatcher;
     @Mock(stubOnly = true)
-    private AudioManager.AudioRecordingCallback mRecordingCallback;
-    @Mock(stubOnly = true)
     private AudioRecordingConfiguration mPausedMockRecording;
 
     private AppOpsControllerImpl mController;
+    private AudioManager.AudioRecordingCallback mRecordingCallback;
     private TestableLooper mTestableLooper;
     private final FakeExecutor mBgExecutor = new FakeExecutor(new FakeSystemClock());
 
@@ -975,6 +974,7 @@
     }
 
     private void verifyUnPausedSentActive(int micOpCode) {
+        // Setup stubs the initial active recording list with a single silenced client
         mController.addCallback(new int[]{micOpCode}, mCallback);
         mBgExecutor.runAllReady();
         mTestableLooper.processAllMessages();
@@ -982,11 +982,20 @@
                 TEST_PACKAGE_NAME, true);
 
         mTestableLooper.processAllMessages();
-        mRecordingCallback.onRecordingConfigChanged(Collections.emptyList());
+
+        // Update with multiple recording configs, of which one is unsilenced
+        var mockARCUnsilenced = mock(AudioRecordingConfiguration.class);
+        when(mockARCUnsilenced.getClientUid()).thenReturn(TEST_UID);
+        when(mockARCUnsilenced.isClientSilenced()).thenReturn(false);
+
+        mRecordingCallback.onRecordingConfigChanged(List.of(
+                    mockARCUnsilenced, mPausedMockRecording));
 
         mTestableLooper.processAllMessages();
 
         verify(mCallback).onActiveStateChanged(micOpCode, TEST_UID, TEST_PACKAGE_NAME, true);
+        // For consistency since this runs in a loop
+        mController.removeCallback(new int[]{micOpCode}, mCallback);
     }
 
     private void verifyAudioPausedSentInactive(int micOpCode) {
@@ -997,11 +1006,16 @@
                 TEST_PACKAGE_NAME, true);
         mTestableLooper.processAllMessages();
 
-        AudioRecordingConfiguration mockARC = mock(AudioRecordingConfiguration.class);
-        when(mockARC.getClientUid()).thenReturn(TEST_UID_OTHER);
-        when(mockARC.isClientSilenced()).thenReturn(true);
+        // Multiple recording configs, which are all silenced
+        AudioRecordingConfiguration mockARCOne = mock(AudioRecordingConfiguration.class);
+        when(mockARCOne.getClientUid()).thenReturn(TEST_UID_OTHER);
+        when(mockARCOne.isClientSilenced()).thenReturn(true);
 
-        mRecordingCallback.onRecordingConfigChanged(List.of(mockARC));
+        AudioRecordingConfiguration mockARCTwo = mock(AudioRecordingConfiguration.class);
+        when(mockARCTwo.getClientUid()).thenReturn(TEST_UID_OTHER);
+        when(mockARCTwo.isClientSilenced()).thenReturn(true);
+
+        mRecordingCallback.onRecordingConfigChanged(List.of(mockARCOne, mockARCTwo));
         mTestableLooper.processAllMessages();
 
         InOrder inOrder = inOrder(mCallback);
@@ -1009,6 +1023,8 @@
                 micOpCode, TEST_UID_OTHER, TEST_PACKAGE_NAME, true);
         inOrder.verify(mCallback).onActiveStateChanged(
                 micOpCode, TEST_UID_OTHER, TEST_PACKAGE_NAME, false);
+        // For consistency since this runs in a loop
+        mController.removeCallback(new int[]{micOpCode}, mCallback);
     }
 
     private void verifySingleActiveOps(int op) {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt
similarity index 100%
rename from packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt
rename to packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsViewTest.kt
similarity index 100%
rename from packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsViewTest.kt
rename to packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsViewTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/AudioSharingButtonViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/AudioSharingButtonViewModelTest.kt
new file mode 100644
index 0000000..655b2cc
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/AudioSharingButtonViewModelTest.kt
@@ -0,0 +1,185 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.bluetooth.qsdialog
+
+import android.testing.TestableLooper
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession
+import com.android.dx.mockito.inline.extended.StaticMockitoSession
+import com.android.settingslib.bluetooth.BluetoothUtils
+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.android.systemui.kosmos.testScope
+import com.android.systemui.lifecycle.activateIn
+import com.android.systemui.res.R
+import com.android.systemui.testKosmos
+import com.android.systemui.util.mockito.whenever
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.MutableSharedFlow
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.After
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+
+@ExperimentalCoroutinesApi
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
+class AudioSharingButtonViewModelTest : SysuiTestCase() {
+    private val kosmos = testKosmos()
+    private val testScope = kosmos.testScope
+    private val bluetoothState = MutableStateFlow(false)
+    private val deviceItemUpdate: MutableSharedFlow<List<DeviceItem>> = MutableSharedFlow()
+    @Mock private lateinit var cachedBluetoothDevice: CachedBluetoothDevice
+    @Mock private lateinit var localBluetoothManager: LocalBluetoothManager
+    @Mock private lateinit var bluetoothStateInteractor: BluetoothStateInteractor
+    @Mock private lateinit var deviceItemInteractor: DeviceItemInteractor
+    @Mock private lateinit var deviceItem: DeviceItem
+    private lateinit var mockitoSession: StaticMockitoSession
+    private lateinit var audioSharingButtonViewModel: AudioSharingButtonViewModel
+
+    @Before
+    fun setUp() {
+        mockitoSession =
+            mockitoSession().initMocks(this).mockStatic(BluetoothUtils::class.java).startMocking()
+        whenever(bluetoothStateInteractor.bluetoothStateUpdate).thenReturn(bluetoothState)
+        whenever(deviceItemInteractor.deviceItemUpdate).thenReturn(deviceItemUpdate)
+        audioSharingButtonViewModel =
+            AudioSharingButtonViewModel(
+                localBluetoothManager,
+                kosmos.audioSharingInteractor,
+                bluetoothStateInteractor,
+                deviceItemInteractor,
+            )
+        audioSharingButtonViewModel.activateIn(testScope)
+    }
+
+    @After
+    fun tearDown() {
+        mockitoSession.finishMocking()
+    }
+
+    @Test
+    fun testButtonStateUpdate_bluetoothOff_returnGone() {
+        testScope.runTest {
+            val actual by
+                collectLastValue(audioSharingButtonViewModel.audioSharingButtonStateUpdate)
+            kosmos.bluetoothTileDialogAudioSharingRepository.setAudioSharingAvailable(true)
+
+            runCurrent()
+
+            assertThat(actual).isEqualTo(AudioSharingButtonState.Gone)
+        }
+    }
+
+    @Test
+    fun testButtonStateUpdate_noDevice_returnGone() {
+        testScope.runTest {
+            val actual by
+                collectLastValue(audioSharingButtonViewModel.audioSharingButtonStateUpdate)
+            kosmos.bluetoothTileDialogAudioSharingRepository.setAudioSharingAvailable(true)
+            bluetoothState.value = true
+            runCurrent()
+
+            assertThat(actual).isEqualTo(AudioSharingButtonState.Gone)
+        }
+    }
+
+    @Test
+    fun testButtonStateUpdate_isBroadcasting_returnSharingAudio() {
+        testScope.runTest {
+            val actual by
+                collectLastValue(audioSharingButtonViewModel.audioSharingButtonStateUpdate)
+            kosmos.bluetoothTileDialogAudioSharingRepository.setAudioSharingAvailable(true)
+            bluetoothState.value = true
+            runCurrent()
+            deviceItemUpdate.emit(listOf())
+            runCurrent()
+            kosmos.bluetoothTileDialogAudioSharingRepository.setInAudioSharing(true)
+            runCurrent()
+
+            assertThat(actual)
+                .isEqualTo(
+                    AudioSharingButtonState.Visible(
+                        R.string.quick_settings_bluetooth_audio_sharing_button_sharing,
+                        isActive = true,
+                    )
+                )
+        }
+    }
+
+    @Test
+    fun testButtonStateUpdate_hasSource_returnGone() {
+        testScope.runTest {
+            val actual by
+                collectLastValue(audioSharingButtonViewModel.audioSharingButtonStateUpdate)
+            kosmos.bluetoothTileDialogAudioSharingRepository.setAudioSharingAvailable(true)
+            whenever(deviceItem.cachedBluetoothDevice).thenReturn(cachedBluetoothDevice)
+            whenever(
+                    BluetoothUtils.hasConnectedBroadcastSource(
+                        cachedBluetoothDevice,
+                        localBluetoothManager,
+                    )
+                )
+                .thenReturn(true)
+            bluetoothState.value = true
+            runCurrent()
+            deviceItemUpdate.emit(listOf(deviceItem))
+            runCurrent()
+
+            assertThat(actual).isEqualTo(AudioSharingButtonState.Gone)
+        }
+    }
+
+    @Test
+    fun testButtonStateUpdate_hasActiveDevice_returnAudioSharing() {
+        testScope.runTest {
+            val actual by
+                collectLastValue(audioSharingButtonViewModel.audioSharingButtonStateUpdate)
+            kosmos.bluetoothTileDialogAudioSharingRepository.setAudioSharingAvailable(true)
+            whenever(deviceItem.cachedBluetoothDevice).thenReturn(cachedBluetoothDevice)
+            whenever(
+                    BluetoothUtils.hasConnectedBroadcastSource(
+                        cachedBluetoothDevice,
+                        localBluetoothManager,
+                    )
+                )
+                .thenReturn(false)
+            whenever(BluetoothUtils.isActiveLeAudioDevice(cachedBluetoothDevice)).thenReturn(true)
+            bluetoothState.value = true
+            runCurrent()
+            deviceItemUpdate.emit(listOf(deviceItem))
+            runCurrent()
+
+            assertThat(actual)
+                .isEqualTo(
+                    AudioSharingButtonState.Visible(
+                        R.string.quick_settings_bluetooth_audio_sharing_button,
+                        isActive = false,
+                    )
+                )
+        }
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/AudioSharingDeviceItemActionInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/AudioSharingDeviceItemActionInteractorTest.kt
new file mode 100644
index 0000000..ce37eee
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/AudioSharingDeviceItemActionInteractorTest.kt
@@ -0,0 +1,193 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.bluetooth.qsdialog
+
+import android.bluetooth.BluetoothDevice
+import android.platform.test.annotations.DisableFlags
+import android.platform.test.annotations.EnableFlags
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import androidx.test.filters.SmallTest
+import com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession
+import com.android.dx.mockito.inline.extended.StaticMockitoSession
+import com.android.settingslib.bluetooth.BluetoothUtils
+import com.android.settingslib.bluetooth.LeAudioProfile
+import com.android.settingslib.flags.Flags
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.kosmos.testDispatcher
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.plugins.activityStarter
+import com.android.systemui.statusbar.phone.SystemUIDialog
+import com.android.systemui.testKosmos
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.UnconfinedTestDispatcher
+import kotlinx.coroutines.test.runTest
+import org.junit.After
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers
+import org.mockito.ArgumentMatchers.anyBoolean
+import org.mockito.Mock
+import org.mockito.Mockito
+import org.mockito.Mockito.verify
+import org.mockito.junit.MockitoJUnit
+import org.mockito.junit.MockitoRule
+import org.mockito.kotlin.any
+import org.mockito.kotlin.eq
+import org.mockito.kotlin.never
+import org.mockito.kotlin.whenever
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
+@OptIn(ExperimentalCoroutinesApi::class)
+class AudioSharingDeviceItemActionInteractorTest : SysuiTestCase() {
+    @get:Rule val mockitoRule: MockitoRule = MockitoJUnit.rule()
+    private val kosmos = testKosmos().apply { testDispatcher = UnconfinedTestDispatcher() }
+    private lateinit var actionInteractorImpl: DeviceItemActionInteractor
+    private lateinit var mockitoSession: StaticMockitoSession
+    private lateinit var connectedAudioSharingMediaDeviceItem: DeviceItem
+    private lateinit var connectedMediaDeviceItem: DeviceItem
+    @Mock private lateinit var dialog: SystemUIDialog
+    @Mock private lateinit var leAudioProfile: LeAudioProfile
+    @Mock private lateinit var bluetoothDevice: BluetoothDevice
+
+    @Before
+    fun setUp() {
+        mockitoSession =
+            mockitoSession().initMocks(this).mockStatic(BluetoothUtils::class.java).startMocking()
+        connectedMediaDeviceItem =
+            DeviceItem(
+                type = DeviceItemType.AVAILABLE_MEDIA_BLUETOOTH_DEVICE,
+                cachedBluetoothDevice = kosmos.cachedBluetoothDevice,
+                deviceName = DEVICE_NAME,
+                connectionSummary = DEVICE_CONNECTION_SUMMARY,
+                iconWithDescription = null,
+                background = null,
+            )
+        connectedAudioSharingMediaDeviceItem =
+            DeviceItem(
+                type = DeviceItemType.AVAILABLE_AUDIO_SHARING_MEDIA_BLUETOOTH_DEVICE,
+                cachedBluetoothDevice = kosmos.cachedBluetoothDevice,
+                deviceName = DEVICE_NAME,
+                connectionSummary = DEVICE_CONNECTION_SUMMARY,
+                iconWithDescription = null,
+                background = null,
+            )
+        actionInteractorImpl = kosmos.audioSharingDeviceItemActionInteractorImpl
+    }
+
+    @After
+    fun tearDown() {
+        mockitoSession.finishMocking()
+    }
+
+    @Test
+    @EnableFlags(Flags.FLAG_AUDIO_SHARING_QS_DIALOG_IMPROVEMENT)
+    fun testOnClick_connectedAudioSharingMediaDevice_flagOn_createDialog() {
+        with(kosmos) {
+            testScope.runTest {
+                bluetoothTileDialogAudioSharingRepository.setAudioSharingAvailable(true)
+                actionInteractorImpl.onClick(connectedAudioSharingMediaDeviceItem, dialog)
+                verify(dialogTransitionAnimator)
+                    .showFromDialog(any(), any(), eq(null), anyBoolean())
+            }
+        }
+    }
+
+    @Test
+    @DisableFlags(Flags.FLAG_AUDIO_SHARING_QS_DIALOG_IMPROVEMENT)
+    fun testOnClick_connectedAudioSharingMediaDevice_flagOff_shouldLaunchSettings() {
+        with(kosmos) {
+            testScope.runTest {
+                bluetoothTileDialogAudioSharingRepository.setAudioSharingAvailable(true)
+                whenever(cachedBluetoothDevice.device).thenReturn(bluetoothDevice)
+                actionInteractorImpl.onClick(connectedAudioSharingMediaDeviceItem, dialog)
+                verify(activityStarter)
+                    .postStartActivityDismissingKeyguard(
+                        ArgumentMatchers.any(),
+                        ArgumentMatchers.anyInt(),
+                        ArgumentMatchers.any(),
+                    )
+                verify(dialogTransitionAnimator, never())
+                    .showFromDialog(any(), any(), eq(null), anyBoolean())
+            }
+        }
+    }
+
+    @Test
+    fun testOnClick_inAudioSharing_clickedDeviceHasSource_shouldNotLaunchSettings() {
+        with(kosmos) {
+            testScope.runTest {
+                bluetoothTileDialogAudioSharingRepository.setAudioSharingAvailable(true)
+                whenever(cachedBluetoothDevice.uiAccessibleProfiles)
+                    .thenReturn(listOf(leAudioProfile))
+                whenever(BluetoothUtils.isBroadcasting(ArgumentMatchers.any())).thenReturn(true)
+                whenever(
+                        BluetoothUtils.hasConnectedBroadcastSource(
+                            ArgumentMatchers.any(),
+                            ArgumentMatchers.any(),
+                        )
+                    )
+                    .thenReturn(true)
+
+                actionInteractorImpl.onClick(connectedMediaDeviceItem, dialog)
+                verify(activityStarter, Mockito.never())
+                    .postStartActivityDismissingKeyguard(
+                        ArgumentMatchers.any(),
+                        ArgumentMatchers.anyInt(),
+                        ArgumentMatchers.any(),
+                    )
+            }
+        }
+    }
+
+    @Test
+    fun testOnClick_inAudioSharing_clickedDeviceNoSource_shouldLaunchSettings() {
+        with(kosmos) {
+            testScope.runTest {
+                bluetoothTileDialogAudioSharingRepository.setAudioSharingAvailable(true)
+                whenever(cachedBluetoothDevice.device).thenReturn(bluetoothDevice)
+                whenever(cachedBluetoothDevice.uiAccessibleProfiles)
+                    .thenReturn(listOf(leAudioProfile))
+
+                whenever(BluetoothUtils.isBroadcasting(ArgumentMatchers.any())).thenReturn(true)
+                whenever(
+                        BluetoothUtils.hasConnectedBroadcastSource(
+                            ArgumentMatchers.any(),
+                            ArgumentMatchers.any(),
+                        )
+                    )
+                    .thenReturn(false)
+
+                actionInteractorImpl.onClick(connectedMediaDeviceItem, dialog)
+                verify(activityStarter)
+                    .postStartActivityDismissingKeyguard(
+                        ArgumentMatchers.any(),
+                        ArgumentMatchers.anyInt(),
+                        ArgumentMatchers.any(),
+                    )
+            }
+        }
+    }
+
+    private companion object {
+        const val DEVICE_NAME = "device"
+        const val DEVICE_CONNECTION_SUMMARY = "active"
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/AudioSharingDialogDelegateTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/AudioSharingDialogDelegateTest.kt
new file mode 100644
index 0000000..25b85b5
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/AudioSharingDialogDelegateTest.kt
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.bluetooth.qsdialog
+
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import android.widget.Button
+import android.widget.TextView
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.res.R
+import com.android.systemui.statusbar.phone.SystemUIDialog
+import com.android.systemui.testKosmos
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.MutableSharedFlow
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.test.runCurrent
+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.junit.MockitoJUnit
+import org.mockito.junit.MockitoRule
+import org.mockito.kotlin.spy
+import org.mockito.kotlin.verify
+import org.mockito.kotlin.whenever
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
+@OptIn(ExperimentalCoroutinesApi::class)
+class AudioSharingDialogDelegateTest : SysuiTestCase() {
+    @get:Rule val mockitoRule: MockitoRule = MockitoJUnit.rule()
+    private val kosmos = testKosmos()
+    private val updateFlow = MutableSharedFlow<Unit>()
+    private lateinit var underTest: AudioSharingDialogDelegate
+
+    @Before
+    fun setUp() {
+        with(kosmos) {
+            // TODO(b/364515243): use real object instead of mock
+            whenever(deviceItemInteractor.deviceItemUpdateRequest).thenReturn(updateFlow)
+            whenever(deviceItemInteractor.deviceItemUpdate)
+                .thenReturn(MutableStateFlow(emptyList()))
+            underTest = audioSharingDialogDelegate
+        }
+    }
+
+    @Test
+    fun testCreateDialog() =
+        kosmos.testScope.runTest {
+            val dialog = underTest.createDialog()
+            assertThat(dialog).isInstanceOf(SystemUIDialog::class.java)
+        }
+
+    @Test
+    fun testCreateDialog_showState() =
+        with(kosmos) {
+            testScope.runTest {
+                val availableDeviceName = "name"
+                whenever(cachedBluetoothDevice.name).thenReturn(availableDeviceName)
+                val dialog = spy(underTest.createDialog())
+                dialog.show()
+                runCurrent()
+                val subtitleTextView = dialog.findViewById<TextView>(R.id.subtitle)
+                val switchActiveButton = dialog.findViewById<Button>(R.id.switch_active_button)
+                val shareAudioButton = dialog.findViewById<Button>(R.id.share_audio_button)
+                val subtitle =
+                    context.getString(
+                        R.string.quick_settings_bluetooth_audio_sharing_dialog_subtitle,
+                        availableDeviceName,
+                        ""
+                    )
+                val switchButtonText =
+                    context.getString(
+                        R.string.quick_settings_bluetooth_audio_sharing_dialog_switch_to_button,
+                        availableDeviceName
+                    )
+                assertThat(subtitleTextView.text).isEqualTo(subtitle)
+                assertThat(switchActiveButton.text).isEqualTo(switchButtonText)
+                assertThat(switchActiveButton.hasOnClickListeners()).isTrue()
+                assertThat(shareAudioButton.hasOnClickListeners()).isTrue()
+
+                switchActiveButton.performClick()
+                verify(dialog).dismiss()
+            }
+        }
+
+    @Test
+    fun testCreateDialog_hideState() =
+        with(kosmos) {
+            testScope.runTest {
+                val dialog = spy(underTest.createDialog())
+                dialog.show()
+                runCurrent()
+                updateFlow.emit(Unit)
+                runCurrent()
+                verify(dialog).dismiss()
+            }
+        }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/AudioSharingDialogViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/AudioSharingDialogViewModelTest.kt
new file mode 100644
index 0000000..beb816c
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/AudioSharingDialogViewModelTest.kt
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.bluetooth.qsdialog
+
+import android.bluetooth.BluetoothDevice
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import androidx.test.filters.SmallTest
+import com.android.settingslib.bluetooth.LeAudioProfile
+import com.android.settingslib.bluetooth.LocalBluetoothProfileManager
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.bluetooth.cachedBluetoothDeviceManager
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.kosmos.testDispatcher
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.res.R
+import com.android.systemui.testKosmos
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.MutableSharedFlow
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.test.UnconfinedTestDispatcher
+import kotlinx.coroutines.test.runCurrent
+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.junit.MockitoJUnit
+import org.mockito.junit.MockitoRule
+import org.mockito.kotlin.any
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.whenever
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
+@OptIn(ExperimentalCoroutinesApi::class)
+class AudioSharingDialogViewModelTest : SysuiTestCase() {
+    @get:Rule val mockitoRule: MockitoRule = MockitoJUnit.rule()
+    private val kosmos = testKosmos().apply { testDispatcher = UnconfinedTestDispatcher() }
+    @Mock private lateinit var profileManager: LocalBluetoothProfileManager
+    @Mock private lateinit var leAudioProfile: LeAudioProfile
+    private val updateFlow = MutableSharedFlow<Unit>()
+    private lateinit var underTest: AudioSharingDialogViewModel
+
+    @Before
+    fun setUp() {
+        with(kosmos) {
+            // TODO(b/364515243): use real object instead of mock
+            whenever(deviceItemInteractor.deviceItemUpdateRequest).thenReturn(updateFlow)
+            whenever(deviceItemInteractor.deviceItemUpdate)
+                .thenReturn(MutableStateFlow(emptyList()))
+            underTest = audioSharingDialogViewModel
+        }
+    }
+
+    @Test
+    fun testDialogState_show() =
+        with(kosmos) {
+            testScope.runTest {
+                val deviceName = "name"
+                whenever(cachedBluetoothDevice.name).thenReturn(deviceName)
+                val actual by collectLastValue(underTest.dialogState)
+                runCurrent()
+                assertThat(actual)
+                    .isEqualTo(
+                        AudioSharingDialogState.Show(
+                            context.getString(
+                                R.string.quick_settings_bluetooth_audio_sharing_dialog_subtitle,
+                                deviceName,
+                                ""
+                            ),
+                            context.getString(
+                                R.string
+                                    .quick_settings_bluetooth_audio_sharing_dialog_switch_to_button,
+                                deviceName
+                            )
+                        )
+                    )
+            }
+        }
+
+    @Test
+    fun testDialogState_showWithActiveDeviceName() =
+        with(kosmos) {
+            testScope.runTest {
+                val deviceName = "name"
+                whenever(cachedBluetoothDevice.name).thenReturn(deviceName)
+                whenever(localBluetoothManager.profileManager).thenReturn(profileManager)
+                whenever(localBluetoothManager.cachedDeviceManager)
+                    .thenReturn(cachedBluetoothDeviceManager)
+                whenever(profileManager.leAudioProfile).thenReturn(leAudioProfile)
+                whenever(leAudioProfile.activeDevices).thenReturn(listOf(mock<BluetoothDevice>()))
+                whenever(cachedBluetoothDeviceManager.findDevice(any()))
+                    .thenReturn(cachedBluetoothDevice)
+                val actual by collectLastValue(underTest.dialogState)
+                runCurrent()
+                assertThat(actual)
+                    .isEqualTo(
+                        AudioSharingDialogState.Show(
+                            context.getString(
+                                R.string.quick_settings_bluetooth_audio_sharing_dialog_subtitle,
+                                deviceName,
+                                deviceName
+                            ),
+                            context.getString(
+                                R.string
+                                    .quick_settings_bluetooth_audio_sharing_dialog_switch_to_button,
+                                deviceName
+                            )
+                        )
+                    )
+            }
+        }
+
+    @Test
+    fun testDialogState_hide() =
+        with(kosmos) {
+            testScope.runTest {
+                val actual by collectLastValue(underTest.dialogState)
+                runCurrent()
+                updateFlow.emit(Unit)
+                assertThat(actual).isEqualTo(AudioSharingDialogState.Hide)
+            }
+        }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/AudioSharingInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/AudioSharingInteractorTest.kt
index 2c53fd6..25f9565 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/AudioSharingInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/AudioSharingInteractorTest.kt
@@ -16,158 +16,197 @@
 
 package com.android.systemui.bluetooth.qsdialog
 
+import android.bluetooth.BluetoothLeBroadcast
 import android.testing.TestableLooper
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession
-import com.android.dx.mockito.inline.extended.StaticMockitoSession
-import com.android.settingslib.bluetooth.BluetoothUtils
-import com.android.settingslib.bluetooth.CachedBluetoothDevice
-import com.android.settingslib.bluetooth.LocalBluetoothManager
+import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcast
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.coroutines.collectLastValue
-import com.android.systemui.res.R
-import com.android.systemui.util.mockito.whenever
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.testKosmos
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.ExperimentalCoroutinesApi
-import kotlinx.coroutines.flow.MutableSharedFlow
-import kotlinx.coroutines.flow.MutableStateFlow
-import kotlinx.coroutines.test.TestScope
-import kotlinx.coroutines.test.UnconfinedTestDispatcher
+import kotlinx.coroutines.launch
 import kotlinx.coroutines.test.runCurrent
 import kotlinx.coroutines.test.runTest
-import org.junit.After
 import org.junit.Before
+import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
+import org.mockito.ArgumentCaptor
+import org.mockito.Captor
 import org.mockito.Mock
+import org.mockito.Mockito.verify
+import org.mockito.junit.MockitoJUnit
+import org.mockito.junit.MockitoRule
+import org.mockito.kotlin.any
 
-@ExperimentalCoroutinesApi
 @SmallTest
 @RunWith(AndroidJUnit4::class)
 @TestableLooper.RunWithLooper(setAsMainLooper = true)
+@OptIn(ExperimentalCoroutinesApi::class)
 class AudioSharingInteractorTest : SysuiTestCase() {
-    private val testDispatcher = UnconfinedTestDispatcher()
-    private val testScope = TestScope(testDispatcher)
-    private val bluetoothState = MutableStateFlow(false)
-    private val deviceItemUpdate: MutableSharedFlow<List<DeviceItem>> = MutableSharedFlow()
-    @Mock private lateinit var cachedBluetoothDevice: CachedBluetoothDevice
-    @Mock private lateinit var localBluetoothManager: LocalBluetoothManager
-    @Mock private lateinit var bluetoothStateInteractor: BluetoothStateInteractor
-    @Mock private lateinit var deviceItemInteractor: DeviceItemInteractor
-    @Mock private lateinit var deviceItem: DeviceItem
-    private lateinit var mockitoSession: StaticMockitoSession
-    private lateinit var audioSharingInteractor: AudioSharingInteractor
+    @get:Rule val mockito: MockitoRule = MockitoJUnit.rule()
+    private val kosmos = testKosmos()
+    @Mock private lateinit var localBluetoothLeBroadcast: LocalBluetoothLeBroadcast
+    @Captor private lateinit var callbackCaptor: ArgumentCaptor<BluetoothLeBroadcast.Callback>
+    private lateinit var underTest: AudioSharingInteractor
 
     @Before
     fun setUp() {
-        mockitoSession =
-            mockitoSession().initMocks(this).mockStatic(BluetoothUtils::class.java).startMocking()
-        whenever(bluetoothStateInteractor.bluetoothStateUpdate).thenReturn(bluetoothState)
-        whenever(deviceItemInteractor.deviceItemUpdate).thenReturn(deviceItemUpdate)
-        audioSharingInteractor =
-            AudioSharingInteractor(
-                localBluetoothManager,
-                bluetoothStateInteractor,
-                deviceItemInteractor,
-                testScope.backgroundScope,
-                testDispatcher,
-            )
-    }
-
-    @After
-    fun tearDown() {
-        mockitoSession.finishMocking()
+        with(kosmos) { underTest = audioSharingInteractor }
     }
 
     @Test
-    fun testButtonStateUpdate_bluetoothOff_returnGone() {
-        testScope.runTest {
-            val actual by collectLastValue(audioSharingInteractor.audioSharingButtonStateUpdate)
+    fun testIsAudioSharingOn_flagOff_false() =
+        with(kosmos) {
+            testScope.runTest {
+                bluetoothTileDialogAudioSharingRepository.setAudioSharingAvailable(false)
+                val value by collectLastValue(underTest.isAudioSharingOn)
+                runCurrent()
 
-            assertThat(actual).isEqualTo(AudioSharingButtonState.Gone)
+                assertThat(value).isFalse()
+            }
         }
-    }
 
     @Test
-    fun testButtonStateUpdate_noDevice_returnGone() {
-        testScope.runTest {
-            val actual by collectLastValue(audioSharingInteractor.audioSharingButtonStateUpdate)
-            bluetoothState.value = true
-            runCurrent()
+    fun testIsAudioSharingOn_flagOn_notInAudioSharing_false() =
+        with(kosmos) {
+            testScope.runTest {
+                bluetoothTileDialogAudioSharingRepository.setAudioSharingAvailable(true)
+                bluetoothTileDialogAudioSharingRepository.setInAudioSharing(false)
+                val value by collectLastValue(underTest.isAudioSharingOn)
+                runCurrent()
 
-            assertThat(actual).isEqualTo(AudioSharingButtonState.Gone)
+                assertThat(value).isFalse()
+            }
         }
-    }
 
     @Test
-    fun testButtonStateUpdate_isBroadcasting_returnSharingAudio() {
-        testScope.runTest {
-            whenever(BluetoothUtils.isBroadcasting(localBluetoothManager)).thenReturn(true)
+    fun testIsAudioSharingOn_flagOn_inAudioSharing_true() =
+        with(kosmos) {
+            testScope.runTest {
+                bluetoothTileDialogAudioSharingRepository.setAudioSharingAvailable(true)
+                bluetoothTileDialogAudioSharingRepository.setInAudioSharing(true)
+                val value by collectLastValue(underTest.isAudioSharingOn)
+                runCurrent()
 
-            val actual by collectLastValue(audioSharingInteractor.audioSharingButtonStateUpdate)
-            bluetoothState.value = true
-            deviceItemUpdate.emit(listOf())
-            runCurrent()
+                assertThat(value).isTrue()
+            }
+        }
 
-            assertThat(actual)
-                .isEqualTo(
-                    AudioSharingButtonState.Visible(
-                        R.string.quick_settings_bluetooth_audio_sharing_button_sharing,
-                        isActive = true
-                    )
+    @Test
+    fun testAudioSourceStateUpdate_notInAudioSharing_returnEmpty() =
+        with(kosmos) {
+            testScope.runTest {
+                bluetoothTileDialogAudioSharingRepository.setAudioSharingAvailable(true)
+                bluetoothTileDialogAudioSharingRepository.setInAudioSharing(false)
+                val value by collectLastValue(underTest.audioSourceStateUpdate)
+                runCurrent()
+
+                assertThat(value).isNull()
+            }
+        }
+
+    @Test
+    fun testAudioSourceStateUpdate_inAudioSharing_returnUnit() =
+        with(kosmos) {
+            testScope.runTest {
+                bluetoothTileDialogAudioSharingRepository.setAudioSharingAvailable(true)
+                bluetoothTileDialogAudioSharingRepository.setInAudioSharing(true)
+                val value by collectLastValue(underTest.audioSourceStateUpdate)
+                runCurrent()
+                bluetoothTileDialogAudioSharingRepository.emitAudioSourceStateUpdate()
+                runCurrent()
+
+                assertThat(value).isNull()
+            }
+        }
+
+    @Test
+    fun testHandleAudioSourceWhenReady_flagOff_sourceNotAdded() =
+        with(kosmos) {
+            testScope.runTest {
+                bluetoothTileDialogAudioSharingRepository.setAudioSharingAvailable(false)
+                val job = launch { underTest.handleAudioSourceWhenReady() }
+                runCurrent()
+
+                assertThat(bluetoothTileDialogAudioSharingRepository.sourceAdded).isFalse()
+                job.cancel()
+            }
+        }
+
+    @Test
+    fun testHandleAudioSourceWhenReady_noProfile_sourceNotAdded() =
+        with(kosmos) {
+            testScope.runTest {
+                bluetoothTileDialogAudioSharingRepository.setAudioSharingAvailable(true)
+                bluetoothTileDialogAudioSharingRepository.setLeAudioBroadcastProfile(null)
+                val job = launch { underTest.handleAudioSourceWhenReady() }
+                runCurrent()
+
+                assertThat(bluetoothTileDialogAudioSharingRepository.sourceAdded).isFalse()
+                job.cancel()
+            }
+        }
+
+    @Test
+    fun testHandleAudioSourceWhenReady_hasProfileButAudioSharingOff_sourceNotAdded() =
+        with(kosmos) {
+            testScope.runTest {
+                bluetoothTileDialogAudioSharingRepository.setInAudioSharing(false)
+                bluetoothTileDialogAudioSharingRepository.setAudioSharingAvailable(true)
+                bluetoothTileDialogAudioSharingRepository.setLeAudioBroadcastProfile(
+                    localBluetoothLeBroadcast
                 )
+                val job = launch { underTest.handleAudioSourceWhenReady() }
+                runCurrent()
+
+                assertThat(bluetoothTileDialogAudioSharingRepository.sourceAdded).isFalse()
+                job.cancel()
+            }
         }
-    }
 
     @Test
-    fun testButtonStateUpdate_hasSource_returnGone() {
-        testScope.runTest {
-            whenever(BluetoothUtils.isBroadcasting(localBluetoothManager)).thenReturn(false)
-            whenever(deviceItem.cachedBluetoothDevice).thenReturn(cachedBluetoothDevice)
-            whenever(
-                    BluetoothUtils.hasConnectedBroadcastSource(
-                        cachedBluetoothDevice,
-                        localBluetoothManager
-                    )
+    fun testHandleAudioSourceWhenReady_audioSharingOnButNoPlayback_sourceNotAdded() =
+        with(kosmos) {
+            testScope.runTest {
+                bluetoothTileDialogAudioSharingRepository.setInAudioSharing(true)
+                bluetoothTileDialogAudioSharingRepository.setAudioSharingAvailable(true)
+                bluetoothTileDialogAudioSharingRepository.setLeAudioBroadcastProfile(
+                    localBluetoothLeBroadcast
                 )
-                .thenReturn(true)
+                val job = launch { underTest.handleAudioSourceWhenReady() }
+                runCurrent()
+                verify(localBluetoothLeBroadcast)
+                    .registerServiceCallBack(any(), callbackCaptor.capture())
+                runCurrent()
 
-            val actual by collectLastValue(audioSharingInteractor.audioSharingButtonStateUpdate)
-            bluetoothState.value = true
-            deviceItemUpdate.emit(listOf(deviceItem))
-            runCurrent()
-
-            assertThat(actual).isEqualTo(AudioSharingButtonState.Gone)
+                assertThat(bluetoothTileDialogAudioSharingRepository.sourceAdded).isFalse()
+                job.cancel()
+            }
         }
-    }
 
     @Test
-    fun testButtonStateUpdate_hasActiveDevice_returnAudioSharing() {
-        testScope.runTest {
-            whenever(BluetoothUtils.isBroadcasting(localBluetoothManager)).thenReturn(false)
-            whenever(deviceItem.cachedBluetoothDevice).thenReturn(cachedBluetoothDevice)
-            whenever(
-                    BluetoothUtils.hasConnectedBroadcastSource(
-                        cachedBluetoothDevice,
-                        localBluetoothManager
-                    )
+    fun testHandleAudioSourceWhenReady_audioSharingOnAndPlaybackStarts_sourceAdded() =
+        with(kosmos) {
+            testScope.runTest {
+                bluetoothTileDialogAudioSharingRepository.setInAudioSharing(true)
+                bluetoothTileDialogAudioSharingRepository.setAudioSharingAvailable(true)
+                bluetoothTileDialogAudioSharingRepository.setLeAudioBroadcastProfile(
+                    localBluetoothLeBroadcast
                 )
-                .thenReturn(false)
-            whenever(BluetoothUtils.isActiveLeAudioDevice(cachedBluetoothDevice)).thenReturn(true)
+                val job = launch { underTest.handleAudioSourceWhenReady() }
+                runCurrent()
+                verify(localBluetoothLeBroadcast)
+                    .registerServiceCallBack(any(), callbackCaptor.capture())
+                runCurrent()
+                callbackCaptor.value.onPlaybackStarted(0, 0)
+                runCurrent()
 
-            val actual by collectLastValue(audioSharingInteractor.audioSharingButtonStateUpdate)
-            bluetoothState.value = true
-            deviceItemUpdate.emit(listOf(deviceItem))
-            runCurrent()
-
-            assertThat(actual)
-                .isEqualTo(
-                    AudioSharingButtonState.Visible(
-                        R.string.quick_settings_bluetooth_audio_sharing_button,
-                        isActive = false
-                    )
-                )
+                assertThat(bluetoothTileDialogAudioSharingRepository.sourceAdded).isTrue()
+                job.cancel()
+            }
         }
-    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/AudioSharingRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/AudioSharingRepositoryTest.kt
new file mode 100644
index 0000000..c9e8813
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/AudioSharingRepositoryTest.kt
@@ -0,0 +1,183 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.bluetooth.qsdialog
+
+import android.bluetooth.BluetoothDevice
+import android.bluetooth.BluetoothLeBroadcastMetadata
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import androidx.test.filters.SmallTest
+import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcast
+import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastAssistant
+import com.android.settingslib.bluetooth.LocalBluetoothProfileManager
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.kosmos.testDispatcher
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.testKosmos
+import com.android.systemui.volume.data.repository.audioSharingRepository
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.runCurrent
+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.ArgumentMatchers.anyBoolean
+import org.mockito.Mock
+import org.mockito.junit.MockitoJUnit
+import org.mockito.junit.MockitoRule
+import org.mockito.kotlin.any
+import org.mockito.kotlin.never
+import org.mockito.kotlin.verify
+import org.mockito.kotlin.whenever
+
+@ExperimentalCoroutinesApi
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
+class AudioSharingRepositoryTest : SysuiTestCase() {
+    @get:Rule val mockitoRule: MockitoRule = MockitoJUnit.rule()
+    @Mock private lateinit var profileManager: LocalBluetoothProfileManager
+    @Mock private lateinit var leAudioBroadcastProfile: LocalBluetoothLeBroadcast
+    @Mock private lateinit var leAudioBroadcastAssistant: LocalBluetoothLeBroadcastAssistant
+    @Mock private lateinit var metadata: BluetoothLeBroadcastMetadata
+    @Mock private lateinit var bluetoothDevice: BluetoothDevice
+    private val kosmos = testKosmos()
+    private lateinit var underTest: AudioSharingRepository
+
+    @Before
+    fun setUp() {
+        underTest =
+            AudioSharingRepositoryImpl(
+                kosmos.localBluetoothManager,
+                kosmos.audioSharingRepository,
+                kosmos.testDispatcher,
+            )
+    }
+
+    @Test
+    fun testSwitchActive() =
+        with(kosmos) {
+            testScope.runTest {
+                audioSharingRepository.setAudioSharingAvailable(true)
+                underTest.setActive(cachedBluetoothDevice)
+                verify(cachedBluetoothDevice).setActive()
+            }
+        }
+
+    @Test
+    fun testSwitchActive_flagOff_doNothing() =
+        with(kosmos) {
+            testScope.runTest {
+                audioSharingRepository.setAudioSharingAvailable(false)
+                underTest.setActive(cachedBluetoothDevice)
+                verify(cachedBluetoothDevice, never()).setActive()
+            }
+        }
+
+    @Test
+    fun testStartAudioSharing() =
+        with(kosmos) {
+            testScope.runTest {
+                whenever(localBluetoothManager.profileManager).thenReturn(profileManager)
+                whenever(profileManager.leAudioBroadcastProfile).thenReturn(leAudioBroadcastProfile)
+                audioSharingRepository.setAudioSharingAvailable(true)
+                underTest.startAudioSharing()
+                verify(leAudioBroadcastProfile).startPrivateBroadcast()
+            }
+        }
+
+    @Test
+    fun testStartAudioSharing_flagOff_doNothing() =
+        with(kosmos) {
+            testScope.runTest {
+                audioSharingRepository.setAudioSharingAvailable(false)
+                underTest.startAudioSharing()
+                verify(leAudioBroadcastProfile, never()).startPrivateBroadcast()
+            }
+        }
+
+    @Test
+    fun testAddSource_flagOff_doesNothing() =
+        with(kosmos) {
+            testScope.runTest {
+                audioSharingRepository.setAudioSharingAvailable(false)
+
+                underTest.addSource()
+                runCurrent()
+
+                verify(leAudioBroadcastAssistant, never()).allConnectedDevices
+            }
+        }
+
+    @Test
+    fun testAddSource_noMetadata_doesNothing() =
+        with(kosmos) {
+            testScope.runTest {
+                whenever(localBluetoothManager.profileManager).thenReturn(profileManager)
+                whenever(profileManager.leAudioBroadcastProfile).thenReturn(leAudioBroadcastProfile)
+                audioSharingRepository.setAudioSharingAvailable(true)
+                whenever(leAudioBroadcastProfile.latestBluetoothLeBroadcastMetadata)
+                    .thenReturn(null)
+
+                underTest.addSource()
+                runCurrent()
+
+                verify(leAudioBroadcastAssistant, never()).allConnectedDevices
+            }
+        }
+
+    @Test
+    fun testAddSource_noConnectedDevice_doesNothing() =
+        with(kosmos) {
+            testScope.runTest {
+                whenever(localBluetoothManager.profileManager).thenReturn(profileManager)
+                whenever(profileManager.leAudioBroadcastProfile).thenReturn(leAudioBroadcastProfile)
+                whenever(profileManager.leAudioBroadcastAssistantProfile)
+                    .thenReturn(leAudioBroadcastAssistant)
+                audioSharingRepository.setAudioSharingAvailable(true)
+                whenever(leAudioBroadcastProfile.latestBluetoothLeBroadcastMetadata)
+                    .thenReturn(metadata)
+                whenever(leAudioBroadcastAssistant.allConnectedDevices).thenReturn(emptyList())
+
+                underTest.addSource()
+                runCurrent()
+
+                verify(leAudioBroadcastAssistant, never()).addSource(any(), any(), anyBoolean())
+            }
+        }
+
+    @Test
+    fun testAddSource_hasConnectedDeviceAndMetadata_addSource() =
+        with(kosmos) {
+            testScope.runTest {
+                whenever(localBluetoothManager.profileManager).thenReturn(profileManager)
+                whenever(profileManager.leAudioBroadcastProfile).thenReturn(leAudioBroadcastProfile)
+                whenever(profileManager.leAudioBroadcastAssistantProfile)
+                    .thenReturn(leAudioBroadcastAssistant)
+                audioSharingRepository.setAudioSharingAvailable(true)
+                whenever(leAudioBroadcastProfile.latestBluetoothLeBroadcastMetadata)
+                    .thenReturn(metadata)
+                whenever(leAudioBroadcastAssistant.allConnectedDevices)
+                    .thenReturn(listOf(bluetoothDevice))
+
+                underTest.addSource()
+                runCurrent()
+
+                verify(leAudioBroadcastAssistant).addSource(bluetoothDevice, metadata, false)
+            }
+        }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogViewModelTest.kt
index d7bea66..a56c2cb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogViewModelTest.kt
@@ -31,8 +31,11 @@
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.animation.DialogTransitionAnimator
 import com.android.systemui.animation.Expandable
+import com.android.systemui.kosmos.testDispatcher
+import com.android.systemui.kosmos.testScope
 import com.android.systemui.plugins.ActivityStarter
 import com.android.systemui.statusbar.phone.SystemUIDialog
+import com.android.systemui.testKosmos
 import com.android.systemui.util.FakeSharedPreferences
 import com.android.systemui.util.concurrency.FakeExecutor
 import com.android.systemui.util.kotlin.getMutableStateFlow
@@ -42,12 +45,12 @@
 import com.android.systemui.util.time.FakeSystemClock
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.flow.MutableSharedFlow
 import kotlinx.coroutines.flow.MutableStateFlow
 import kotlinx.coroutines.flow.asStateFlow
-import kotlinx.coroutines.test.TestCoroutineScheduler
 import kotlinx.coroutines.test.TestScope
-import kotlinx.coroutines.test.UnconfinedTestDispatcher
+import kotlinx.coroutines.test.runCurrent
 import kotlinx.coroutines.test.runTest
 import org.junit.Before
 import org.junit.Rule
@@ -64,10 +67,12 @@
 @SmallTest
 @RunWith(AndroidJUnit4::class)
 @TestableLooper.RunWithLooper(setAsMainLooper = true)
+@OptIn(ExperimentalCoroutinesApi::class)
 @EnableFlags(Flags.FLAG_BLUETOOTH_QS_TILE_DIALOG_AUTO_ON_TOGGLE)
 class BluetoothTileDialogViewModelTest : SysuiTestCase() {
 
     @get:Rule val mockitoRule: MockitoRule = MockitoJUnit.rule()
+    private val kosmos = testKosmos()
     private val fakeSystemClock = FakeSystemClock()
     private val backgroundExecutor = FakeExecutor(fakeSystemClock)
 
@@ -75,8 +80,6 @@
 
     @Mock private lateinit var bluetoothStateInteractor: BluetoothStateInteractor
 
-    @Mock private lateinit var audioSharingInteractor: AudioSharingInteractor
-
     @Mock private lateinit var bluetoothDeviceMetadataInteractor: BluetoothDeviceMetadataInteractor
 
     @Mock private lateinit var deviceItemInteractor: DeviceItemInteractor
@@ -111,15 +114,15 @@
 
     private val sharedPreferences = FakeSharedPreferences()
 
-    private lateinit var scheduler: TestCoroutineScheduler
     private lateinit var dispatcher: CoroutineDispatcher
     private lateinit var testScope: TestScope
 
     @Before
     fun setUp() {
-        scheduler = TestCoroutineScheduler()
-        dispatcher = UnconfinedTestDispatcher(scheduler)
-        testScope = TestScope(dispatcher)
+        dispatcher = kosmos.testDispatcher
+        testScope = kosmos.testScope
+        // TODO(b/364515243): use real object instead of mock
+        whenever(kosmos.deviceItemInteractor.deviceItemUpdate).thenReturn(MutableSharedFlow())
         bluetoothTileDialogViewModel =
             BluetoothTileDialogViewModel(
                 deviceItemInteractor,
@@ -139,11 +142,13 @@
                         dispatcher
                     )
                 ),
-                audioSharingInteractor,
+                kosmos.audioSharingInteractor,
+                kosmos.audioSharingButtonViewModelFactory,
                 bluetoothDeviceMetadataInteractor,
                 mDialogTransitionAnimator,
                 activityStarter,
                 uiEventLogger,
+                bluetoothTileDialogLogger,
                 testScope.backgroundScope,
                 dispatcher,
                 dispatcher,
@@ -161,13 +166,10 @@
         whenever(sysuiDialog.context).thenReturn(mContext)
         whenever(bluetoothTileDialogDelegate.bluetoothStateToggle)
             .thenReturn(getMutableStateFlow(false))
-        whenever(bluetoothTileDialogDelegate.deviceItemClick)
-            .thenReturn(getMutableStateFlow(deviceItem))
+        whenever(bluetoothTileDialogDelegate.deviceItemClick).thenReturn(MutableSharedFlow())
         whenever(bluetoothTileDialogDelegate.contentHeight).thenReturn(getMutableStateFlow(0))
         whenever(bluetoothTileDialogDelegate.bluetoothAutoOnToggle)
             .thenReturn(getMutableStateFlow(false))
-        whenever(audioSharingInteractor.audioSharingButtonStateUpdate)
-            .thenReturn(getMutableStateFlow(AudioSharingButtonState.Gone))
         whenever(expandable.dialogTransitionController(any())).thenReturn(controller)
     }
 
@@ -175,6 +177,7 @@
     fun testShowDialog_noAnimation() {
         testScope.runTest {
             bluetoothTileDialogViewModel.showDialog(null)
+            runCurrent()
 
             verify(mDialogTransitionAnimator, never()).show(any(), any(), any())
         }
@@ -184,6 +187,7 @@
     fun testShowDialog_animated() {
         testScope.runTest {
             bluetoothTileDialogViewModel.showDialog(expandable)
+            runCurrent()
 
             verify(mDialogTransitionAnimator).show(any(), any(), anyBoolean())
         }
@@ -194,6 +198,7 @@
         testScope.runTest {
             backgroundExecutor.execute {
                 bluetoothTileDialogViewModel.showDialog(expandable)
+                runCurrent()
 
                 verify(mDialogTransitionAnimator).show(any(), any(), anyBoolean())
             }
@@ -204,6 +209,7 @@
     fun testShowDialog_fetchDeviceItem() {
         testScope.runTest {
             bluetoothTileDialogViewModel.showDialog(null)
+            runCurrent()
 
             verify(deviceItemInteractor).deviceItemUpdate
         }
@@ -214,6 +220,7 @@
         testScope.runTest {
             whenever(deviceItem.cachedBluetoothDevice).thenReturn(cachedBluetoothDevice)
             bluetoothTileDialogViewModel.showDialog(null)
+            runCurrent()
 
             val clickedView = View(context)
             bluetoothTileDialogViewModel.onPairNewDeviceClicked(clickedView)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/DeviceItemActionInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/DeviceItemActionInteractorTest.kt
index 681ea75..9c427c6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/DeviceItemActionInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/DeviceItemActionInteractorTest.kt
@@ -15,34 +15,22 @@
  */
 package com.android.systemui.bluetooth.qsdialog
 
-import android.bluetooth.BluetoothDevice
 import android.testing.AndroidTestingRunner
 import android.testing.TestableLooper
 import androidx.test.filters.SmallTest
-import com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession
-import com.android.dx.mockito.inline.extended.StaticMockitoSession
-import com.android.settingslib.bluetooth.BluetoothUtils
-import com.android.settingslib.bluetooth.CachedBluetoothDevice
-import com.android.settingslib.bluetooth.LeAudioProfile
-import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastAssistant
-import com.android.settingslib.bluetooth.LocalBluetoothProfileManager
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.kosmos.testDispatcher
 import com.android.systemui.kosmos.testScope
-import com.android.systemui.plugins.activityStarter
 import com.android.systemui.statusbar.phone.SystemUIDialog
 import com.android.systemui.testKosmos
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.test.UnconfinedTestDispatcher
 import kotlinx.coroutines.test.runTest
-import org.junit.After
 import org.junit.Before
 import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
-import org.mockito.ArgumentMatchers
 import org.mockito.Mock
-import org.mockito.Mockito
 import org.mockito.Mockito.verify
 import org.mockito.junit.MockitoJUnit
 import org.mockito.junit.MockitoRule
@@ -56,28 +44,18 @@
     @get:Rule val mockitoRule: MockitoRule = MockitoJUnit.rule()
     private val kosmos = testKosmos().apply { testDispatcher = UnconfinedTestDispatcher() }
     private lateinit var actionInteractorImpl: DeviceItemActionInteractor
-    private lateinit var mockitoSession: StaticMockitoSession
     private lateinit var activeMediaDeviceItem: DeviceItem
     private lateinit var notConnectedDeviceItem: DeviceItem
-    private lateinit var connectedAudioSharingMediaDeviceItem: DeviceItem
     private lateinit var connectedMediaDeviceItem: DeviceItem
     private lateinit var connectedOtherDeviceItem: DeviceItem
     @Mock private lateinit var dialog: SystemUIDialog
-    @Mock private lateinit var profileManager: LocalBluetoothProfileManager
-    @Mock private lateinit var leAudioProfile: LeAudioProfile
-    @Mock private lateinit var assistantProfile: LocalBluetoothLeBroadcastAssistant
-    @Mock private lateinit var bluetoothDevice: BluetoothDevice
-    @Mock private lateinit var bluetoothDeviceGroupId2: BluetoothDevice
-    @Mock private lateinit var cachedBluetoothDevice: CachedBluetoothDevice
 
     @Before
     fun setUp() {
-        mockitoSession =
-            mockitoSession().initMocks(this).mockStatic(BluetoothUtils::class.java).startMocking()
         activeMediaDeviceItem =
             DeviceItem(
                 type = DeviceItemType.ACTIVE_MEDIA_BLUETOOTH_DEVICE,
-                cachedBluetoothDevice = cachedBluetoothDevice,
+                cachedBluetoothDevice = kosmos.cachedBluetoothDevice,
                 deviceName = DEVICE_NAME,
                 connectionSummary = DEVICE_CONNECTION_SUMMARY,
                 iconWithDescription = null,
@@ -86,7 +64,7 @@
         notConnectedDeviceItem =
             DeviceItem(
                 type = DeviceItemType.SAVED_BLUETOOTH_DEVICE,
-                cachedBluetoothDevice = cachedBluetoothDevice,
+                cachedBluetoothDevice = kosmos.cachedBluetoothDevice,
                 deviceName = DEVICE_NAME,
                 connectionSummary = DEVICE_CONNECTION_SUMMARY,
                 iconWithDescription = null,
@@ -95,16 +73,7 @@
         connectedMediaDeviceItem =
             DeviceItem(
                 type = DeviceItemType.AVAILABLE_MEDIA_BLUETOOTH_DEVICE,
-                cachedBluetoothDevice = cachedBluetoothDevice,
-                deviceName = DEVICE_NAME,
-                connectionSummary = DEVICE_CONNECTION_SUMMARY,
-                iconWithDescription = null,
-                background = null
-            )
-        connectedAudioSharingMediaDeviceItem =
-            DeviceItem(
-                type = DeviceItemType.AVAILABLE_AUDIO_SHARING_MEDIA_BLUETOOTH_DEVICE,
-                cachedBluetoothDevice = cachedBluetoothDevice,
+                cachedBluetoothDevice = kosmos.cachedBluetoothDevice,
                 deviceName = DEVICE_NAME,
                 connectionSummary = DEVICE_CONNECTION_SUMMARY,
                 iconWithDescription = null,
@@ -113,18 +82,13 @@
         connectedOtherDeviceItem =
             DeviceItem(
                 type = DeviceItemType.CONNECTED_BLUETOOTH_DEVICE,
-                cachedBluetoothDevice = cachedBluetoothDevice,
+                cachedBluetoothDevice = kosmos.cachedBluetoothDevice,
                 deviceName = DEVICE_NAME,
                 connectionSummary = DEVICE_CONNECTION_SUMMARY,
                 iconWithDescription = null,
                 background = null
             )
-        actionInteractorImpl = kosmos.deviceItemActionInteractor
-    }
-
-    @After
-    fun tearDown() {
-        mockitoSession.finishMocking()
+        actionInteractorImpl = kosmos.deviceItemActionInteractorImpl
     }
 
     @Test
@@ -132,14 +96,8 @@
         with(kosmos) {
             testScope.runTest {
                 whenever(cachedBluetoothDevice.address).thenReturn(DEVICE_ADDRESS)
-                whenever(BluetoothUtils.isAudioSharingEnabled()).thenReturn(false)
                 actionInteractorImpl.onClick(connectedMediaDeviceItem, dialog)
                 verify(cachedBluetoothDevice).setActive()
-                verify(bluetoothTileDialogLogger)
-                    .logDeviceClick(
-                        cachedBluetoothDevice.address,
-                        DeviceItemType.AVAILABLE_MEDIA_BLUETOOTH_DEVICE
-                    )
             }
         }
     }
@@ -149,14 +107,8 @@
         with(kosmos) {
             testScope.runTest {
                 whenever(cachedBluetoothDevice.address).thenReturn(DEVICE_ADDRESS)
-                whenever(BluetoothUtils.isAudioSharingEnabled()).thenReturn(false)
                 actionInteractorImpl.onClick(activeMediaDeviceItem, dialog)
                 verify(cachedBluetoothDevice).disconnect()
-                verify(bluetoothTileDialogLogger)
-                    .logDeviceClick(
-                        cachedBluetoothDevice.address,
-                        DeviceItemType.ACTIVE_MEDIA_BLUETOOTH_DEVICE
-                    )
             }
         }
     }
@@ -166,14 +118,8 @@
         with(kosmos) {
             testScope.runTest {
                 whenever(cachedBluetoothDevice.address).thenReturn(DEVICE_ADDRESS)
-                whenever(BluetoothUtils.isAudioSharingEnabled()).thenReturn(false)
                 actionInteractorImpl.onClick(connectedOtherDeviceItem, dialog)
                 verify(cachedBluetoothDevice).disconnect()
-                verify(bluetoothTileDialogLogger)
-                    .logDeviceClick(
-                        cachedBluetoothDevice.address,
-                        DeviceItemType.CONNECTED_BLUETOOTH_DEVICE
-                    )
             }
         }
     }
@@ -183,293 +129,8 @@
         with(kosmos) {
             testScope.runTest {
                 whenever(cachedBluetoothDevice.address).thenReturn(DEVICE_ADDRESS)
-                whenever(BluetoothUtils.isAudioSharingEnabled()).thenReturn(false)
                 actionInteractorImpl.onClick(notConnectedDeviceItem, dialog)
                 verify(cachedBluetoothDevice).connect()
-                verify(bluetoothTileDialogLogger)
-                    .logDeviceClick(
-                        cachedBluetoothDevice.address,
-                        DeviceItemType.SAVED_BLUETOOTH_DEVICE
-                    )
-            }
-        }
-    }
-
-    @Test
-    fun testOnClick_connectedAudioSharingMediaDevice_logClick() {
-        with(kosmos) {
-            testScope.runTest {
-                whenever(cachedBluetoothDevice.address).thenReturn(DEVICE_ADDRESS)
-                actionInteractorImpl.onClick(connectedAudioSharingMediaDeviceItem, dialog)
-                verify(bluetoothTileDialogLogger)
-                    .logDeviceClick(
-                        cachedBluetoothDevice.address,
-                        DeviceItemType.AVAILABLE_AUDIO_SHARING_MEDIA_BLUETOOTH_DEVICE
-                    )
-            }
-        }
-    }
-
-    @Test
-    fun testOnClick_audioSharingDisabled_shouldNotLaunchSettings() {
-        with(kosmos) {
-            testScope.runTest {
-                whenever(cachedBluetoothDevice.address).thenReturn(DEVICE_ADDRESS)
-                whenever(BluetoothUtils.isAudioSharingEnabled()).thenReturn(false)
-
-                actionInteractorImpl.onClick(connectedMediaDeviceItem, dialog)
-                verify(activityStarter, Mockito.never())
-                    .postStartActivityDismissingKeyguard(
-                        ArgumentMatchers.any(),
-                        ArgumentMatchers.anyInt(),
-                        ArgumentMatchers.any()
-                    )
-            }
-        }
-    }
-
-    @Test
-    fun testOnClick_inAudioSharing_clickedDeviceHasSource_shouldNotLaunchSettings() {
-        with(kosmos) {
-            testScope.runTest {
-                whenever(cachedBluetoothDevice.address).thenReturn(DEVICE_ADDRESS)
-                whenever(cachedBluetoothDevice.uiAccessibleProfiles)
-                    .thenReturn(listOf(leAudioProfile))
-
-                whenever(BluetoothUtils.isAudioSharingEnabled()).thenReturn(true)
-                whenever(localBluetoothManager.profileManager).thenReturn(profileManager)
-                whenever(profileManager.leAudioProfile).thenReturn(leAudioProfile)
-                whenever(profileManager.leAudioBroadcastAssistantProfile)
-                    .thenReturn(assistantProfile)
-
-                whenever(BluetoothUtils.isBroadcasting(ArgumentMatchers.any())).thenReturn(true)
-                whenever(
-                        BluetoothUtils.hasConnectedBroadcastSource(
-                            ArgumentMatchers.any(),
-                            ArgumentMatchers.any()
-                        )
-                    )
-                    .thenReturn(true)
-
-                actionInteractorImpl.onClick(connectedMediaDeviceItem, dialog)
-                verify(activityStarter, Mockito.never())
-                    .postStartActivityDismissingKeyguard(
-                        ArgumentMatchers.any(),
-                        ArgumentMatchers.anyInt(),
-                        ArgumentMatchers.any()
-                    )
-            }
-        }
-    }
-
-    @Test
-    fun testOnClick_inAudioSharing_clickedDeviceNoSource_shouldLaunchSettings() {
-        with(kosmos) {
-            testScope.runTest {
-                whenever(cachedBluetoothDevice.address).thenReturn(DEVICE_ADDRESS)
-                whenever(cachedBluetoothDevice.device).thenReturn(bluetoothDevice)
-                whenever(cachedBluetoothDevice.uiAccessibleProfiles)
-                    .thenReturn(listOf(leAudioProfile))
-
-                whenever(BluetoothUtils.isAudioSharingEnabled()).thenReturn(true)
-                whenever(localBluetoothManager.profileManager).thenReturn(profileManager)
-                whenever(profileManager.leAudioProfile).thenReturn(leAudioProfile)
-                whenever(profileManager.leAudioBroadcastAssistantProfile)
-                    .thenReturn(assistantProfile)
-
-                whenever(BluetoothUtils.isBroadcasting(ArgumentMatchers.any())).thenReturn(true)
-                whenever(
-                        BluetoothUtils.hasConnectedBroadcastSource(
-                            ArgumentMatchers.any(),
-                            ArgumentMatchers.any()
-                        )
-                    )
-                    .thenReturn(false)
-
-                actionInteractorImpl.onClick(connectedMediaDeviceItem, dialog)
-                verify(activityStarter)
-                    .postStartActivityDismissingKeyguard(
-                        ArgumentMatchers.any(),
-                        ArgumentMatchers.anyInt(),
-                        ArgumentMatchers.any()
-                    )
-            }
-        }
-    }
-
-    @Test
-    fun testOnClick_noConnectedLeDevice_shouldNotLaunchSettings() {
-        with(kosmos) {
-            testScope.runTest {
-                whenever(cachedBluetoothDevice.address).thenReturn(DEVICE_ADDRESS)
-
-                whenever(BluetoothUtils.isAudioSharingEnabled()).thenReturn(true)
-                whenever(localBluetoothManager.profileManager).thenReturn(profileManager)
-                whenever(profileManager.leAudioProfile).thenReturn(leAudioProfile)
-                whenever(profileManager.leAudioBroadcastAssistantProfile)
-                    .thenReturn(assistantProfile)
-
-                actionInteractorImpl.onClick(notConnectedDeviceItem, dialog)
-                verify(activityStarter, Mockito.never())
-                    .postStartActivityDismissingKeyguard(
-                        ArgumentMatchers.any(),
-                        ArgumentMatchers.anyInt(),
-                        ArgumentMatchers.any()
-                    )
-            }
-        }
-    }
-
-    @Test
-    fun testOnClick_hasOneConnectedLeDevice_clickedNonLe_shouldNotLaunchSettings() {
-        with(kosmos) {
-            testScope.runTest {
-                whenever(cachedBluetoothDevice.address).thenReturn(DEVICE_ADDRESS)
-
-                whenever(BluetoothUtils.isAudioSharingEnabled()).thenReturn(true)
-                whenever(localBluetoothManager.profileManager).thenReturn(profileManager)
-                whenever(profileManager.leAudioProfile).thenReturn(leAudioProfile)
-                whenever(profileManager.leAudioBroadcastAssistantProfile)
-                    .thenReturn(assistantProfile)
-
-                whenever(
-                        assistantProfile.getDevicesMatchingConnectionStates(ArgumentMatchers.any())
-                    )
-                    .thenReturn(listOf(bluetoothDevice))
-
-                actionInteractorImpl.onClick(notConnectedDeviceItem, dialog)
-                verify(activityStarter, Mockito.never())
-                    .postStartActivityDismissingKeyguard(
-                        ArgumentMatchers.any(),
-                        ArgumentMatchers.anyInt(),
-                        ArgumentMatchers.any()
-                    )
-            }
-        }
-    }
-
-    @Test
-    fun testOnClick_hasOneConnectedLeDevice_clickedLe_shouldLaunchSettings() {
-        with(kosmos) {
-            testScope.runTest {
-                whenever(cachedBluetoothDevice.device).thenReturn(bluetoothDevice)
-                whenever(cachedBluetoothDevice.address).thenReturn(DEVICE_ADDRESS)
-                whenever(cachedBluetoothDevice.profiles).thenReturn(listOf(leAudioProfile))
-                whenever(leAudioProfile.isEnabled(ArgumentMatchers.any())).thenReturn(true)
-
-                whenever(BluetoothUtils.isAudioSharingEnabled()).thenReturn(true)
-                whenever(localBluetoothManager.profileManager).thenReturn(profileManager)
-                whenever(profileManager.leAudioProfile).thenReturn(leAudioProfile)
-                whenever(profileManager.leAudioBroadcastAssistantProfile)
-                    .thenReturn(assistantProfile)
-
-                whenever(
-                        assistantProfile.getDevicesMatchingConnectionStates(ArgumentMatchers.any())
-                    )
-                    .thenReturn(listOf(bluetoothDevice))
-
-                actionInteractorImpl.onClick(notConnectedDeviceItem, dialog)
-                verify(activityStarter)
-                    .postStartActivityDismissingKeyguard(
-                        ArgumentMatchers.any(),
-                        ArgumentMatchers.anyInt(),
-                        ArgumentMatchers.any()
-                    )
-            }
-        }
-    }
-
-    @Test
-    fun testOnClick_hasOneConnectedLeDevice_clickedConnectedLe_shouldNotLaunchSettings() {
-        with(kosmos) {
-            testScope.runTest {
-                whenever(cachedBluetoothDevice.address).thenReturn(DEVICE_ADDRESS)
-
-                whenever(BluetoothUtils.isAudioSharingEnabled()).thenReturn(true)
-                whenever(localBluetoothManager.profileManager).thenReturn(profileManager)
-                whenever(profileManager.leAudioProfile).thenReturn(leAudioProfile)
-                whenever(profileManager.leAudioBroadcastAssistantProfile)
-                    .thenReturn(assistantProfile)
-
-                whenever(
-                        assistantProfile.getDevicesMatchingConnectionStates(ArgumentMatchers.any())
-                    )
-                    .thenReturn(listOf(bluetoothDevice))
-
-                actionInteractorImpl.onClick(connectedMediaDeviceItem, dialog)
-                verify(activityStarter, Mockito.never())
-                    .postStartActivityDismissingKeyguard(
-                        ArgumentMatchers.any(),
-                        ArgumentMatchers.anyInt(),
-                        ArgumentMatchers.any()
-                    )
-            }
-        }
-    }
-
-    @Test
-    fun testOnClick_hasTwoConnectedLeDevice_clickedNotConnectedLe_shouldNotLaunchSettings() {
-        with(kosmos) {
-            testScope.runTest {
-                whenever(cachedBluetoothDevice.address).thenReturn(DEVICE_ADDRESS)
-
-                whenever(BluetoothUtils.isAudioSharingEnabled()).thenReturn(true)
-                whenever(localBluetoothManager.profileManager).thenReturn(profileManager)
-                whenever(profileManager.leAudioProfile).thenReturn(leAudioProfile)
-                whenever(profileManager.leAudioBroadcastAssistantProfile)
-                    .thenReturn(assistantProfile)
-
-                whenever(
-                        assistantProfile.getDevicesMatchingConnectionStates(ArgumentMatchers.any())
-                    )
-                    .thenReturn(listOf(bluetoothDevice, bluetoothDeviceGroupId2))
-                whenever(leAudioProfile.getGroupId(ArgumentMatchers.any())).thenAnswer {
-                    val device = it.arguments.first() as BluetoothDevice
-                    if (device == bluetoothDevice) GROUP_ID_1 else GROUP_ID_2
-                }
-
-                actionInteractorImpl.onClick(notConnectedDeviceItem, dialog)
-                verify(activityStarter, Mockito.never())
-                    .postStartActivityDismissingKeyguard(
-                        ArgumentMatchers.any(),
-                        ArgumentMatchers.anyInt(),
-                        ArgumentMatchers.any()
-                    )
-            }
-        }
-    }
-
-    @Test
-    fun testOnClick_hasTwoConnectedLeDevice_clickedActiveLe_shouldLaunchSettings() {
-        with(kosmos) {
-            testScope.runTest {
-                whenever(cachedBluetoothDevice.device).thenReturn(bluetoothDevice)
-                whenever(cachedBluetoothDevice.address).thenReturn(DEVICE_ADDRESS)
-                whenever(cachedBluetoothDevice.profiles).thenReturn(listOf(leAudioProfile))
-                whenever(leAudioProfile.isEnabled(ArgumentMatchers.any())).thenReturn(true)
-
-                whenever(BluetoothUtils.isAudioSharingEnabled()).thenReturn(true)
-                whenever(localBluetoothManager.profileManager).thenReturn(profileManager)
-                whenever(profileManager.leAudioProfile).thenReturn(leAudioProfile)
-                whenever(profileManager.leAudioBroadcastAssistantProfile)
-                    .thenReturn(assistantProfile)
-
-                whenever(
-                        assistantProfile.getDevicesMatchingConnectionStates(ArgumentMatchers.any())
-                    )
-                    .thenReturn(listOf(bluetoothDevice, bluetoothDeviceGroupId2))
-                whenever(leAudioProfile.getGroupId(ArgumentMatchers.any())).thenAnswer {
-                    val device = it.arguments.first() as BluetoothDevice
-                    if (device == bluetoothDevice) GROUP_ID_1 else GROUP_ID_2
-                }
-
-                actionInteractorImpl.onClick(activeMediaDeviceItem, dialog)
-                verify(activityStarter)
-                    .postStartActivityDismissingKeyguard(
-                        ArgumentMatchers.any(),
-                        ArgumentMatchers.anyInt(),
-                        ArgumentMatchers.any()
-                    )
             }
         }
     }
@@ -478,7 +139,5 @@
         const val DEVICE_NAME = "device"
         const val DEVICE_CONNECTION_SUMMARY = "active"
         const val DEVICE_ADDRESS = "address"
-        const val GROUP_ID_1 = 1
-        const val GROUP_ID_2 = 2
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/DeviceItemFactoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/DeviceItemFactoryTest.kt
index ef441c1..10c3457 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/DeviceItemFactoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/DeviceItemFactoryTest.kt
@@ -133,8 +133,8 @@
 
     @Test
     fun testAvailableAudioSharingMediaDeviceItemFactory_isFilterMatched_flagOff_returnsFalse() {
-         // Flags.FLAG_ENABLE_LE_AUDIO_SHARING off or the device doesn't support broadcast
-         // source or assistant.
+        // Flags.FLAG_ENABLE_LE_AUDIO_SHARING off or the device doesn't support broadcast
+        // source or assistant.
         `when`(BluetoothUtils.isAudioSharingEnabled()).thenReturn(false)
 
         assertThat(
@@ -145,9 +145,9 @@
     }
 
     @Test
-    fun testAvailableAudioSharingMediaDeviceItemFactory_isFilterMatched_isActiveDevice_returnsFalse() {
-         // Flags.FLAG_ENABLE_LE_AUDIO_SHARING on and the device support broadcast source and
-         // assistant.
+    fun testAvailableAudioSharingMediaDeviceItemFactory_isFilterMatched_isActiveDevice_false() {
+        // Flags.FLAG_ENABLE_LE_AUDIO_SHARING on and the device support broadcast source and
+        // assistant.
         `when`(BluetoothUtils.isAudioSharingEnabled()).thenReturn(true)
         `when`(BluetoothUtils.isActiveMediaDevice(any())).thenReturn(true)
 
@@ -159,9 +159,9 @@
     }
 
     @Test
-    fun testAvailableAudioSharingMediaDeviceItemFactory_isFilterMatched_isNotAvailable_returnsFalse() {
-         // Flags.FLAG_ENABLE_LE_AUDIO_SHARING on and the device support broadcast source and
-         // assistant.
+    fun testAvailableAudioSharingMediaDeviceItemFactory_isFilterMatched_isNotAvailable_false() {
+        // Flags.FLAG_ENABLE_LE_AUDIO_SHARING on and the device support broadcast source and
+        // assistant.
         `when`(BluetoothUtils.isAudioSharingEnabled()).thenReturn(true)
         `when`(BluetoothUtils.isActiveMediaDevice(any())).thenReturn(false)
         `when`(BluetoothUtils.isAvailableMediaBluetoothDevice(any(), any())).thenReturn(true)
@@ -177,8 +177,8 @@
 
     @Test
     fun testAvailableAudioSharingMediaDeviceItemFactory_isFilterMatched_returnsTrue() {
-         // Flags.FLAG_ENABLE_LE_AUDIO_SHARING on and the device support broadcast source and
-         // assistant.
+        // Flags.FLAG_ENABLE_LE_AUDIO_SHARING on and the device support broadcast source and
+        // assistant.
         `when`(BluetoothUtils.isAudioSharingEnabled()).thenReturn(true)
         `when`(BluetoothUtils.isActiveMediaDevice(any())).thenReturn(false)
         `when`(BluetoothUtils.isAvailableMediaBluetoothDevice(any(), any())).thenReturn(true)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/DeviceItemInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/DeviceItemInteractorTest.kt
index 194590c..c39b9a6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/DeviceItemInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/DeviceItemInteractorTest.kt
@@ -83,18 +83,6 @@
     fun setUp() {
         dispatcher = UnconfinedTestDispatcher()
         testScope = TestScope(dispatcher)
-        interactor =
-            DeviceItemInteractor(
-                bluetoothTileDialogRepository,
-                audioManager,
-                adapter,
-                localBluetoothManager,
-                fakeSystemClock,
-                logger,
-                testScope.backgroundScope,
-                dispatcher
-            )
-
         `when`(deviceItem1.cachedBluetoothDevice).thenReturn(cachedDevice1)
         `when`(deviceItem2.cachedBluetoothDevice).thenReturn(cachedDevice2)
         `when`(cachedDevice1.address).thenReturn("ADDRESS")
@@ -108,9 +96,19 @@
     fun testUpdateDeviceItems_noCachedDevice_returnEmpty() {
         testScope.runTest {
             `when`(bluetoothTileDialogRepository.cachedDevices).thenReturn(emptyList())
-            interactor.setDeviceItemFactoryListForTesting(
-                listOf(createFactory({ true }, deviceItem1))
-            )
+            interactor =
+                DeviceItemInteractor(
+                    bluetoothTileDialogRepository,
+                    audioManager,
+                    adapter,
+                    localBluetoothManager,
+                    fakeSystemClock,
+                    logger,
+                    listOf(createFactory({ true }, deviceItem1)),
+                    emptyList(),
+                    testScope.backgroundScope,
+                    dispatcher
+                )
 
             val latest by collectLastValue(interactor.deviceItemUpdate)
             val latestShowSeeAll by collectLastValue(interactor.showSeeAllUpdate)
@@ -125,9 +123,19 @@
     fun testUpdateDeviceItems_hasCachedDevice_filterNotMatch_returnEmpty() {
         testScope.runTest {
             `when`(bluetoothTileDialogRepository.cachedDevices).thenReturn(listOf(cachedDevice1))
-            interactor.setDeviceItemFactoryListForTesting(
-                listOf(createFactory({ false }, deviceItem1))
-            )
+            interactor =
+                DeviceItemInteractor(
+                    bluetoothTileDialogRepository,
+                    audioManager,
+                    adapter,
+                    localBluetoothManager,
+                    fakeSystemClock,
+                    logger,
+                    listOf(createFactory({ false }, deviceItem1)),
+                    emptyList(),
+                    testScope.backgroundScope,
+                    dispatcher
+                )
 
             val latest by collectLastValue(interactor.deviceItemUpdate)
             val latestShowSeeAll by collectLastValue(interactor.showSeeAllUpdate)
@@ -142,9 +150,19 @@
     fun testUpdateDeviceItems_hasCachedDevice_filterMatch_returnDeviceItem() {
         testScope.runTest {
             `when`(bluetoothTileDialogRepository.cachedDevices).thenReturn(listOf(cachedDevice1))
-            interactor.setDeviceItemFactoryListForTesting(
-                listOf(createFactory({ true }, deviceItem1))
-            )
+            interactor =
+                DeviceItemInteractor(
+                    bluetoothTileDialogRepository,
+                    audioManager,
+                    adapter,
+                    localBluetoothManager,
+                    fakeSystemClock,
+                    logger,
+                    listOf(createFactory({ true }, deviceItem1)),
+                    emptyList(),
+                    testScope.backgroundScope,
+                    dispatcher
+                )
 
             val latest by collectLastValue(interactor.deviceItemUpdate)
             val latestShowSeeAll by collectLastValue(interactor.showSeeAllUpdate)
@@ -159,9 +177,22 @@
     fun testUpdateDeviceItems_hasCachedDevice_filterMatch_returnMultipleDeviceItem() {
         testScope.runTest {
             `when`(adapter.mostRecentlyConnectedDevices).thenReturn(null)
-            interactor.setDeviceItemFactoryListForTesting(
-                listOf(createFactory({ false }, deviceItem1), createFactory({ true }, deviceItem2))
-            )
+            interactor =
+                DeviceItemInteractor(
+                    bluetoothTileDialogRepository,
+                    audioManager,
+                    adapter,
+                    localBluetoothManager,
+                    fakeSystemClock,
+                    logger,
+                    listOf(
+                        createFactory({ false }, deviceItem1),
+                        createFactory({ true }, deviceItem2)
+                    ),
+                    emptyList(),
+                    testScope.backgroundScope,
+                    dispatcher
+                )
 
             val latest by collectLastValue(interactor.deviceItemUpdate)
             val latestShowSeeAll by collectLastValue(interactor.showSeeAllUpdate)
@@ -176,18 +207,31 @@
     fun testUpdateDeviceItems_sortByDisplayPriority() {
         testScope.runTest {
             `when`(adapter.mostRecentlyConnectedDevices).thenReturn(null)
-            interactor.setDeviceItemFactoryListForTesting(
-                listOf(
-                    createFactory({ cachedDevice -> cachedDevice.device == device1 }, deviceItem1),
-                    createFactory({ cachedDevice -> cachedDevice.device == device2 }, deviceItem2)
+            interactor =
+                DeviceItemInteractor(
+                    bluetoothTileDialogRepository,
+                    audioManager,
+                    adapter,
+                    localBluetoothManager,
+                    fakeSystemClock,
+                    logger,
+                    listOf(
+                        createFactory(
+                            { cachedDevice -> cachedDevice.device == device1 },
+                            deviceItem1
+                        ),
+                        createFactory(
+                            { cachedDevice -> cachedDevice.device == device2 },
+                            deviceItem2
+                        )
+                    ),
+                    listOf(
+                        DeviceItemType.SAVED_BLUETOOTH_DEVICE,
+                        DeviceItemType.CONNECTED_BLUETOOTH_DEVICE
+                    ),
+                    testScope.backgroundScope,
+                    dispatcher
                 )
-            )
-            interactor.setDisplayPriorityForTesting(
-                listOf(
-                    DeviceItemType.SAVED_BLUETOOTH_DEVICE,
-                    DeviceItemType.CONNECTED_BLUETOOTH_DEVICE
-                )
-            )
             `when`(deviceItem1.type).thenReturn(DeviceItemType.CONNECTED_BLUETOOTH_DEVICE)
             `when`(deviceItem2.type).thenReturn(DeviceItemType.SAVED_BLUETOOTH_DEVICE)
 
@@ -204,15 +248,28 @@
     fun testUpdateDeviceItems_sameType_sortByRecentlyConnected() {
         testScope.runTest {
             `when`(adapter.mostRecentlyConnectedDevices).thenReturn(listOf(device2, device1))
-            interactor.setDeviceItemFactoryListForTesting(
-                listOf(
-                    createFactory({ cachedDevice -> cachedDevice.device == device1 }, deviceItem1),
-                    createFactory({ cachedDevice -> cachedDevice.device == device2 }, deviceItem2)
+            interactor =
+                DeviceItemInteractor(
+                    bluetoothTileDialogRepository,
+                    audioManager,
+                    adapter,
+                    localBluetoothManager,
+                    fakeSystemClock,
+                    logger,
+                    listOf(
+                        createFactory(
+                            { cachedDevice -> cachedDevice.device == device1 },
+                            deviceItem1
+                        ),
+                        createFactory(
+                            { cachedDevice -> cachedDevice.device == device2 },
+                            deviceItem2
+                        )
+                    ),
+                    listOf(DeviceItemType.CONNECTED_BLUETOOTH_DEVICE),
+                    testScope.backgroundScope,
+                    dispatcher
                 )
-            )
-            interactor.setDisplayPriorityForTesting(
-                listOf(DeviceItemType.CONNECTED_BLUETOOTH_DEVICE)
-            )
             `when`(deviceItem1.type).thenReturn(DeviceItemType.CONNECTED_BLUETOOTH_DEVICE)
             `when`(deviceItem2.type).thenReturn(DeviceItemType.CONNECTED_BLUETOOTH_DEVICE)
 
@@ -231,10 +288,19 @@
             `when`(bluetoothTileDialogRepository.cachedDevices)
                 .thenReturn(listOf(cachedDevice2, cachedDevice2, cachedDevice2, cachedDevice2))
             `when`(adapter.mostRecentlyConnectedDevices).thenReturn(null)
-            interactor.setDeviceItemFactoryListForTesting(
-                listOf(createFactory({ true }, deviceItem2))
-            )
-
+            interactor =
+                DeviceItemInteractor(
+                    bluetoothTileDialogRepository,
+                    audioManager,
+                    adapter,
+                    localBluetoothManager,
+                    fakeSystemClock,
+                    logger,
+                    listOf(createFactory({ true }, deviceItem2)),
+                    emptyList(),
+                    testScope.backgroundScope,
+                    dispatcher
+                )
             val latest by collectLastValue(interactor.deviceItemUpdate)
             val latestShowSeeAll by collectLastValue(interactor.showSeeAllUpdate)
             interactor.updateDeviceItems(mContext, DeviceFetchTrigger.FIRST_LOAD)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardModelTest.kt
index 85e8ab4..5741d64 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardModelTest.kt
@@ -122,6 +122,7 @@
 
     @Test
     @Throws(IOException::class)
+    @DisableFlags(FLAG_CLIPBOARD_USE_DESCRIPTION_MIMETYPE)
     fun test_imageClipData_loadFailure() {
         whenever(mMockContext.contentResolver).thenReturn(mMockContentResolver)
         whenever(mMockContext.resources).thenReturn(mContext.resources)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/backup/CommunalBackupUtilsTest.kt b/packages/SystemUI/tests/src/com/android/systemui/communal/data/backup/CommunalBackupUtilsTest.kt
similarity index 100%
rename from packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/backup/CommunalBackupUtilsTest.kt
rename to packages/SystemUI/tests/src/com/android/systemui/communal/data/backup/CommunalBackupUtilsTest.kt
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/db/CommunalWidgetDaoTest.kt b/packages/SystemUI/tests/src/com/android/systemui/communal/data/db/CommunalWidgetDaoTest.kt
similarity index 100%
rename from packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/db/CommunalWidgetDaoTest.kt
rename to packages/SystemUI/tests/src/com/android/systemui/communal/data/db/CommunalWidgetDaoTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/display/data/repository/DisplayScopeRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/display/data/repository/DisplayScopeRepositoryImplTest.kt
new file mode 100644
index 0000000..5d5c120
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/display/data/repository/DisplayScopeRepositoryImplTest.kt
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.display.data.repository
+
+import android.platform.test.annotations.EnableFlags
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.kosmos.applicationCoroutineScope
+import com.android.systemui.kosmos.testDispatcher
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.kosmos.unconfinedTestDispatcher
+import com.android.systemui.statusbar.core.StatusBarConnectedDisplays
+import com.android.systemui.testKosmos
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.isActive
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@EnableFlags(StatusBarConnectedDisplays.FLAG_NAME)
+@RunWith(AndroidJUnit4::class)
+@SmallTest
+class DisplayScopeRepositoryImplTest : SysuiTestCase() {
+
+    private val kosmos = testKosmos().also { it.testDispatcher = it.unconfinedTestDispatcher }
+    private val testScope = kosmos.testScope
+    private val fakeDisplayRepository = kosmos.displayRepository
+
+    private val repo =
+        DisplayScopeRepositoryImpl(
+            kosmos.applicationCoroutineScope,
+            kosmos.testDispatcher,
+            fakeDisplayRepository,
+        )
+
+    @Before
+    fun setUp() {
+        repo.start()
+    }
+
+    @Test
+    fun scopeForDisplay_multipleCallsForSameDisplayId_returnsSameInstance() {
+        val scopeForDisplay = repo.scopeForDisplay(displayId = 1)
+
+        assertThat(repo.scopeForDisplay(displayId = 1)).isSameInstanceAs(scopeForDisplay)
+    }
+
+    @Test
+    fun scopeForDisplay_differentDisplayId_returnsNewInstance() {
+        val scopeForDisplay1 = repo.scopeForDisplay(displayId = 1)
+        val scopeForDisplay2 = repo.scopeForDisplay(displayId = 2)
+
+        assertThat(scopeForDisplay1).isNotSameInstanceAs(scopeForDisplay2)
+    }
+
+    @Test
+    fun scopeForDisplay_activeByDefault() =
+        testScope.runTest {
+            val scopeForDisplay = repo.scopeForDisplay(displayId = 1)
+
+            assertThat(scopeForDisplay.isActive).isTrue()
+        }
+
+    @Test
+    fun scopeForDisplay_afterDisplayRemoved_scopeIsCancelled() =
+        testScope.runTest {
+            val scopeForDisplay = repo.scopeForDisplay(displayId = 1)
+
+            fakeDisplayRepository.removeDisplay(displayId = 1)
+
+            assertThat(scopeForDisplay.isActive).isFalse()
+        }
+
+    @Test
+    fun scopeForDisplay_afterDisplayRemoved_returnsNewInstance() =
+        testScope.runTest {
+            val initialScope = repo.scopeForDisplay(displayId = 1)
+
+            fakeDisplayRepository.removeDisplay(displayId = 1)
+
+            val newScope = repo.scopeForDisplay(displayId = 1)
+            assertThat(newScope).isNotSameInstanceAs(initialScope)
+        }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/display/data/repository/DisplayWindowPropertiesRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/display/data/repository/DisplayWindowPropertiesRepositoryImplTest.kt
new file mode 100644
index 0000000..ff3186a
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/display/data/repository/DisplayWindowPropertiesRepositoryImplTest.kt
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.display.data.repository
+
+import android.content.testableContext
+import android.platform.test.annotations.EnableFlags
+import android.view.Display
+import android.view.mockWindowManager
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.display.shared.model.DisplayWindowProperties
+import com.android.systemui.kosmos.applicationCoroutineScope
+import com.android.systemui.kosmos.testDispatcher
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.kosmos.unconfinedTestDispatcher
+import com.android.systemui.statusbar.core.StatusBarConnectedDisplays
+import com.android.systemui.testKosmos
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.runBlocking
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.kotlin.doReturn
+import org.mockito.kotlin.mock
+
+@EnableFlags(StatusBarConnectedDisplays.FLAG_NAME)
+@RunWith(AndroidJUnit4::class)
+@SmallTest
+class DisplayWindowPropertiesRepositoryImplTest : SysuiTestCase() {
+
+    private val kosmos = testKosmos().also { it.testDispatcher = it.unconfinedTestDispatcher }
+    private val fakeDisplayRepository = kosmos.displayRepository
+    private val testScope = kosmos.testScope
+
+    private val applicationContext = kosmos.testableContext
+    private val applicationWindowManager = kosmos.mockWindowManager
+
+    private val repo =
+        DisplayWindowPropertiesRepositoryImpl(
+            kosmos.applicationCoroutineScope,
+            applicationContext,
+            applicationWindowManager,
+            fakeDisplayRepository,
+        )
+
+    @Before
+    fun start() {
+        repo.start()
+    }
+
+    @Before
+    fun addDisplays() = runBlocking {
+        fakeDisplayRepository.addDisplay(createDisplay(DEFAULT_DISPLAY_ID))
+        fakeDisplayRepository.addDisplay(createDisplay(NON_DEFAULT_DISPLAY_ID))
+    }
+
+    @Test
+    fun get_defaultDisplayId_returnsDefaultProperties() =
+        testScope.runTest {
+            val displayContext = repo.get(DEFAULT_DISPLAY_ID, WINDOW_TYPE_FOO)
+
+            assertThat(displayContext)
+                .isEqualTo(
+                    DisplayWindowProperties(
+                        displayId = DEFAULT_DISPLAY_ID,
+                        windowType = WINDOW_TYPE_FOO,
+                        context = applicationContext,
+                        windowManager = applicationWindowManager,
+                    )
+                )
+        }
+
+    @Test
+    fun get_nonDefaultDisplayId_returnsNewStatusBarContext() =
+        testScope.runTest {
+            val displayContext = repo.get(NON_DEFAULT_DISPLAY_ID, WINDOW_TYPE_FOO)
+
+            assertThat(displayContext.context).isNotSameInstanceAs(applicationContext)
+        }
+
+    @Test
+    fun get_nonDefaultDisplayId_returnsNewWindowManager() =
+        testScope.runTest {
+            val displayContext = repo.get(NON_DEFAULT_DISPLAY_ID, WINDOW_TYPE_FOO)
+
+            assertThat(displayContext.windowManager).isNotSameInstanceAs(applicationWindowManager)
+        }
+
+    @Test
+    fun get_multipleCallsForDefaultDisplay_returnsSameInstance() =
+        testScope.runTest {
+            val displayContext = repo.get(DEFAULT_DISPLAY_ID, WINDOW_TYPE_FOO)
+
+            assertThat(repo.get(DEFAULT_DISPLAY_ID, WINDOW_TYPE_FOO))
+                .isSameInstanceAs(displayContext)
+        }
+
+    @Test
+    fun get_multipleCallsForNonDefaultDisplay_returnsSameInstance() =
+        testScope.runTest {
+            val displayContext = repo.get(NON_DEFAULT_DISPLAY_ID, WINDOW_TYPE_FOO)
+
+            assertThat(repo.get(NON_DEFAULT_DISPLAY_ID, WINDOW_TYPE_FOO))
+                .isSameInstanceAs(displayContext)
+        }
+
+    @Test
+    fun get_multipleCalls_differentType_returnsNewInstance() =
+        testScope.runTest {
+            val displayContext = repo.get(NON_DEFAULT_DISPLAY_ID, WINDOW_TYPE_FOO)
+
+            assertThat(repo.get(NON_DEFAULT_DISPLAY_ID, WINDOW_TYPE_BAR))
+                .isNotSameInstanceAs(displayContext)
+        }
+
+    @Test
+    fun get_afterDisplayRemoved_returnsNewInstance() =
+        testScope.runTest {
+            val displayContext = repo.get(NON_DEFAULT_DISPLAY_ID, WINDOW_TYPE_FOO)
+
+            fakeDisplayRepository.removeDisplay(NON_DEFAULT_DISPLAY_ID)
+            fakeDisplayRepository.addDisplay(createDisplay(NON_DEFAULT_DISPLAY_ID))
+
+            assertThat(repo.get(NON_DEFAULT_DISPLAY_ID, WINDOW_TYPE_FOO))
+                .isNotSameInstanceAs(displayContext)
+        }
+
+    @Test(expected = IllegalArgumentException::class)
+    fun get_nonExistingDisplayId_throws() =
+        testScope.runTest { repo.get(NON_EXISTING_DISPLAY_ID, WINDOW_TYPE_FOO) }
+
+    private fun createDisplay(displayId: Int) =
+        mock<Display> { on { getDisplayId() } doReturn displayId }
+
+    companion object {
+        private const val DEFAULT_DISPLAY_ID = Display.DEFAULT_DISPLAY
+        private const val NON_DEFAULT_DISPLAY_ID = DEFAULT_DISPLAY_ID + 1
+        private const val NON_EXISTING_DISPLAY_ID = DEFAULT_DISPLAY_ID + 2
+        private const val WINDOW_TYPE_FOO = 123
+        private const val WINDOW_TYPE_BAR = 321
+    }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/data/repository/KeyboardRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyboard/data/repository/KeyboardRepositoryTest.kt
similarity index 100%
rename from packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/data/repository/KeyboardRepositoryTest.kt
rename to packages/SystemUI/tests/src/com/android/systemui/keyboard/data/repository/KeyboardRepositoryTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
index 6608542..b3cccea 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
@@ -26,6 +26,7 @@
 import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_NON_STRONG_BIOMETRICS_TIMEOUT;
 import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN;
 import static com.android.systemui.Flags.FLAG_KEYGUARD_WM_STATE_REFACTOR;
+import static com.android.systemui.Flags.FLAG_RELOCK_WITH_POWER_BUTTON_IMMEDIATELY;
 import static com.android.systemui.Flags.FLAG_SIM_PIN_BOUNCER_RESET;
 import static com.android.systemui.keyguard.KeyguardViewMediator.DELAYED_KEYGUARD_ACTION;
 import static com.android.systemui.keyguard.KeyguardViewMediator.KEYGUARD_LOCK_AFTER_DELAY_DEFAULT;
@@ -63,6 +64,7 @@
 import android.os.PowerManager;
 import android.os.PowerManager.WakeLock;
 import android.os.RemoteException;
+import android.platform.test.annotations.DisableFlags;
 import android.platform.test.annotations.EnableFlags;
 import android.telephony.TelephonyManager;
 import android.testing.AndroidTestingRunner;
@@ -841,6 +843,32 @@
 
     @Test
     @TestableLooper.RunWithLooper(setAsMainLooper = true)
+    @EnableFlags(FLAG_RELOCK_WITH_POWER_BUTTON_IMMEDIATELY)
+    public void testCancelKeyguardExitAnimationDueToSleep_withPendingLockAndRelockFlag_keyguardWillBeShowing() {
+        startMockKeyguardExitAnimation();
+
+        mViewMediator.onStartedGoingToSleep(PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON);
+        mViewMediator.onFinishedGoingToSleep(PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON, false);
+
+        cancelMockKeyguardExitAnimation();
+
+        mViewMediator.maybeHandlePendingLock();
+        TestableLooper.get(this).processAllMessages();
+
+        assertTrue(mViewMediator.isShowingAndNotOccluded());
+
+        verify(mKeyguardUnlockAnimationController).notifyFinishedKeyguardExitAnimation(true);
+
+        // Unlock animators call `exitKeyguardAndFinishSurfaceBehindRemoteAnimation` when canceled
+        mViewMediator.exitKeyguardAndFinishSurfaceBehindRemoteAnimation(false);
+        TestableLooper.get(this).processAllMessages();
+
+        verify(mUpdateMonitor, never()).dispatchKeyguardDismissAnimationFinished();
+    }
+
+    @Test
+    @TestableLooper.RunWithLooper(setAsMainLooper = true)
+    @DisableFlags(FLAG_RELOCK_WITH_POWER_BUTTON_IMMEDIATELY)
     public void testCancelKeyguardExitAnimationDueToSleep_withPendingLock_keyguardWillBeShowing() {
         startMockKeyguardExitAnimation();
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSectionTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSectionTest.kt
index 0b944f0..96a0aad 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSectionTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSectionTest.kt
@@ -39,13 +39,13 @@
 import com.android.systemui.kosmos.Kosmos
 import com.android.systemui.kosmos.testScope
 import com.android.systemui.res.R
+import com.android.systemui.shade.LargeScreenHeaderHelper
 import com.android.systemui.shade.data.repository.shadeRepository
 import com.android.systemui.statusbar.notification.stack.domain.interactor.notificationsKeyguardInteractor
 import com.android.systemui.statusbar.policy.fakeConfigurationController
 import com.android.systemui.statusbar.ui.fakeSystemBarUtilsProxy
 import com.android.systemui.testKosmos
 import com.android.systemui.util.mockito.eq
-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
@@ -57,6 +57,7 @@
 import org.mockito.ArgumentMatchers.anyInt
 import org.mockito.ArgumentMatchers.anyString
 import org.mockito.MockitoAnnotations
+import org.mockito.kotlin.mock
 
 @OptIn(ExperimentalCoroutinesApi::class)
 @RunWith(AndroidJUnit4::class)
@@ -122,6 +123,7 @@
                     { keyguardBlueprintInteractor },
                     keyguardRootViewModel,
                     aodBurnInViewModel,
+                    largeScreenHeaderHelperLazy = { mock<LargeScreenHeaderHelper>() },
                 )
         }
     }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt
similarity index 100%
rename from packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt
rename to packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardQuickAffordancesCombinedViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardQuickAffordancesCombinedViewModelTest.kt
similarity index 100%
rename from packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardQuickAffordancesCombinedViewModelTest.kt
rename to packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardQuickAffordancesCombinedViewModelTest.kt
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/lifecycle/ActivatableTest.kt b/packages/SystemUI/tests/src/com/android/systemui/lifecycle/ActivatableTest.kt
similarity index 100%
rename from packages/SystemUI/multivalentTests/src/com/android/systemui/lifecycle/ActivatableTest.kt
rename to packages/SystemUI/tests/src/com/android/systemui/lifecycle/ActivatableTest.kt
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/lifecycle/SysUiViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/lifecycle/SysUiViewModelTest.kt
similarity index 100%
rename from packages/SystemUI/multivalentTests/src/com/android/systemui/lifecycle/SysUiViewModelTest.kt
rename to packages/SystemUI/tests/src/com/android/systemui/lifecycle/SysUiViewModelTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaSwitchingControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaSwitchingControllerTest.java
index 07e48b9..bf4ef50 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaSwitchingControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaSwitchingControllerTest.java
@@ -125,6 +125,8 @@
     private static final boolean VOLUME_FIXED_TRUE = true;
     private static final int LATCH_COUNT_DOWN_TIME_IN_SECOND = 5;
     private static final int LATCH_TIME_OUT_TIME_IN_SECOND = 10;
+    private static final String PRODUCT_NAME_BUILTIN_MIC = "Built-in Mic";
+    private static final String PRODUCT_NAME_WIRED_HEADSET = "My Wired Headset";
 
     @Mock
     private DialogTransitionAnimator mDialogTransitionAnimator;
@@ -568,7 +570,8 @@
                         AudioDeviceInfo.TYPE_BUILTIN_MIC,
                         MAX_VOLUME,
                         CURRENT_VOLUME,
-                        VOLUME_FIXED_TRUE);
+                        VOLUME_FIXED_TRUE,
+                        PRODUCT_NAME_BUILTIN_MIC);
         final MediaDevice mediaDevice4 =
                 InputMediaDevice.create(
                         mContext,
@@ -576,7 +579,8 @@
                         AudioDeviceInfo.TYPE_WIRED_HEADSET,
                         MAX_VOLUME,
                         CURRENT_VOLUME,
-                        VOLUME_FIXED_TRUE);
+                        VOLUME_FIXED_TRUE,
+                        PRODUCT_NAME_WIRED_HEADSET);
         final List<MediaDevice> inputDevices = new ArrayList<>();
         inputDevices.add(mediaDevice3);
         inputDevices.add(mediaDevice4);
@@ -1355,7 +1359,8 @@
                         AudioDeviceInfo.TYPE_BUILTIN_MIC,
                         MAX_VOLUME,
                         CURRENT_VOLUME,
-                        VOLUME_FIXED_TRUE);
+                        VOLUME_FIXED_TRUE,
+                        PRODUCT_NAME_BUILTIN_MIC);
         mMediaSwitchingController.connectDevice(inputMediaDevice);
 
         CountDownLatch latch = new CountDownLatch(LATCH_COUNT_DOWN_TIME_IN_SECOND);
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/QSImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSImplTest.java
similarity index 100%
rename from packages/SystemUI/multivalentTests/src/com/android/systemui/qs/QSImplTest.java
rename to packages/SystemUI/tests/src/com/android/systemui/qs/QSImplTest.java
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/recordissue/RecordIssueDialogDelegateTest.kt b/packages/SystemUI/tests/src/com/android/systemui/recordissue/RecordIssueDialogDelegateTest.kt
similarity index 97%
rename from packages/SystemUI/multivalentTests/src/com/android/systemui/recordissue/RecordIssueDialogDelegateTest.kt
rename to packages/SystemUI/tests/src/com/android/systemui/recordissue/RecordIssueDialogDelegateTest.kt
index 8d84c3e..9639735 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/recordissue/RecordIssueDialogDelegateTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/recordissue/RecordIssueDialogDelegateTest.kt
@@ -78,7 +78,6 @@
     @Mock private lateinit var sysuiState: SysUiState
     @Mock private lateinit var systemUIDialogManager: SystemUIDialogManager
     @Mock private lateinit var broadcastDispatcher: BroadcastDispatcher
-    @Mock private lateinit var traceurMessageSender: TraceurMessageSender
     private val systemClock = FakeSystemClock()
     private val bgExecutor = FakeExecutor(systemClock)
     private val mainExecutor = FakeExecutor(systemClock)
@@ -104,7 +103,7 @@
                     systemUIDialogManager,
                     sysuiState,
                     broadcastDispatcher,
-                    mDialogTransitionAnimator
+                    mDialogTransitionAnimator,
                 )
             )
 
@@ -120,7 +119,6 @@
                     mediaProjectionMetricsLogger,
                     screenCaptureDisabledDialogDelegate,
                     state,
-                    traceurMessageSender
                 ) {
                     latch.countDown()
                 }
@@ -166,7 +164,7 @@
         verify(mediaProjectionMetricsLogger, never())
             .notifyProjectionInitiated(
                 anyInt(),
-                eq(SessionCreationSource.SYSTEM_UI_SCREEN_RECORDER)
+                eq(SessionCreationSource.SYSTEM_UI_SCREEN_RECORDER),
             )
         assertThat(screenRecordSwitch.isChecked).isFalse()
     }
@@ -188,7 +186,7 @@
         verify(mediaProjectionMetricsLogger)
             .notifyProjectionInitiated(
                 anyInt(),
-                eq(SessionCreationSource.SYSTEM_UI_SCREEN_RECORDER)
+                eq(SessionCreationSource.SYSTEM_UI_SCREEN_RECORDER),
             )
         verify(factory, times(2)).create(any(SystemUIDialog.Delegate::class.java))
     }
@@ -208,7 +206,7 @@
         verify(mediaProjectionMetricsLogger)
             .notifyProjectionInitiated(
                 anyInt(),
-                eq(SessionCreationSource.SYSTEM_UI_SCREEN_RECORDER)
+                eq(SessionCreationSource.SYSTEM_UI_SCREEN_RECORDER),
             )
         verify(factory, never()).create()
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/policy/PolicyRequestProcessorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/screenshot/policy/PolicyRequestProcessorTest.kt
index 2fcacb9..0d4cb4c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/policy/PolicyRequestProcessorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/policy/PolicyRequestProcessorTest.kt
@@ -16,6 +16,7 @@
 package com.android.systemui.screenshot.policy
 
 import android.content.ComponentName
+import android.graphics.Bitmap
 import android.graphics.Insets
 import android.graphics.Rect
 import android.os.UserHandle
@@ -27,10 +28,12 @@
 import com.android.systemui.screenshot.ScreenshotData
 import com.android.systemui.screenshot.data.model.DisplayContentScenarios.ActivityNames.FILES
 import com.android.systemui.screenshot.data.model.DisplayContentScenarios.TaskSpec
+import com.android.systemui.screenshot.data.model.DisplayContentScenarios.launcherOnly
 import com.android.systemui.screenshot.data.model.DisplayContentScenarios.singleFullScreen
 import com.android.systemui.screenshot.data.repository.DisplayContentRepository
 import com.android.systemui.screenshot.policy.TestUserIds.PERSONAL
 import com.android.systemui.screenshot.policy.TestUserIds.WORK
+import com.google.common.truth.Truth.assertThat
 import com.google.common.truth.Truth.assertWithMessage
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.runBlocking
@@ -39,14 +42,6 @@
 
 @RunWith(AndroidJUnit4::class)
 class PolicyRequestProcessorTest {
-
-    val imageCapture =
-        object : ImageCapture {
-            override fun captureDisplay(displayId: Int, crop: Rect?) = null
-
-            override suspend fun captureTask(taskId: Int) = null
-        }
-
     /** Tests behavior when no policies are applied */
     @Test
     fun testProcess_defaultOwner_whenNoPolicyApplied() {
@@ -60,9 +55,9 @@
                 SCREENSHOT_KEY_CHORD,
                 UserHandle.CURRENT,
                 topComponent = null,
-                screenBounds = Rect(0, 0, 1, 1),
+                originalScreenBounds = Rect(0, 0, 1, 1),
                 taskId = -1,
-                insets = Insets.NONE,
+                originalInsets = Insets.NONE,
                 bitmap = null,
                 displayId = DEFAULT_DISPLAY,
             )
@@ -71,7 +66,7 @@
         val requestProcessor =
             PolicyRequestProcessor(
                 Dispatchers.Unconfined,
-                imageCapture,
+                createImageCapture(),
                 policies = emptyList(),
                 defaultOwner = UserHandle.of(PERSONAL),
                 defaultComponent = ComponentName("default", "Component"),
@@ -91,6 +86,70 @@
         assertWithMessage("Task ID").that(result.taskId).isEqualTo(TASK_ID)
     }
 
+    @Test
+    fun testProcess_throwsWhenCaptureFails() {
+        val request = ScreenshotData.forTesting()
+
+        /* Create a policy request processor with no capture policies */
+        val requestProcessor =
+            PolicyRequestProcessor(
+                Dispatchers.Unconfined,
+                createImageCapture(display = null),
+                policies = emptyList(),
+                defaultComponent = ComponentName("default", "Component"),
+                displayTasks = DisplayContentRepository { launcherOnly() },
+            )
+
+        val result = runCatching { runBlocking { requestProcessor.process(request) } }
+
+        assertThat(result.isFailure).isTrue()
+    }
+
+    @Test
+    fun testProcess_throwsWhenTaskCaptureFails() {
+        val request = ScreenshotData.forTesting()
+        val fullScreenWork = DisplayContentRepository {
+            singleFullScreen(TaskSpec(taskId = TASK_ID, name = FILES, userId = WORK))
+        }
+
+        val captureTaskPolicy = CapturePolicy {
+            CapturePolicy.PolicyResult.Matched(
+                policy = "",
+                reason = "",
+                parameters =
+                    CaptureParameters(
+                        CaptureType.IsolatedTask(taskId = 0, taskBounds = null),
+                        null,
+                        UserHandle.CURRENT,
+                    ),
+            )
+        }
+
+        /* Create a policy request processor with no capture policies */
+        val requestProcessor =
+            PolicyRequestProcessor(
+                Dispatchers.Unconfined,
+                createImageCapture(task = null),
+                policies = listOf(captureTaskPolicy),
+                defaultComponent = ComponentName("default", "Component"),
+                displayTasks = fullScreenWork,
+            )
+
+        val result = runCatching { runBlocking { requestProcessor.process(request) } }
+
+        assertThat(result.isFailure).isTrue()
+    }
+
+    private fun createImageCapture(
+        display: Bitmap? = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888),
+        task: Bitmap? = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888),
+    ) =
+        object : ImageCapture {
+            override fun captureDisplay(displayId: Int, crop: Rect?) = display
+
+            override suspend fun captureTask(taskId: Int) = task
+        }
+
     companion object {
         const val TASK_ID = 1001
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerWifiTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerWifiTest.java
index 6febb91..7a579ba 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerWifiTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerWifiTest.java
@@ -58,7 +58,7 @@
     private static final int MIN_RSSI = -100;
     private static final int MAX_RSSI = -55;
     private WifiInfo mWifiInfo = mock(WifiInfo.class);
-    private VcnTransportInfo mVcnTransportInfo = mock(VcnTransportInfo.class);
+    private VcnTransportInfo mVcnTransportInfo = new VcnTransportInfo.Builder().build();
 
     @Before
     public void setUp() throws Exception {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationSectionsFeatureManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationSectionsFeatureManagerTest.kt
deleted file mode 100644
index ac73882..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationSectionsFeatureManagerTest.kt
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.statusbar.notification
-
-import android.platform.test.annotations.DisableFlags
-import android.provider.DeviceConfig
-import android.provider.Settings
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import androidx.test.filters.SmallTest
-import com.android.dx.mockito.inline.extended.ExtendedMockito
-import com.android.internal.config.sysui.SystemUiDeviceConfigFlags.NOTIFICATIONS_USE_PEOPLE_FILTERING
-import com.android.systemui.SysuiTestCase
-import com.android.systemui.statusbar.notification.shared.NotificationMinimalism
-import com.android.systemui.statusbar.notification.shared.PriorityPeopleSection
-import com.android.systemui.util.DeviceConfigProxyFake
-import com.android.systemui.util.Utils
-import com.android.systemui.util.mockito.any
-import org.junit.After
-import org.junit.Assert.assertFalse
-import org.junit.Assert.assertTrue
-import org.junit.Before
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.mockito.MockitoSession
-import org.mockito.kotlin.whenever
-import org.mockito.quality.Strictness
-
-@RunWith(AndroidJUnit4::class)
-@SmallTest
-// this class has no testable logic with either of these flags enabled
-@DisableFlags(PriorityPeopleSection.FLAG_NAME, NotificationMinimalism.FLAG_NAME)
-class NotificationSectionsFeatureManagerTest : SysuiTestCase() {
-    lateinit var manager: NotificationSectionsFeatureManager
-    private val proxyFake = DeviceConfigProxyFake()
-    private lateinit var staticMockSession: MockitoSession
-
-    @Before
-    fun setup() {
-        manager = NotificationSectionsFeatureManager(proxyFake, mContext)
-        manager.clearCache()
-        staticMockSession =
-            ExtendedMockito.mockitoSession()
-                .mockStatic(Utils::class.java)
-                .strictness(Strictness.LENIENT)
-                .startMocking()
-        whenever(Utils.useQsMediaPlayer(any())).thenReturn(false)
-        Settings.Global.putInt(
-            context.getContentResolver(),
-            Settings.Global.SHOW_MEDIA_ON_QUICK_SETTINGS,
-            0
-        )
-    }
-
-    @After
-    fun teardown() {
-        staticMockSession.finishMocking()
-    }
-
-    @Test
-    fun testPeopleFilteringOff_newInterruptionModelOn() {
-        proxyFake.setProperty(
-            DeviceConfig.NAMESPACE_SYSTEMUI,
-            NOTIFICATIONS_USE_PEOPLE_FILTERING,
-            "false",
-            false
-        )
-
-        assertFalse("People filtering should be disabled", manager.isFilteringEnabled())
-        assertTrue(
-            "Expecting 2 buckets when people filtering is disabled",
-            manager.getNumberOfBuckets() == 2
-        )
-    }
-
-    @Test
-    fun testPeopleFilteringOn_newInterruptionModelOn() {
-        proxyFake.setProperty(
-            DeviceConfig.NAMESPACE_SYSTEMUI,
-            NOTIFICATIONS_USE_PEOPLE_FILTERING,
-            "true",
-            false
-        )
-
-        assertTrue("People filtering should be enabled", manager.isFilteringEnabled())
-        assertTrue(
-            "Expecting 5 buckets when people filtering is enabled",
-            manager.getNumberOfBuckets() == 5
-        )
-    }
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java
index 7cd306e..6425da4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java
@@ -83,6 +83,7 @@
 import com.android.systemui.statusbar.SysuiStatusBarStateController;
 import com.android.systemui.statusbar.notification.ColorUpdateLogger;
 import com.android.systemui.statusbar.notification.DynamicPrivacyController;
+import com.android.systemui.statusbar.notification.HeadsUpTouchHelper;
 import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
 import com.android.systemui.statusbar.notification.collection.NotifCollection;
 import com.android.systemui.statusbar.notification.collection.NotifPipeline;
@@ -103,7 +104,6 @@
 import com.android.systemui.statusbar.notification.stack.NotificationSwipeHelper.NotificationCallback;
 import com.android.systemui.statusbar.notification.stack.ui.viewbinder.NotificationListViewBinder;
 import com.android.systemui.statusbar.phone.HeadsUpAppearanceController;
-import com.android.systemui.statusbar.notification.HeadsUpTouchHelper;
 import com.android.systemui.statusbar.phone.KeyguardBypassController;
 import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
@@ -113,6 +113,7 @@
 import com.android.systemui.statusbar.policy.ZenModeController;
 import com.android.systemui.tuner.TunerService;
 import com.android.systemui.util.settings.SecureSettings;
+import com.android.systemui.wallpapers.domain.interactor.WallpaperInteractor;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -154,6 +155,7 @@
     @Mock private KeyguardBypassController mKeyguardBypassController;
     @Mock private PowerInteractor mPowerInteractor;
     @Mock private PrimaryBouncerInteractor mPrimaryBouncerInteractor;
+    @Mock private WallpaperInteractor mWallpaperInteractor;
     @Mock private NotificationLockscreenUserManager mNotificationLockscreenUserManager;
     @Mock private MetricsLogger mMetricsLogger;
     @Mock private ColorUpdateLogger mColorUpdateLogger;
@@ -1070,7 +1072,8 @@
                 mock(NotificationDismissibilityProvider.class),
                 mActivityStarter,
                 new ResourcesSplitShadeStateController(),
-                mSensitiveNotificationProtectionController);
+                mSensitiveNotificationProtectionController,
+                mWallpaperInteractor);
     }
 
     static class LogMatcher implements ArgumentMatcher<LogMaker> {
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 8a3e551..87cda64 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
@@ -102,6 +102,7 @@
 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
 import com.android.systemui.statusbar.policy.AvalancheController;
 import com.android.systemui.statusbar.policy.ResourcesSplitShadeStateController;
+import com.android.systemui.wallpapers.domain.interactor.WallpaperInteractor;
 
 import kotlin.Unit;
 
@@ -146,6 +147,7 @@
     @Mock private NotificationStackScrollLayoutController mStackScrollLayoutController;
     @Mock private ScreenOffAnimationController mScreenOffAnimationController;
     @Mock private NotificationShelf mNotificationShelf;
+    @Mock private WallpaperInteractor mWallpaperInteractor;
     @Mock private NotificationStackSizeCalculator mStackSizeCalculator;
     @Mock private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
     @Mock private LargeScreenShadeInterpolator mLargeScreenShadeInterpolator;
@@ -208,6 +210,7 @@
                 .thenReturn(mNotificationRoundnessManager);
         mStackScroller.setController(mStackScrollLayoutController);
         mStackScroller.setShelf(mNotificationShelf);
+        mStackScroller.setWallpaperInteractor(mWallpaperInteractor);
         when(mStackScroller.getExpandHelper()).thenReturn(mExpandHelper);
 
         doNothing().when(mGroupExpansionManager).collapseGroups();
@@ -588,8 +591,8 @@
         ArgumentCaptor<FooterView> captor = ArgumentCaptor.forClass(FooterView.class);
         verify(mStackScroller).setFooterView(captor.capture());
 
-        assertNotNull(captor.getValue().findViewById(R.id.manage_text).hasOnClickListeners());
-        assertNotNull(captor.getValue().findViewById(R.id.dismiss_text).hasOnClickListeners());
+        assertNotNull(captor.getValue().findViewById(R.id.manage_text));
+        assertNotNull(captor.getValue().findViewById(R.id.dismiss_text));
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java
index 63a560f..e57e8d1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java
@@ -66,7 +66,6 @@
 import com.android.systemui.statusbar.notification.icon.ui.viewbinder.NotificationIconContainerStatusBarViewBinder;
 import com.android.systemui.statusbar.phone.HeadsUpAppearanceController;
 import com.android.systemui.statusbar.phone.StatusBarHideIconsForBouncerManager;
-import com.android.systemui.statusbar.phone.StatusBarLocationPublisher;
 import com.android.systemui.statusbar.phone.fragment.dagger.StatusBarFragmentComponent;
 import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallController;
 import com.android.systemui.statusbar.phone.ui.DarkIconManager;
@@ -98,7 +97,6 @@
     private ShadeExpansionStateManager mShadeExpansionStateManager;
     private OngoingCallController mOngoingCallController;
     private SystemStatusAnimationScheduler mAnimationScheduler;
-    private StatusBarLocationPublisher mLocationPublisher;
     // Set in instantiate()
     private StatusBarIconController mStatusBarIconController;
     private KeyguardStateController mKeyguardStateController;
@@ -1181,7 +1179,6 @@
         setUpDaggerComponent();
         mOngoingCallController = mock(OngoingCallController.class);
         mAnimationScheduler = mock(SystemStatusAnimationScheduler.class);
-        mLocationPublisher = mock(StatusBarLocationPublisher.class);
         mStatusBarIconController = mock(StatusBarIconController.class);
         mStatusBarStateController = mock(StatusBarStateController.class);
         mKeyguardStateController = mock(KeyguardStateController.class);
@@ -1200,7 +1197,6 @@
                 mStatusBarFragmentComponentFactory,
                 mOngoingCallController,
                 mAnimationScheduler,
-                mLocationPublisher,
                 mShadeExpansionStateManager,
                 mStatusBarIconController,
                 mIconManagerFactory,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt
index 4b6e313..c48898a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt
@@ -50,8 +50,8 @@
 import com.android.systemui.flags.FakeFeatureFlagsClassic
 import com.android.systemui.flags.Flags
 import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.table.TableLogBuffer
 import com.android.systemui.log.table.TableLogBufferFactory
+import com.android.systemui.log.table.logcatTableLogBuffer
 import com.android.systemui.statusbar.connectivity.WifiPickerTrackerFactory
 import com.android.systemui.statusbar.pipeline.airplane.data.repository.FakeAirplaneModeRepository
 import com.android.systemui.statusbar.pipeline.mobile.data.MobileInputLogger
@@ -66,6 +66,7 @@
 import com.android.systemui.statusbar.pipeline.shared.data.repository.ConnectivityRepositoryImpl
 import com.android.systemui.statusbar.pipeline.wifi.data.repository.WifiRepository
 import com.android.systemui.statusbar.pipeline.wifi.data.repository.prod.WifiRepositoryImpl
+import com.android.systemui.testKosmos
 import com.android.systemui.util.concurrency.FakeExecutor
 import com.android.systemui.util.mockito.any
 import com.android.systemui.util.mockito.argumentCaptor
@@ -104,6 +105,7 @@
 // to run the callback and this makes the looper place nicely with TestScope etc.
 @TestableLooper.RunWithLooper
 class MobileConnectionsRepositoryTest : SysuiTestCase() {
+    private val kosmos = testKosmos()
 
     private val flags =
         FakeFeatureFlagsClassic().also { it.set(Flags.ROAMING_INDICATOR_VIA_DISPLAY_INFO, true) }
@@ -120,13 +122,13 @@
     @Mock private lateinit var subscriptionManager: SubscriptionManager
     @Mock private lateinit var telephonyManager: TelephonyManager
     @Mock private lateinit var logger: MobileInputLogger
-    @Mock private lateinit var summaryLogger: TableLogBuffer
+    private val summaryLogger = logcatTableLogBuffer(kosmos, "summaryLogger")
     @Mock private lateinit var logBufferFactory: TableLogBufferFactory
     @Mock private lateinit var updateMonitor: KeyguardUpdateMonitor
     @Mock private lateinit var wifiManager: WifiManager
     @Mock private lateinit var wifiPickerTrackerFactory: WifiPickerTrackerFactory
     @Mock private lateinit var wifiPickerTracker: WifiPickerTracker
-    @Mock private lateinit var wifiTableLogBuffer: TableLogBuffer
+    private val wifiTableLogBuffer = logcatTableLogBuffer(kosmos, "wifiTableLog")
 
     private val mobileMappings = FakeMobileMappingsProxy()
     private val subscriptionManagerProxy = FakeSubscriptionManagerProxy()
@@ -134,6 +136,7 @@
     private val wifiLogBuffer = LogBuffer("wifi", maxSize = 100, logcatEchoTracker = mock())
     private val wifiPickerTrackerCallback =
         argumentCaptor<WifiPickerTracker.WifiPickerTrackerCallback>()
+    private val vcnTransportInfo = VcnTransportInfo.Builder().build()
 
     private val testDispatcher = StandardTestDispatcher()
     private val testScope = TestScope(testDispatcher)
@@ -153,7 +156,7 @@
         }
 
         whenever(logBufferFactory.getOrCreate(anyString(), anyInt())).thenAnswer { _ ->
-            mock<TableLogBuffer>()
+            logcatTableLogBuffer(kosmos, "test")
         }
 
         whenever(wifiPickerTrackerFactory.create(any(), capture(wifiPickerTrackerCallback), any()))
@@ -606,10 +609,7 @@
 
             // WHEN an appropriate intent gets sent out
             val intent = serviceStateIntent(subId = -1)
-            fakeBroadcastDispatcher.sendIntentToMatchingReceiversOnly(
-                context,
-                intent,
-            )
+            fakeBroadcastDispatcher.sendIntentToMatchingReceiversOnly(context, intent)
             runCurrent()
 
             // THEN the repo's state is updated despite no listeners
@@ -636,10 +636,7 @@
 
             // GIVEN a broadcast goes out for the appropriate subID
             val intent = serviceStateIntent(subId = -1)
-            fakeBroadcastDispatcher.sendIntentToMatchingReceiversOnly(
-                context,
-                intent,
-            )
+            fakeBroadcastDispatcher.sendIntentToMatchingReceiversOnly(context, intent)
             runCurrent()
 
             // THEN the device is in ECM, because one of the service states is
@@ -666,10 +663,7 @@
 
             // GIVEN a broadcast goes out for the appropriate subID
             val intent = serviceStateIntent(subId = -1)
-            fakeBroadcastDispatcher.sendIntentToMatchingReceiversOnly(
-                context,
-                intent,
-            )
+            fakeBroadcastDispatcher.sendIntentToMatchingReceiversOnly(context, intent)
             runCurrent()
 
             // THEN the device is in ECM, because one of the service states is
@@ -820,17 +814,9 @@
 
             // Get repos to trigger creation
             underTest.getRepoForSubId(SUB_1_ID)
-            verify(logBufferFactory)
-                .getOrCreate(
-                    eq(tableBufferLogName(SUB_1_ID)),
-                    anyInt(),
-                )
+            verify(logBufferFactory).getOrCreate(eq(tableBufferLogName(SUB_1_ID)), anyInt())
             underTest.getRepoForSubId(SUB_2_ID)
-            verify(logBufferFactory)
-                .getOrCreate(
-                    eq(tableBufferLogName(SUB_2_ID)),
-                    anyInt(),
-                )
+            verify(logBufferFactory).getOrCreate(eq(tableBufferLogName(SUB_2_ID)), anyInt())
         }
 
     @Test
@@ -1018,6 +1004,18 @@
             assertThat(latest).isTrue()
         }
 
+    private fun newWifiNetwork(wifiInfo: WifiInfo): Network {
+        val network = mock<Network>()
+        val capabilities =
+            mock<NetworkCapabilities>().also {
+                whenever(it.hasTransport(TRANSPORT_WIFI)).thenReturn(true)
+                whenever(it.transportInfo).thenReturn(wifiInfo)
+            }
+        whenever(connectivityManager.getNetworkCapabilities(network)).thenReturn(capabilities)
+
+        return network
+    }
+
     /** Regression test for b/272586234. */
     @Test
     fun hasCarrierMergedConnection_carrierMergedViaWifiWithVcnTransport_isTrue() =
@@ -1027,10 +1025,12 @@
                     whenever(this.isCarrierMerged).thenReturn(true)
                     whenever(this.isPrimary).thenReturn(true)
                 }
+            val underlyingWifi = newWifiNetwork(carrierMergedInfo)
             val caps =
                 mock<NetworkCapabilities>().also {
                     whenever(it.hasTransport(TRANSPORT_WIFI)).thenReturn(true)
-                    whenever(it.transportInfo).thenReturn(VcnTransportInfo(carrierMergedInfo))
+                    whenever(it.transportInfo).thenReturn(vcnTransportInfo)
+                    whenever(it.underlyingNetworks).thenReturn(listOf(underlyingWifi))
                 }
 
             val latest by collectLastValue(underTest.hasCarrierMergedConnection)
@@ -1049,10 +1049,12 @@
                     whenever(this.isCarrierMerged).thenReturn(true)
                     whenever(this.isPrimary).thenReturn(true)
                 }
+            val underlyingWifi = newWifiNetwork(carrierMergedInfo)
             val caps =
                 mock<NetworkCapabilities>().also {
                     whenever(it.hasTransport(TRANSPORT_CELLULAR)).thenReturn(true)
-                    whenever(it.transportInfo).thenReturn(VcnTransportInfo(carrierMergedInfo))
+                    whenever(it.transportInfo).thenReturn(vcnTransportInfo)
+                    whenever(it.underlyingNetworks).thenReturn(listOf(underlyingWifi))
                 }
 
             val latest by collectLastValue(underTest.hasCarrierMergedConnection)
@@ -1109,10 +1111,15 @@
                     whenever(this.isCarrierMerged).thenReturn(true)
                     whenever(this.isPrimary).thenReturn(true)
                 }
+
+            // The Wifi network that is under the VCN network
+            val physicalWifiNetwork = newWifiNetwork(carrierMergedInfo)
+
             val underlyingCapabilities =
                 mock<NetworkCapabilities>().also {
                     whenever(it.hasTransport(TRANSPORT_CELLULAR)).thenReturn(true)
-                    whenever(it.transportInfo).thenReturn(VcnTransportInfo(carrierMergedInfo))
+                    whenever(it.transportInfo).thenReturn(vcnTransportInfo)
+                    whenever(it.underlyingNetworks).thenReturn(listOf(physicalWifiNetwork))
                 }
             whenever(connectivityManager.getNetworkCapabilities(underlyingCarrierMergedNetwork))
                 .thenReturn(underlyingCapabilities)
@@ -1578,9 +1585,7 @@
          * To properly mimic telephony manager, create a service state, and then turn it into an
          * intent
          */
-        private fun serviceStateIntent(
-            subId: Int,
-        ): Intent {
+        private fun serviceStateIntent(subId: Int): Intent {
             return Intent(Intent.ACTION_SERVICE_STATE).apply {
                 putExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, subId)
             }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/data/repository/ConnectivityRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/data/repository/ConnectivityRepositoryImplTest.kt
index 0945742..88f262b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/data/repository/ConnectivityRepositoryImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/data/repository/ConnectivityRepositoryImplTest.kt
@@ -23,6 +23,7 @@
 import android.net.NetworkCapabilities.TRANSPORT_ETHERNET
 import android.net.NetworkCapabilities.TRANSPORT_VPN
 import android.net.NetworkCapabilities.TRANSPORT_WIFI
+import android.net.TelephonyNetworkSpecifier
 import android.net.VpnTransportInfo
 import android.net.vcn.VcnTransportInfo
 import android.net.wifi.WifiInfo
@@ -74,6 +75,8 @@
     private val testScope = kosmos.testScope
     private val tunerService = mock<TunerService>()
 
+    private val vcnTransportInfo = VcnTransportInfo.Builder().build()
+
     @Before
     fun setUp() {
         createAndSetRepo()
@@ -343,6 +346,30 @@
             assertThat(latest!!.wifi.isDefault).isTrue()
         }
 
+    private fun newWifiNetwork(wifiInfo: WifiInfo): Network {
+        val network = mock<Network>()
+        val capabilities =
+            mock<NetworkCapabilities>().also {
+                whenever(it.hasTransport(TRANSPORT_WIFI)).thenReturn(true)
+                whenever(it.transportInfo).thenReturn(wifiInfo)
+            }
+        whenever(connectivityManager.getNetworkCapabilities(network)).thenReturn(capabilities)
+
+        return network
+    }
+
+    private fun newCellNetwork(subId: Int): Network {
+        val network = mock<Network>()
+        val capabilities =
+            mock<NetworkCapabilities>().also {
+                whenever(it.hasTransport(TRANSPORT_CELLULAR)).thenReturn(true)
+                whenever(it.networkSpecifier).thenReturn(TelephonyNetworkSpecifier(subId))
+            }
+        whenever(connectivityManager.getNetworkCapabilities(network)).thenReturn(capabilities)
+
+        return network
+    }
+
     @Test
     fun defaultConnections_carrierMergedViaWifiWithVcnTransport_wifiAndCarrierMergedDefault() =
         testScope.runTest {
@@ -350,10 +377,12 @@
 
             val carrierMergedInfo =
                 mock<WifiInfo>().apply { whenever(this.isCarrierMerged).thenReturn(true) }
+            val underlyingWifi = newWifiNetwork(carrierMergedInfo)
             val capabilities =
                 mock<NetworkCapabilities>().also {
                     whenever(it.hasTransport(TRANSPORT_WIFI)).thenReturn(true)
-                    whenever(it.transportInfo).thenReturn(VcnTransportInfo(carrierMergedInfo))
+                    whenever(it.transportInfo).thenReturn(vcnTransportInfo)
+                    whenever(it.underlyingNetworks).thenReturn(listOf(underlyingWifi))
                     whenever(it.hasTransport(TRANSPORT_CELLULAR)).thenReturn(false)
                     whenever(it.hasTransport(TRANSPORT_ETHERNET)).thenReturn(false)
                 }
@@ -373,10 +402,12 @@
 
             val carrierMergedInfo =
                 mock<WifiInfo>().apply { whenever(this.isCarrierMerged).thenReturn(true) }
+            val underlyingWifi = newWifiNetwork(carrierMergedInfo)
             val capabilities =
                 mock<NetworkCapabilities>().also {
                     whenever(it.hasTransport(TRANSPORT_CELLULAR)).thenReturn(true)
-                    whenever(it.transportInfo).thenReturn(VcnTransportInfo(carrierMergedInfo))
+                    whenever(it.transportInfo).thenReturn(vcnTransportInfo)
+                    whenever(it.underlyingNetworks).thenReturn(listOf(underlyingWifi))
                     whenever(it.hasTransport(TRANSPORT_ETHERNET)).thenReturn(false)
                     whenever(it.hasTransport(TRANSPORT_WIFI)).thenReturn(false)
                 }
@@ -561,10 +592,12 @@
             val underlyingCarrierMergedNetwork = mock<Network>()
             val carrierMergedInfo =
                 mock<WifiInfo>().apply { whenever(this.isCarrierMerged).thenReturn(true) }
+            val underlyingWifi = newWifiNetwork(carrierMergedInfo)
             val underlyingCapabilities =
                 mock<NetworkCapabilities>().also {
                     whenever(it.hasTransport(TRANSPORT_CELLULAR)).thenReturn(true)
-                    whenever(it.transportInfo).thenReturn(VcnTransportInfo(carrierMergedInfo))
+                    whenever(it.transportInfo).thenReturn(vcnTransportInfo)
+                    whenever(it.underlyingNetworks).thenReturn(listOf(underlyingWifi))
                 }
             whenever(connectivityManager.getNetworkCapabilities(underlyingCarrierMergedNetwork))
                 .thenReturn(underlyingCapabilities)
@@ -645,14 +678,15 @@
     @Test
     fun vcnSubId_tracksVcnTransportInfo() =
         testScope.runTest {
-            val vcnInfo = VcnTransportInfo(SUB_1_ID)
+            val underlyingCell = newCellNetwork(SUB_1_ID)
 
             val latest by collectLastValue(underTest.vcnSubId)
 
             val capabilities =
                 mock<NetworkCapabilities>().also {
                     whenever(it.hasTransport(TRANSPORT_CELLULAR)).thenReturn(true)
-                    whenever(it.transportInfo).thenReturn(vcnInfo)
+                    whenever(it.transportInfo).thenReturn(vcnTransportInfo)
+                    whenever(it.underlyingNetworks).thenReturn(listOf(underlyingCell))
                 }
 
             getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, capabilities)
@@ -663,14 +697,15 @@
     @Test
     fun vcnSubId_filersOutInvalid() =
         testScope.runTest {
-            val vcnInfo = VcnTransportInfo(INVALID_SUBSCRIPTION_ID)
+            val underlyingCell = newCellNetwork(INVALID_SUBSCRIPTION_ID)
 
             val latest by collectLastValue(underTest.vcnSubId)
 
             val capabilities =
                 mock<NetworkCapabilities>().also {
                     whenever(it.hasTransport(TRANSPORT_CELLULAR)).thenReturn(true)
-                    whenever(it.transportInfo).thenReturn(vcnInfo)
+                    whenever(it.transportInfo).thenReturn(vcnTransportInfo)
+                    whenever(it.underlyingNetworks).thenReturn(listOf(underlyingCell))
                 }
 
             getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, capabilities)
@@ -703,11 +738,12 @@
             val latest by collectLastValue(underTest.vcnSubId)
 
             val wifiInfo = mock<WifiInfo>()
-            val vcnInfo = VcnTransportInfo(wifiInfo)
+            val underlyingWifi = newWifiNetwork(wifiInfo)
             val capabilities =
                 mock<NetworkCapabilities>().also {
                     whenever(it.hasTransport(TRANSPORT_CELLULAR)).thenReturn(true)
-                    whenever(it.transportInfo).thenReturn(vcnInfo)
+                    whenever(it.transportInfo).thenReturn(vcnTransportInfo)
+                    whenever(it.underlyingNetworks).thenReturn(listOf(underlyingWifi))
                 }
 
             getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, capabilities)
@@ -721,14 +757,15 @@
             val latest by collectLastValue(underTest.vcnSubId)
 
             val wifiInfo = mock<WifiInfo>()
-            val wifiVcnInfo = VcnTransportInfo(wifiInfo)
-            val sub1VcnInfo = VcnTransportInfo(SUB_1_ID)
-            val sub2VcnInfo = VcnTransportInfo(SUB_2_ID)
+            val underlyingWifi = newWifiNetwork(wifiInfo)
+            val underlyingCell1 = newCellNetwork(SUB_1_ID)
+            val underlyingCell2 = newCellNetwork(SUB_2_ID)
 
             val capabilities =
                 mock<NetworkCapabilities>().also {
                     whenever(it.hasTransport(TRANSPORT_WIFI)).thenReturn(true)
-                    whenever(it.transportInfo).thenReturn(wifiVcnInfo)
+                    whenever(it.transportInfo).thenReturn(vcnTransportInfo)
+                    whenever(it.underlyingNetworks).thenReturn(listOf(underlyingWifi))
                 }
 
             // WIFI VCN info
@@ -738,14 +775,16 @@
 
             // Cellular VCN info with subId 1
             whenever(capabilities.hasTransport(eq(TRANSPORT_CELLULAR))).thenReturn(true)
-            whenever(capabilities.transportInfo).thenReturn(sub1VcnInfo)
+            whenever(capabilities.transportInfo).thenReturn(vcnTransportInfo)
+            whenever(capabilities.underlyingNetworks).thenReturn(listOf(underlyingCell1))
 
             getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, capabilities)
 
             assertThat(latest).isEqualTo(SUB_1_ID)
 
             // Cellular VCN info with subId 2
-            whenever(capabilities.transportInfo).thenReturn(sub2VcnInfo)
+            whenever(capabilities.transportInfo).thenReturn(vcnTransportInfo)
+            whenever(capabilities.underlyingNetworks).thenReturn(listOf(underlyingCell2))
 
             getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, capabilities)
 
@@ -776,11 +815,12 @@
     @Test
     fun getMainOrUnderlyingWifiInfo_vcnWithWifi_hasInfo() {
         val wifiInfo = mock<WifiInfo>()
-        val vcnInfo = VcnTransportInfo(wifiInfo)
+        val underlyingWifi = newWifiNetwork(wifiInfo)
         val capabilities =
             mock<NetworkCapabilities>().also {
                 whenever(it.hasTransport(TRANSPORT_WIFI)).thenReturn(true)
-                whenever(it.transportInfo).thenReturn(vcnInfo)
+                whenever(it.transportInfo).thenReturn(vcnTransportInfo)
+                whenever(it.underlyingNetworks).thenReturn(listOf(underlyingWifi))
             }
 
         val result = capabilities.getMainOrUnderlyingWifiInfo(connectivityManager)
@@ -860,11 +900,15 @@
     fun getMainOrUnderlyingWifiInfo_cellular_underlyingVcnWithWifi_hasInfo() {
         val wifiInfo = mock<WifiInfo>()
         val underlyingNetwork = mock<Network>()
-        val underlyingVcnInfo = VcnTransportInfo(wifiInfo)
+
+        // The Wifi network that is under the VCN network
+        val physicalWifiNetwork = newWifiNetwork(wifiInfo)
+
         val underlyingWifiCapabilities =
             mock<NetworkCapabilities>().also {
                 whenever(it.hasTransport(TRANSPORT_WIFI)).thenReturn(true)
-                whenever(it.transportInfo).thenReturn(underlyingVcnInfo)
+                whenever(it.transportInfo).thenReturn(vcnTransportInfo)
+                whenever(it.underlyingNetworks).thenReturn(listOf(physicalWifiNetwork))
             }
         whenever(connectivityManager.getNetworkCapabilities(underlyingNetwork))
             .thenReturn(underlyingWifiCapabilities)
@@ -887,11 +931,15 @@
     @DisableFlags(FLAG_STATUS_BAR_ALWAYS_CHECK_UNDERLYING_NETWORKS)
     fun getMainOrUnderlyingWifiInfo_notCellular_underlyingVcnWithWifi_noInfo() {
         val underlyingNetwork = mock<Network>()
-        val underlyingVcnInfo = VcnTransportInfo(mock<WifiInfo>())
+
+        // The Wifi network that is under the VCN network
+        val physicalWifiNetwork = newWifiNetwork(mock<WifiInfo>())
+
         val underlyingWifiCapabilities =
             mock<NetworkCapabilities>().also {
                 whenever(it.hasTransport(TRANSPORT_WIFI)).thenReturn(true)
-                whenever(it.transportInfo).thenReturn(underlyingVcnInfo)
+                whenever(it.transportInfo).thenReturn(vcnTransportInfo)
+                whenever(it.underlyingNetworks).thenReturn(listOf(physicalWifiNetwork))
             }
         whenever(connectivityManager.getNetworkCapabilities(underlyingNetwork))
             .thenReturn(underlyingWifiCapabilities)
@@ -917,10 +965,15 @@
         val underlyingCarrierMergedNetwork = mock<Network>()
         val carrierMergedInfo =
             mock<WifiInfo>().apply { whenever(this.isCarrierMerged).thenReturn(true) }
+
+        // The Wifi network that is under the VCN network
+        val physicalWifiNetwork = newWifiNetwork(carrierMergedInfo)
+
         val underlyingCapabilities =
             mock<NetworkCapabilities>().also {
                 whenever(it.hasTransport(TRANSPORT_CELLULAR)).thenReturn(true)
-                whenever(it.transportInfo).thenReturn(VcnTransportInfo(carrierMergedInfo))
+                whenever(it.transportInfo).thenReturn(vcnTransportInfo)
+                whenever(it.underlyingNetworks).thenReturn(listOf(physicalWifiNetwork))
             }
         whenever(connectivityManager.getNetworkCapabilities(underlyingCarrierMergedNetwork))
             .thenReturn(underlyingCapabilities)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImplTest.kt
index fd4b77d..44e1437 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImplTest.kt
@@ -26,19 +26,20 @@
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.table.TableLogBuffer
+import com.android.systemui.log.table.logcatTableLogBuffer
 import com.android.systemui.statusbar.connectivity.WifiPickerTrackerFactory
 import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel
 import com.android.systemui.statusbar.pipeline.wifi.data.repository.prod.WifiRepositoryImpl.Companion.WIFI_NETWORK_DEFAULT
 import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiNetworkModel
 import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiScanEntry
+import com.android.systemui.testKosmos
 import com.android.systemui.util.concurrency.FakeExecutor
 import com.android.systemui.util.mockito.any
 import com.android.systemui.util.mockito.argumentCaptor
 import com.android.systemui.util.mockito.capture
 import com.android.systemui.util.mockito.mock
 import com.android.systemui.util.mockito.whenever
-import com.android.systemui.util.time.FakeSystemClock
+import com.android.systemui.util.time.fakeSystemClock
 import com.android.wifitrackerlib.HotspotNetworkEntry
 import com.android.wifitrackerlib.HotspotNetworkEntry.DeviceType
 import com.android.wifitrackerlib.MergedCarrierEntry
@@ -67,6 +68,7 @@
 @SmallTest
 @TestableLooper.RunWithLooper(setAsMainLooper = true)
 class WifiRepositoryImplTest : SysuiTestCase() {
+    private val kosmos = testKosmos()
 
     // Using lazy means that the class will only be constructed once it's fetched. Because the
     // repository internally sets some values on construction, we need to set up some test
@@ -84,9 +86,9 @@
         )
     }
 
-    private val executor = FakeExecutor(FakeSystemClock())
+    private val executor = FakeExecutor(kosmos.fakeSystemClock)
     private val logger = LogBuffer("name", maxSize = 100, logcatEchoTracker = mock())
-    private val tableLogger = mock<TableLogBuffer>()
+    private val tableLogger = logcatTableLogBuffer(kosmos, "WifiRepositoryImplTest")
     private val wifiManager =
         mock<WifiManager>().apply { whenever(this.maxSignalLevel).thenReturn(10) }
     private val wifiPickerTrackerFactory = mock<WifiPickerTrackerFactory>()
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
deleted file mode 100644
index 637a0f1..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/ZenModeControllerImplTest.java
+++ /dev/null
@@ -1,201 +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.systemui.statusbar.policy;
-
-import static junit.framework.Assert.assertEquals;
-import static junit.framework.Assert.assertFalse;
-import static junit.framework.Assert.assertTrue;
-
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.app.NotificationManager;
-import android.os.Handler;
-import android.provider.Settings;
-import android.service.notification.ZenModeConfig;
-import android.testing.TestableLooper;
-import android.testing.TestableLooper.RunWithLooper;
-
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import androidx.test.filters.SmallTest;
-
-import com.android.systemui.SysuiTestCase;
-import com.android.systemui.broadcast.BroadcastDispatcher;
-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.FakeGlobalSettings;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-import java.util.List;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.atomic.AtomicInteger;
-
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-@RunWithLooper
-public class ZenModeControllerImplTest extends SysuiTestCase {
-
-    private Callback mCallback;
-    @Mock
-    NotificationManager mNm;
-    @Mock
-    ZenModeConfig mConfig;
-    @Mock
-    BroadcastDispatcher mBroadcastDispatcher;
-    @Mock
-    DumpManager mDumpManager;
-    @Mock
-    UserTracker mUserTracker;
-    private ZenModeControllerImpl mController;
-
-    private final FakeGlobalSettings mGlobalSettings = new FakeGlobalSettings();
-
-    @Before
-    public void setUp() {
-        MockitoAnnotations.initMocks(this);
-        mContext.addMockSystemService(NotificationManager.class, mNm);
-        when(mNm.getZenModeConfig()).thenReturn(mConfig);
-
-        mController = new ZenModeControllerImpl(
-                mContext,
-                Handler.createAsync(TestableLooper.get(this).getLooper()),
-                Handler.createAsync(TestableLooper.get(this).getLooper()),
-                mBroadcastDispatcher,
-                mDumpManager,
-                mGlobalSettings,
-                mUserTracker);
-    }
-
-    @Test
-    public void testRemoveDuringCallback() {
-        mCallback = new Callback() {
-            @Override
-            public void onConfigChanged(ZenModeConfig config) {
-                mController.removeCallback(mCallback);
-            }
-        };
-        mController.addCallback(mCallback);
-        Callback mockCallback = mock(Callback.class);
-        mController.addCallback(mockCallback);
-        mController.fireConfigChanged(null);
-        verify(mockCallback).onConfigChanged(eq(null));
-    }
-
-    @Test
-    public void testAreNotificationsHiddenInShade_zenOffShadeSuppressed() {
-        mConfig.suppressedVisualEffects =
-                NotificationManager.Policy.SUPPRESSED_EFFECT_NOTIFICATION_LIST;
-        mController.updateZenMode(Settings.Global.ZEN_MODE_OFF);
-        mController.updateZenModeConfig();
-
-        assertFalse(mController.areNotificationsHiddenInShade());
-    }
-
-    @Test
-    public void testAreNotificationsHiddenInShade_zenOnShadeNotSuppressed() {
-        NotificationManager.Policy policy = new NotificationManager.Policy(0, 0, 0,
-                NotificationManager.Policy.SUPPRESSED_EFFECT_STATUS_BAR);
-        when(mNm.getConsolidatedNotificationPolicy()).thenReturn(policy);
-        mController.updateConsolidatedNotificationPolicy();
-        mController.updateZenMode(Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS);
-
-        assertFalse(mController.areNotificationsHiddenInShade());
-    }
-
-    @Test
-    public void testAreNotificationsHiddenInShade_zenOnShadeSuppressed() {
-        NotificationManager.Policy policy = new NotificationManager.Policy(0, 0, 0,
-                NotificationManager.Policy.SUPPRESSED_EFFECT_NOTIFICATION_LIST);
-        when(mNm.getConsolidatedNotificationPolicy()).thenReturn(policy);
-        mController.updateConsolidatedNotificationPolicy();
-        mController.updateZenMode(Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS);
-
-        assertTrue(mController.areNotificationsHiddenInShade());
-    }
-
-    @Test
-    public void testModeChange() {
-        List<Integer> states = List.of(
-                Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS,
-                Settings.Global.ZEN_MODE_NO_INTERRUPTIONS,
-                Settings.Global.ZEN_MODE_ALARMS,
-                Settings.Global.ZEN_MODE_ALARMS
-        );
-
-        for (Integer state : states) {
-            mGlobalSettings.putInt(Settings.Global.ZEN_MODE, state);
-            TestableLooper.get(this).processAllMessages();
-            assertEquals(state.intValue(), mController.getZen());
-        }
-    }
-
-    @Test
-    public void testModeChange_callbackNotified() {
-        final AtomicInteger currentState = new AtomicInteger(-1);
-
-        ZenModeController.Callback callback = new Callback() {
-            @Override
-            public void onZenChanged(int zen) {
-                currentState.set(zen);
-            }
-        };
-
-        mController.addCallback(callback);
-
-        List<Integer> states = List.of(
-                Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS,
-                Settings.Global.ZEN_MODE_NO_INTERRUPTIONS,
-                Settings.Global.ZEN_MODE_ALARMS,
-                Settings.Global.ZEN_MODE_ALARMS
-        );
-
-        for (Integer state : states) {
-            mGlobalSettings.putInt(Settings.Global.ZEN_MODE, state);
-            TestableLooper.get(this).processAllMessages();
-            assertEquals(state.intValue(), currentState.get());
-        }
-
-    }
-
-    @Test
-    public void testCallbackRemovedWhileDispatching_doesntCrash() {
-        final AtomicBoolean remove = new AtomicBoolean(false);
-        mGlobalSettings.putInt(Settings.Global.ZEN_MODE, Settings.Global.ZEN_MODE_OFF);
-        TestableLooper.get(this).processAllMessages();
-        final ZenModeController.Callback callback = new ZenModeController.Callback() {
-            @Override
-            public void onZenChanged(int zen) {
-                if (remove.get()) {
-                    mController.removeCallback(this);
-                }
-            }
-        };
-        mController.addCallback(callback);
-        mController.addCallback(new ZenModeController.Callback() {});
-
-        remove.set(true);
-
-        mGlobalSettings.putInt(Settings.Global.ZEN_MODE, Settings.Global.ZEN_MODE_NO_INTERRUPTIONS);
-        TestableLooper.get(this).processAllMessages();
-    }
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/window/MultiDisplayStatusBarWindowControllerStoreTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/window/MultiDisplayStatusBarWindowControllerStoreTest.kt
new file mode 100644
index 0000000..faaa4c4
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/window/MultiDisplayStatusBarWindowControllerStoreTest.kt
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.window
+
+import android.platform.test.annotations.EnableFlags
+import android.view.Display
+import android.view.WindowManager
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.app.viewcapture.ViewCaptureAwareWindowManager
+import com.android.app.viewcapture.mockViewCaptureAwareWindowManager
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.display.data.repository.displayRepository
+import com.android.systemui.display.data.repository.fakeDisplayWindowPropertiesRepository
+import com.android.systemui.kosmos.applicationCoroutineScope
+import com.android.systemui.kosmos.testDispatcher
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.kosmos.unconfinedTestDispatcher
+import com.android.systemui.statusbar.core.StatusBarConnectedDisplays
+import com.android.systemui.testKosmos
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.runBlocking
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.kotlin.doReturn
+import org.mockito.kotlin.mock
+
+@RunWith(AndroidJUnit4::class)
+@SmallTest
+@EnableFlags(StatusBarConnectedDisplays.FLAG_NAME)
+class MultiDisplayStatusBarWindowControllerStoreTest : SysuiTestCase() {
+
+    private val kosmos = testKosmos().also { it.testDispatcher = it.unconfinedTestDispatcher }
+    private val testScope = kosmos.testScope
+    private val fakeDisplayRepository = kosmos.displayRepository
+
+    private val store =
+        MultiDisplayStatusBarWindowControllerStore(
+            backgroundApplicationScope = kosmos.applicationCoroutineScope,
+            controllerFactory = kosmos.fakeStatusBarWindowControllerFactory,
+            displayWindowPropertiesRepository = kosmos.fakeDisplayWindowPropertiesRepository,
+            viewCaptureAwareWindowManagerFactory =
+                object : ViewCaptureAwareWindowManager.Factory {
+                    override fun create(
+                        windowManager: WindowManager
+                    ): ViewCaptureAwareWindowManager {
+                        return kosmos.mockViewCaptureAwareWindowManager
+                    }
+                },
+            displayRepository = fakeDisplayRepository,
+        )
+
+    @Before
+    fun start() {
+        store.start()
+    }
+
+    @Before
+    fun addDisplays() = runBlocking {
+        fakeDisplayRepository.addDisplay(createDisplay(DEFAULT_DISPLAY_ID))
+        fakeDisplayRepository.addDisplay(createDisplay(NON_DEFAULT_DISPLAY_ID))
+    }
+
+    @Test
+    fun forDisplay_defaultDisplay_multipleCalls_returnsSameInstance() =
+        testScope.runTest {
+            val controller = store.defaultDisplay
+
+            assertThat(store.defaultDisplay).isSameInstanceAs(controller)
+        }
+
+    @Test
+    fun forDisplay_nonDefaultDisplay_multipleCalls_returnsSameInstance() =
+        testScope.runTest {
+            val controller = store.forDisplay(NON_DEFAULT_DISPLAY_ID)
+
+            assertThat(store.forDisplay(NON_DEFAULT_DISPLAY_ID)).isSameInstanceAs(controller)
+        }
+
+    @Test
+    fun forDisplay_nonDefaultDisplay_afterDisplayRemoved_returnsNewInstance() =
+        testScope.runTest {
+            val controller = store.forDisplay(NON_DEFAULT_DISPLAY_ID)
+
+            fakeDisplayRepository.removeDisplay(NON_DEFAULT_DISPLAY_ID)
+            fakeDisplayRepository.addDisplay(createDisplay(NON_DEFAULT_DISPLAY_ID))
+
+            assertThat(store.forDisplay(NON_DEFAULT_DISPLAY_ID)).isNotSameInstanceAs(controller)
+        }
+
+    @Test(expected = IllegalArgumentException::class)
+    fun forDisplay_nonExistingDisplayId_throws() =
+        testScope.runTest { store.forDisplay(NON_EXISTING_DISPLAY_ID) }
+
+    private fun createDisplay(displayId: Int): Display = mock {
+        on { getDisplayId() } doReturn displayId
+    }
+
+    companion object {
+        private const val DEFAULT_DISPLAY_ID = Display.DEFAULT_DISPLAY
+        private const val NON_DEFAULT_DISPLAY_ID = DEFAULT_DISPLAY_ID + 1
+        private const val NON_EXISTING_DISPLAY_ID = DEFAULT_DISPLAY_ID + 2
+    }
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/FixedColumnsSizeInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/app/WallpaperManagerKosmos.kt
similarity index 64%
copy from packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/FixedColumnsSizeInteractorKosmos.kt
copy to packages/SystemUI/tests/utils/src/com/android/app/WallpaperManagerKosmos.kt
index f4d281d..2850ab7 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/FixedColumnsSizeInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/app/WallpaperManagerKosmos.kt
@@ -13,11 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+package com.android.app
 
-package com.android.systemui.qs.panels.domain.interactor
-
+import android.app.WallpaperManager
+import android.content.applicationContext
 import com.android.systemui.kosmos.Kosmos
-import com.android.systemui.qs.panels.data.repository.fixedColumnsRepository
+import com.android.systemui.kosmos.Kosmos.Fixture
+import kotlinx.coroutines.ExperimentalCoroutinesApi
 
-val Kosmos.fixedColumnsSizeInteractor by
-    Kosmos.Fixture { FixedColumnsSizeInteractor(fixedColumnsRepository) }
+@OptIn(ExperimentalCoroutinesApi::class)
+val Kosmos.wallpaperManager: WallpaperManager by Fixture {
+    WallpaperManager.getInstance(applicationContext)
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/FixedColumnsSizeInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/app/viewcapture/ViewCaptureAwareWindowManagerKosmos.kt
similarity index 67%
copy from packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/FixedColumnsSizeInteractorKosmos.kt
copy to packages/SystemUI/tests/utils/src/com/android/app/viewcapture/ViewCaptureAwareWindowManagerKosmos.kt
index f4d281d..e1c6699 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/FixedColumnsSizeInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/app/viewcapture/ViewCaptureAwareWindowManagerKosmos.kt
@@ -14,10 +14,13 @@
  * limitations under the License.
  */
 
-package com.android.systemui.qs.panels.domain.interactor
+package com.android.app.viewcapture
 
 import com.android.systemui.kosmos.Kosmos
-import com.android.systemui.qs.panels.data.repository.fixedColumnsRepository
+import org.mockito.kotlin.mock
 
-val Kosmos.fixedColumnsSizeInteractor by
-    Kosmos.Fixture { FixedColumnsSizeInteractor(fixedColumnsRepository) }
+val Kosmos.mockViewCaptureAwareWindowManager by
+    Kosmos.Fixture { mock<ViewCaptureAwareWindowManager>() }
+
+var Kosmos.viewCaptureAwareWindowManager: ViewCaptureAwareWindowManager by
+    Kosmos.Fixture { mockViewCaptureAwareWindowManager }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/bluetooth/qsdialog/AudioSharingButtonViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/bluetooth/qsdialog/AudioSharingButtonViewModelKosmos.kt
new file mode 100644
index 0000000..cac4ff3
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/bluetooth/qsdialog/AudioSharingButtonViewModelKosmos.kt
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.bluetooth.qsdialog
+
+import com.android.systemui.kosmos.Kosmos
+
+val Kosmos.audioSharingButtonViewModel: AudioSharingButtonViewModel by
+    Kosmos.Fixture {
+        AudioSharingButtonViewModel(
+            localBluetoothManager,
+            audioSharingInteractor,
+            bluetoothStateInteractor,
+            deviceItemInteractor,
+        )
+    }
+
+val Kosmos.audioSharingButtonViewModelFactory: AudioSharingButtonViewModel.Factory by
+    Kosmos.Fixture {
+        object : AudioSharingButtonViewModel.Factory {
+            override fun create(): AudioSharingButtonViewModel {
+                return audioSharingButtonViewModel
+            }
+        }
+    }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/bluetooth/qsdialog/AudioSharingDeviceItemActionInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/bluetooth/qsdialog/AudioSharingDeviceItemActionInteractorKosmos.kt
new file mode 100644
index 0000000..8019efc
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/bluetooth/qsdialog/AudioSharingDeviceItemActionInteractorKosmos.kt
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.bluetooth.qsdialog
+
+import com.android.internal.logging.uiEventLogger
+import com.android.settingslib.bluetooth.CachedBluetoothDevice
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.testDispatcher
+import com.android.systemui.plugins.activityStarter
+
+val Kosmos.audioSharingDeviceItemActionInteractorImpl: AudioSharingDeviceItemActionInteractorImpl by
+    Kosmos.Fixture {
+        AudioSharingDeviceItemActionInteractorImpl(
+            activityStarter,
+            audioSharingInteractor,
+            dialogTransitionAnimator,
+            localBluetoothManager,
+            testDispatcher,
+            testDispatcher,
+            bluetoothTileDialogLogger,
+            uiEventLogger,
+            audioSharingDialogDelegateFactory,
+            deviceItemActionInteractorImpl,
+        )
+    }
+
+val Kosmos.audioSharingDialogDelegateFactory: AudioSharingDialogDelegate.Factory by
+    Kosmos.Fixture {
+        object : AudioSharingDialogDelegate.Factory {
+            override fun create(
+                cachedBluetoothDevice: CachedBluetoothDevice
+            ): AudioSharingDialogDelegate {
+                return audioSharingDialogDelegate
+            }
+        }
+    }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/bluetooth/qsdialog/AudioSharingDialogViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/bluetooth/qsdialog/AudioSharingDialogViewModelKosmos.kt
new file mode 100644
index 0000000..b8899de8
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/bluetooth/qsdialog/AudioSharingDialogViewModelKosmos.kt
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.bluetooth.qsdialog
+
+import android.content.applicationContext
+import com.android.internal.logging.uiEventLogger
+import com.android.settingslib.bluetooth.CachedBluetoothDevice
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.testDispatcher
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.statusbar.phone.systemUIDialogDotFactory
+import kotlinx.coroutines.CoroutineScope
+import org.mockito.kotlin.mock
+
+val Kosmos.cachedBluetoothDevice: CachedBluetoothDevice by Kosmos.Fixture { mock {} }
+
+val Kosmos.audioSharingDialogViewModel: AudioSharingDialogViewModel by
+    Kosmos.Fixture {
+        AudioSharingDialogViewModel(
+            deviceItemInteractor,
+            audioSharingInteractor,
+            applicationContext,
+            localBluetoothManager,
+            cachedBluetoothDevice,
+            testScope.backgroundScope,
+            testDispatcher
+        )
+    }
+
+val Kosmos.audioSharingDialogViewModelFactory: AudioSharingDialogViewModel.Factory by
+    Kosmos.Fixture {
+        object : AudioSharingDialogViewModel.Factory {
+            override fun create(
+                cachedBluetoothDevice: CachedBluetoothDevice,
+                coroutineScope: CoroutineScope
+            ): AudioSharingDialogViewModel {
+                return audioSharingDialogViewModel
+            }
+        }
+    }
+
+val Kosmos.audioSharingDialogDelegate: AudioSharingDialogDelegate by
+    Kosmos.Fixture {
+        AudioSharingDialogDelegate(
+            cachedBluetoothDevice,
+            testScope.backgroundScope,
+            audioSharingDialogViewModelFactory,
+            systemUIDialogDotFactory,
+            uiEventLogger
+        )
+    }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/ui/viewmodel/PartitionedGridViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/bluetooth/qsdialog/AudioSharingInteractorKosmos.kt
similarity index 68%
rename from packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/ui/viewmodel/PartitionedGridViewModelKosmos.kt
rename to packages/SystemUI/tests/utils/src/com/android/systemui/bluetooth/qsdialog/AudioSharingInteractorKosmos.kt
index fde174d..4f4d1da 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/ui/viewmodel/PartitionedGridViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/bluetooth/qsdialog/AudioSharingInteractorKosmos.kt
@@ -14,15 +14,16 @@
  * limitations under the License.
  */
 
-package com.android.systemui.qs.panels.ui.viewmodel
+package com.android.systemui.bluetooth.qsdialog
 
 import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.testDispatcher
 
-val Kosmos.partitionedGridViewModel by
+val Kosmos.audioSharingInteractor: AudioSharingInteractor by
     Kosmos.Fixture {
-        PartitionedGridViewModel(
-            iconTilesViewModel,
-            fixedColumnsSizeViewModel,
-            iconLabelVisibilityViewModel,
+        AudioSharingInteractorImpl(
+            localBluetoothManager,
+            bluetoothTileDialogAudioSharingRepository,
+            testDispatcher,
         )
     }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/data/repository/FixedColumnsRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/bluetooth/qsdialog/AudioSharingRepositoryKosmos.kt
similarity index 80%
rename from packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/data/repository/FixedColumnsRepositoryKosmos.kt
rename to packages/SystemUI/tests/utils/src/com/android/systemui/bluetooth/qsdialog/AudioSharingRepositoryKosmos.kt
index 2f5daaa..d15d0e5 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/data/repository/FixedColumnsRepositoryKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/bluetooth/qsdialog/AudioSharingRepositoryKosmos.kt
@@ -14,8 +14,9 @@
  * limitations under the License.
  */
 
-package com.android.systemui.qs.panels.data.repository
+package com.android.systemui.bluetooth.qsdialog
 
 import com.android.systemui.kosmos.Kosmos
 
-val Kosmos.fixedColumnsRepository by Kosmos.Fixture { FixedColumnsRepository() }
+val Kosmos.bluetoothTileDialogAudioSharingRepository by
+    Kosmos.Fixture { FakeAudioSharingRepository() }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/bluetooth/qsdialog/BluetoothDeviceMetadataInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/bluetooth/qsdialog/BluetoothDeviceMetadataInteractorKosmos.kt
similarity index 100%
rename from packages/SystemUI/multivalentTests/src/com/android/systemui/bluetooth/qsdialog/BluetoothDeviceMetadataInteractorKosmos.kt
rename to packages/SystemUI/tests/utils/src/com/android/systemui/bluetooth/qsdialog/BluetoothDeviceMetadataInteractorKosmos.kt
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/ui/viewmodel/PartitionedGridViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/bluetooth/qsdialog/BluetoothStateInteractorKosmos.kt
similarity index 64%
copy from packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/ui/viewmodel/PartitionedGridViewModelKosmos.kt
copy to packages/SystemUI/tests/utils/src/com/android/systemui/bluetooth/qsdialog/BluetoothStateInteractorKosmos.kt
index fde174d..aaa918c 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/ui/viewmodel/PartitionedGridViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/bluetooth/qsdialog/BluetoothStateInteractorKosmos.kt
@@ -14,15 +14,18 @@
  * limitations under the License.
  */
 
-package com.android.systemui.qs.panels.ui.viewmodel
+package com.android.systemui.bluetooth.qsdialog
 
 import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.testDispatcher
+import com.android.systemui.kosmos.testScope
 
-val Kosmos.partitionedGridViewModel by
+val Kosmos.bluetoothStateInteractor: BluetoothStateInteractor by
     Kosmos.Fixture {
-        PartitionedGridViewModel(
-            iconTilesViewModel,
-            fixedColumnsSizeViewModel,
-            iconLabelVisibilityViewModel,
+        BluetoothStateInteractor(
+            localBluetoothManager,
+            bluetoothTileDialogLogger,
+            testScope.backgroundScope,
+            testDispatcher
         )
     }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/bluetooth/qsdialog/DeviceItemActionInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/bluetooth/qsdialog/DeviceItemActionInteractorKosmos.kt
similarity index 79%
rename from packages/SystemUI/multivalentTests/src/com/android/systemui/bluetooth/qsdialog/DeviceItemActionInteractorKosmos.kt
rename to packages/SystemUI/tests/utils/src/com/android/systemui/bluetooth/qsdialog/DeviceItemActionInteractorKosmos.kt
index 5ff4634..b5b2f5e 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/bluetooth/qsdialog/DeviceItemActionInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/bluetooth/qsdialog/DeviceItemActionInteractorKosmos.kt
@@ -20,8 +20,7 @@
 import com.android.systemui.animation.DialogTransitionAnimator
 import com.android.systemui.kosmos.Kosmos
 import com.android.systemui.kosmos.testDispatcher
-import com.android.systemui.plugins.activityStarter
-import com.android.systemui.util.mockito.mock
+import org.mockito.kotlin.mock
 
 val Kosmos.bluetoothTileDialogLogger: BluetoothTileDialogLogger by Kosmos.Fixture { mock {} }
 
@@ -29,14 +28,10 @@
 
 val Kosmos.dialogTransitionAnimator: DialogTransitionAnimator by Kosmos.Fixture { mock {} }
 
-val Kosmos.deviceItemActionInteractor: DeviceItemActionInteractor by
+val Kosmos.deviceItemActionInteractorImpl: DeviceItemActionInteractorImpl by
     Kosmos.Fixture {
-        DeviceItemActionInteractor(
-            activityStarter,
-            dialogTransitionAnimator,
-            localBluetoothManager,
+        DeviceItemActionInteractorImpl(
             testDispatcher,
-            bluetoothTileDialogLogger,
             uiEventLogger,
         )
     }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/bluetooth/qsdialog/FakeAudioSharingRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/bluetooth/qsdialog/FakeAudioSharingRepository.kt
new file mode 100644
index 0000000..a839f17
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/bluetooth/qsdialog/FakeAudioSharingRepository.kt
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.bluetooth.qsdialog
+
+import com.android.settingslib.bluetooth.CachedBluetoothDevice
+import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcast
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableSharedFlow
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.StateFlow
+
+class FakeAudioSharingRepository : AudioSharingRepository {
+    private var mutableAvailable: Boolean = false
+
+    private val mutableInAudioSharing: MutableStateFlow<Boolean> = MutableStateFlow(false)
+
+    private val mutableAudioSourceStateUpdate = MutableSharedFlow<Unit>()
+
+    var sourceAdded: Boolean = false
+        private set
+
+    private var profile: LocalBluetoothLeBroadcast? = null
+
+    override val leAudioBroadcastProfile: LocalBluetoothLeBroadcast?
+        get() = profile
+
+    override val audioSourceStateUpdate: Flow<Unit> = mutableAudioSourceStateUpdate
+
+    override val inAudioSharing: StateFlow<Boolean> = mutableInAudioSharing
+
+    override suspend fun audioSharingAvailable(): Boolean = mutableAvailable
+
+    override suspend fun addSource() {
+        sourceAdded = true
+    }
+
+    override suspend fun setActive(cachedBluetoothDevice: CachedBluetoothDevice) {}
+
+    override suspend fun startAudioSharing() {}
+
+    fun setAudioSharingAvailable(available: Boolean) {
+        mutableAvailable = available
+    }
+
+    fun setInAudioSharing(state: Boolean) {
+        mutableInAudioSharing.value = state
+    }
+
+    fun setLeAudioBroadcastProfile(leAudioBroadcastProfile: LocalBluetoothLeBroadcast?) {
+        profile = leAudioBroadcastProfile
+    }
+
+    fun emitAudioSourceStateUpdate() {
+        mutableAudioSourceStateUpdate.tryEmit(Unit)
+    }
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/brightness/domain/interactor/ScreenBrightnessInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/brightness/domain/interactor/ScreenBrightnessInteractorKosmos.kt
index 0e84273..e470e37 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/brightness/domain/interactor/ScreenBrightnessInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/brightness/domain/interactor/ScreenBrightnessInteractorKosmos.kt
@@ -19,14 +19,13 @@
 import com.android.systemui.brightness.data.repository.screenBrightnessRepository
 import com.android.systemui.kosmos.Kosmos
 import com.android.systemui.kosmos.applicationCoroutineScope
-import com.android.systemui.log.table.TableLogBuffer
-import com.android.systemui.util.mockito.mock
+import com.android.systemui.log.table.logcatTableLogBuffer
 
 val Kosmos.screenBrightnessInteractor by
     Kosmos.Fixture {
         ScreenBrightnessInteractor(
             screenBrightnessRepository,
             applicationCoroutineScope,
-            mock<TableLogBuffer>(),
+            logcatTableLogBuffer(this, "screenBrightness"),
         )
     }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/brightness/ui/viewmodel/BrightnessSliderViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/brightness/ui/viewmodel/BrightnessSliderViewModelKosmos.kt
index d208465..6889b8a 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/brightness/ui/viewmodel/BrightnessSliderViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/brightness/ui/viewmodel/BrightnessSliderViewModelKosmos.kt
@@ -18,6 +18,7 @@
 
 import com.android.systemui.brightness.domain.interactor.brightnessPolicyEnforcementInteractor
 import com.android.systemui.brightness.domain.interactor.screenBrightnessInteractor
+import com.android.systemui.haptics.slider.sliderHapticsViewModelFactory
 import com.android.systemui.kosmos.Kosmos
 import com.android.systemui.kosmos.applicationCoroutineScope
 
@@ -27,5 +28,6 @@
             screenBrightnessInteractor = screenBrightnessInteractor,
             brightnessPolicyEnforcementInteractor = brightnessPolicyEnforcementInteractor,
             applicationScope = applicationCoroutineScope,
+            hapticsViewModelFactory = sliderHapticsViewModelFactory,
         )
     }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/data/repository/FakeCommunalWidgetRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/data/repository/FakeCommunalWidgetRepository.kt
index 1302faa..62d221d 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/data/repository/FakeCommunalWidgetRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/data/repository/FakeCommunalWidgetRepository.kt
@@ -6,6 +6,7 @@
 import android.content.pm.ApplicationInfo
 import android.graphics.Bitmap
 import android.os.UserHandle
+import com.android.systemui.communal.shared.model.CommunalContentSize
 import com.android.systemui.communal.shared.model.CommunalWidgetContentModel
 import com.android.systemui.communal.widgets.WidgetConfigurator
 import kotlinx.coroutines.CoroutineScope
@@ -23,6 +24,10 @@
 
     private var nextWidgetId = 1
 
+    private fun updateListFromDatabase() {
+        _communalWidgets.value = fakeDatabase.values.sortedWith(compareBy { it.rank }).toList()
+    }
+
     fun setCommunalWidgets(inventory: List<CommunalWidgetContentModel>) {
         _communalWidgets.value = inventory
     }
@@ -49,6 +54,7 @@
         rank: Int = 0,
         category: Int = AppWidgetProviderInfo.WIDGET_CATEGORY_KEYGUARD,
         userId: Int = 0,
+        spanY: Int = CommunalContentSize.HALF.span,
     ) {
         fakeDatabase[appWidgetId] =
             CommunalWidgetContentModel.Available(
@@ -66,8 +72,9 @@
                                     }
                             }
                     },
+                spanY = spanY,
             )
-        _communalWidgets.value = fakeDatabase.values.toList()
+        updateListFromDatabase()
     }
 
     fun addPendingWidget(
@@ -84,8 +91,9 @@
                 componentName = ComponentName.unflattenFromString(componentName)!!,
                 icon = icon,
                 user = UserHandle(userId),
+                spanY = CommunalContentSize.HALF.span,
             )
-        _communalWidgets.value = fakeDatabase.values.toList()
+        updateListFromDatabase()
     }
 
     override fun deleteWidget(widgetId: Int) {
@@ -93,28 +101,54 @@
         _communalWidgets.value = fakeDatabase.values.toList()
     }
 
-    override fun updateWidgetSpanY(widgetId: Int, spanY: Int) {
-        coroutineScope.launch {
-            fakeDatabase[widgetId]?.let { widget ->
+    private fun reorderDatabase(widgetIdToRankMap: Map<Int, Int>) {
+        for ((id, rank) in widgetIdToRankMap) {
+            val widget = fakeDatabase[id] ?: continue
+            fakeDatabase[id] =
                 when (widget) {
                     is CommunalWidgetContentModel.Available -> {
-                        fakeDatabase[widgetId] = widget.copy(spanY = spanY)
+                        widget.copy(rank = rank)
                     }
                     is CommunalWidgetContentModel.Pending -> {
-                        fakeDatabase[widgetId] = widget.copy(spanY = spanY)
+                        widget.copy(rank = rank)
                     }
                 }
-                _communalWidgets.value = fakeDatabase.values.toList()
-            }
         }
     }
 
+    override fun updateWidgetOrder(widgetIdToRankMap: Map<Int, Int>) {
+        reorderDatabase(widgetIdToRankMap)
+        updateListFromDatabase()
+    }
+
+    override fun resizeWidget(appWidgetId: Int, spanY: Int, widgetIdToRankMap: Map<Int, Int>) {
+        val widget = fakeDatabase[appWidgetId] ?: return
+
+        fakeDatabase[appWidgetId] =
+            when (widget) {
+                is CommunalWidgetContentModel.Available -> {
+                    widget.copy(spanY = spanY)
+                }
+                is CommunalWidgetContentModel.Pending -> {
+                    widget.copy(spanY = spanY)
+                }
+            }
+        reorderDatabase(widgetIdToRankMap)
+        updateListFromDatabase()
+    }
+
     override fun restoreWidgets(oldToNewWidgetIdMap: Map<Int, Int>) {}
 
     override fun abortRestoreWidgets() {}
 
     private fun onConfigured(id: Int, providerInfo: AppWidgetProviderInfo, rank: Int) {
-        _communalWidgets.value +=
-            listOf(CommunalWidgetContentModel.Available(id, providerInfo, rank))
+        fakeDatabase[id] =
+            CommunalWidgetContentModel.Available(
+                appWidgetId = id,
+                providerInfo = providerInfo,
+                rank = rank,
+                spanY = CommunalContentSize.HALF.span,
+            )
+        updateListFromDatabase()
     }
 }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/ui/viewmodel/PartitionedGridViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/display/data/repository/DisplayScopeRepositoryKosmos.kt
similarity index 67%
copy from packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/ui/viewmodel/PartitionedGridViewModelKosmos.kt
copy to packages/SystemUI/tests/utils/src/com/android/systemui/display/data/repository/DisplayScopeRepositoryKosmos.kt
index fde174d..ff4ba61 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/ui/viewmodel/PartitionedGridViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/display/data/repository/DisplayScopeRepositoryKosmos.kt
@@ -14,15 +14,13 @@
  * limitations under the License.
  */
 
-package com.android.systemui.qs.panels.ui.viewmodel
+package com.android.systemui.display.data.repository
 
 import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.testDispatcher
 
-val Kosmos.partitionedGridViewModel by
-    Kosmos.Fixture {
-        PartitionedGridViewModel(
-            iconTilesViewModel,
-            fixedColumnsSizeViewModel,
-            iconLabelVisibilityViewModel,
-        )
-    }
+val Kosmos.fakeDisplayScopeRepository by
+    Kosmos.Fixture { FakeDisplayScopeRepository(testDispatcher) }
+
+var Kosmos.displayScopeRepository: DisplayScopeRepository by
+    Kosmos.Fixture { fakeDisplayScopeRepository }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/FixedColumnsSizeInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/display/data/repository/DisplayWindowPropertiesRepositoryKosmos.kt
similarity index 67%
copy from packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/FixedColumnsSizeInteractorKosmos.kt
copy to packages/SystemUI/tests/utils/src/com/android/systemui/display/data/repository/DisplayWindowPropertiesRepositoryKosmos.kt
index f4d281d..65b18c1 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/FixedColumnsSizeInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/display/data/repository/DisplayWindowPropertiesRepositoryKosmos.kt
@@ -14,10 +14,12 @@
  * limitations under the License.
  */
 
-package com.android.systemui.qs.panels.domain.interactor
+package com.android.systemui.display.data.repository
 
 import com.android.systemui.kosmos.Kosmos
-import com.android.systemui.qs.panels.data.repository.fixedColumnsRepository
 
-val Kosmos.fixedColumnsSizeInteractor by
-    Kosmos.Fixture { FixedColumnsSizeInteractor(fixedColumnsRepository) }
+val Kosmos.fakeDisplayWindowPropertiesRepository by
+    Kosmos.Fixture { FakeDisplayWindowPropertiesRepository() }
+
+var Kosmos.displayWindowPropertiesRepository: DisplayWindowPropertiesRepository by
+    Kosmos.Fixture { fakeDisplayWindowPropertiesRepository }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/display/data/repository/FakeDisplayRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/display/data/repository/FakeDisplayRepository.kt
index 6c3cf91..fcc83b3 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/display/data/repository/FakeDisplayRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/display/data/repository/FakeDisplayRepository.kt
@@ -24,16 +24,12 @@
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.MutableSharedFlow
 import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.StateFlow
 import kotlinx.coroutines.flow.asStateFlow
 import org.mockito.Mockito.`when` as whenever
 
 /** Creates a mock display. */
-fun display(
-    type: Int,
-    flags: Int = 0,
-    id: Int = 0,
-    state: Int? = null,
-): Display {
+fun display(type: Int, flags: Int = 0, id: Int = 0, state: Int? = null): Display {
     return mock {
         whenever(this.displayId).thenReturn(id)
         whenever(this.type).thenReturn(type)
@@ -51,10 +47,21 @@
 @SysUISingleton
 /** Fake [DisplayRepository] implementation for testing. */
 class FakeDisplayRepository @Inject constructor() : DisplayRepository {
-    private val flow = MutableSharedFlow<Set<Display>>(replay = 1)
+    private val flow = MutableStateFlow<Set<Display>>(emptySet())
     private val pendingDisplayFlow =
         MutableSharedFlow<DisplayRepository.PendingDisplay?>(replay = 1)
-    private val displayAdditionEventFlow = MutableSharedFlow<Display?>(replay = 1)
+    private val displayAdditionEventFlow = MutableSharedFlow<Display?>(replay = 0)
+    private val displayRemovalEventFlow = MutableSharedFlow<Int>(replay = 0)
+
+    suspend fun addDisplay(display: Display) {
+        flow.value += display
+        displayAdditionEventFlow.emit(display)
+    }
+
+    suspend fun removeDisplay(displayId: Int) {
+        flow.value = flow.value.filter { it.displayId != displayId }.toSet()
+        displayRemovalEventFlow.emit(displayId)
+    }
 
     /** Emits [value] as [displayAdditionEvent] flow value. */
     suspend fun emit(value: Display?) = displayAdditionEventFlow.emit(value)
@@ -65,7 +72,7 @@
     /** Emits [value] as [pendingDisplay] flow value. */
     suspend fun emit(value: DisplayRepository.PendingDisplay?) = pendingDisplayFlow.emit(value)
 
-    override val displays: Flow<Set<Display>>
+    override val displays: StateFlow<Set<Display>>
         get() = flow
 
     override val pendingDisplay: Flow<DisplayRepository.PendingDisplay?>
@@ -78,8 +85,11 @@
     override val displayAdditionEvent: Flow<Display?>
         get() = displayAdditionEventFlow
 
+    override val displayRemovalEvent: Flow<Int> = displayRemovalEventFlow
+
     private val _displayChangeEvent = MutableSharedFlow<Int>(replay = 1)
     override val displayChangeEvent: Flow<Int> = _displayChangeEvent
+
     suspend fun emitDisplayChangeEvent(displayId: Int) = _displayChangeEvent.emit(displayId)
 
     fun setDefaultDisplayOff(defaultDisplayOff: Boolean) {
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/display/data/repository/FakeDisplayScopeRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/display/data/repository/FakeDisplayScopeRepository.kt
new file mode 100644
index 0000000..3c25924
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/display/data/repository/FakeDisplayScopeRepository.kt
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.display.data.repository
+
+import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.CoroutineScope
+
+class FakeDisplayScopeRepository(private val dispatcher: CoroutineDispatcher) :
+    DisplayScopeRepository {
+
+    private val perDisplayScopes = mutableMapOf<Int, CoroutineScope>()
+
+    override fun scopeForDisplay(displayId: Int): CoroutineScope {
+        return perDisplayScopes.computeIfAbsent(displayId) { CoroutineScope(dispatcher) }
+    }
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/display/data/repository/FakeDisplayWindowPropertiesRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/display/data/repository/FakeDisplayWindowPropertiesRepository.kt
new file mode 100644
index 0000000..9282f27
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/display/data/repository/FakeDisplayWindowPropertiesRepository.kt
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.display.data.repository
+
+import com.android.systemui.display.shared.model.DisplayWindowProperties
+import com.google.common.collect.HashBasedTable
+import org.mockito.kotlin.mock
+
+class FakeDisplayWindowPropertiesRepository : DisplayWindowPropertiesRepository {
+
+    private val properties = HashBasedTable.create<Int, Int, DisplayWindowProperties>()
+
+    override fun get(displayId: Int, windowType: Int): DisplayWindowProperties {
+        return properties.get(displayId, windowType)
+            ?: DisplayWindowProperties(
+                    displayId = displayId,
+                    windowType = windowType,
+                    context = mock(),
+                    windowManager = mock(),
+                )
+                .also { properties.put(displayId, windowType, it) }
+    }
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/haptics/slider/SliderHapticsViewModelFactoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/haptics/slider/SliderHapticsViewModelFactoryKosmos.kt
new file mode 100644
index 0000000..257d758
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/haptics/slider/SliderHapticsViewModelFactoryKosmos.kt
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.haptics.slider
+
+import androidx.compose.foundation.gestures.Orientation
+import androidx.compose.foundation.interaction.InteractionSource
+import com.android.systemui.haptics.slider.compose.ui.SliderHapticsViewModel
+import com.android.systemui.haptics.vibratorHelper
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.util.time.fakeSystemClock
+
+val Kosmos.sliderHapticsViewModelFactory by
+    Kosmos.Fixture {
+        object : SliderHapticsViewModel.Factory {
+            override fun create(
+                interactionSource: InteractionSource,
+                sliderRange: ClosedFloatingPointRange<Float>,
+                orientation: Orientation,
+                sliderHapticFeedbackConfig: SliderHapticFeedbackConfig,
+                sliderTrackerConfig: SeekableSliderTrackerConfig,
+            ): SliderHapticsViewModel =
+                SliderHapticsViewModel(
+                    interactionSource,
+                    sliderRange,
+                    orientation,
+                    sliderHapticFeedbackConfig,
+                    sliderTrackerConfig,
+                    vibratorHelper,
+                    fakeSystemClock,
+                )
+        }
+    }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardClockRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardClockRepository.kt
index 5e5f8cb..159dd34 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardClockRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardClockRepository.kt
@@ -46,16 +46,27 @@
     private val _previewClock = MutableStateFlow(Mockito.mock(ClockController::class.java))
     override val previewClock: Flow<ClockController>
         get() = _previewClock
+
+    private val _notificationDefaultTop = MutableStateFlow(0F)
+    override val notificationDefaultTop: StateFlow<Float>
+        get() = _notificationDefaultTop
+
     override val clockEventController: ClockEventController
         get() = mock()
+
     override val shouldForceSmallClock: Boolean
         get() = _shouldForceSmallClock
+
     private var _shouldForceSmallClock: Boolean = false
 
     override fun setClockSize(size: ClockSize) {
         _clockSize.value = size
     }
 
+    override fun setNotificationDefaultTop(top: Float) {
+        _notificationDefaultTop.value = top
+    }
+
     fun setSelectedClockSize(size: ClockSizeSetting) {
         _selectedClockSize.value = size
     }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt
index 54a6c0c..e513e8d 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt
@@ -131,6 +131,10 @@
     private val _isEncryptedOrLockdown = MutableStateFlow(true)
     override val isEncryptedOrLockdown: Flow<Boolean> = _isEncryptedOrLockdown
 
+    private val _shortcutAbsoluteTop = MutableStateFlow(0F)
+    override val shortcutAbsoluteTop: StateFlow<Float>
+        get() = _shortcutAbsoluteTop.asStateFlow()
+
     private val _isKeyguardEnabled = MutableStateFlow(true)
     override val isKeyguardEnabled: StateFlow<Boolean> = _isKeyguardEnabled.asStateFlow()
 
@@ -241,7 +245,7 @@
 
     override fun setBiometricUnlockState(
         mode: BiometricUnlockMode,
-        source: BiometricUnlockSource?
+        source: BiometricUnlockSource?,
     ) {
         _biometricUnlockState.tryEmit(BiometricUnlockModel(mode, source))
     }
@@ -294,6 +298,10 @@
         return isShowKeyguardWhenReenabled
     }
 
+    override fun setShortcutAbsoluteTop(top: Float) {
+        _shortcutAbsoluteTop.value = top
+    }
+
     override fun setCanIgnoreAuthAndReturnToGone(canWake: Boolean) {
         _canIgnoreAuthAndReturnToGone.value = canWake
     }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardTransitionRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardTransitionRepository.kt
index 4d0e603..70b4f79 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardTransitionRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardTransitionRepository.kt
@@ -48,13 +48,35 @@
  * with OFF -> GONE. Construct with initInLockscreen = false if your test requires this behavior.
  */
 @SysUISingleton
-class FakeKeyguardTransitionRepository(private val initInLockscreen: Boolean = true) :
-    KeyguardTransitionRepository {
+class FakeKeyguardTransitionRepository(
+    private val initInLockscreen: Boolean = true,
+
+    /**
+     * If true, calls to [startTransition] will automatically emit STARTED, RUNNING, and FINISHED
+     * transition steps from/to the given states.
+     *
+     * [startTransition] is what the From*TransitionInteractors call, so this more closely emulates
+     * the behavior of the real KeyguardTransitionRepository, and reduces the work needed to
+     * manually set up the repository state in each test. For example, setting dreaming=true will
+     * automatically cause FromDreamingTransitionInteractor to call startTransition(DREAMING), and
+     * then we'll send STARTED/RUNNING/FINISHED DREAMING TransitionSteps.
+     *
+     * If your test needs to make assertions at specific points between STARTED/FINISHED, or if it's
+     * difficult to set up all of the conditions to make the transition interactors actually call
+     * startTransition, then construct a FakeKeyguardTransitionRepository with this value false.
+     */
+    private val sendTransitionStepsOnStartTransition: Boolean = true,
+    private val testScope: TestScope,
+) : KeyguardTransitionRepository {
+
     private val _transitions =
         MutableSharedFlow<TransitionStep>(replay = 3, onBufferOverflow = BufferOverflow.DROP_OLDEST)
     override val transitions: SharedFlow<TransitionStep> = _transitions
 
-    @Inject constructor() : this(initInLockscreen = true)
+    @Inject
+    constructor(
+        testScope: TestScope
+    ) : this(initInLockscreen = true, sendTransitionStepsOnStartTransition = true, testScope)
 
     private val _currentTransitionInfo: MutableStateFlow<TransitionInfo> =
         MutableStateFlow(
@@ -287,6 +309,11 @@
 
     override suspend fun startTransition(info: TransitionInfo): UUID? {
         _currentTransitionInfo.value = info
+
+        if (sendTransitionStepsOnStartTransition) {
+            sendTransitionSteps(from = info.from, to = info.to, testScope = testScope)
+        }
+
         return if (info.animator == null) UUID.randomUUID() else null
     }
 
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/KeyguardBlueprintRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/KeyguardBlueprintRepositoryKosmos.kt
index 12d7c49..49a8c18 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/KeyguardBlueprintRepositoryKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/KeyguardBlueprintRepositoryKosmos.kt
@@ -29,9 +29,10 @@
 import com.android.systemui.keyguard.ui.viewmodel.keyguardRootViewModel
 import com.android.systemui.keyguard.ui.viewmodel.keyguardSmartspaceViewModel
 import com.android.systemui.kosmos.Kosmos
-import com.android.systemui.util.mockito.mock
+import com.android.systemui.shade.LargeScreenHeaderHelper
 import java.util.Optional
 import org.mockito.Mockito.spy
+import org.mockito.kotlin.mock
 
 val Kosmos.keyguardClockSection: ClockSection by
     Kosmos.Fixture {
@@ -43,6 +44,7 @@
             blueprintInteractor = { keyguardBlueprintInteractor },
             rootViewModel = keyguardRootViewModel,
             aodBurnInViewModel = aodBurnInViewModel,
+            largeScreenHeaderHelperLazy = { mock<LargeScreenHeaderHelper>() },
         )
     }
 
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepositoryKosmos.kt
index 3e69e87..e9eea83 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepositoryKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepositoryKosmos.kt
@@ -18,9 +18,14 @@
 
 import com.android.systemui.kosmos.Kosmos
 import com.android.systemui.kosmos.testDispatcher
+import com.android.systemui.kosmos.testScope
+import org.mockito.Mockito.spy
 
 var Kosmos.keyguardTransitionRepository: KeyguardTransitionRepository by
     Kosmos.Fixture { fakeKeyguardTransitionRepository }
-var Kosmos.fakeKeyguardTransitionRepository by Kosmos.Fixture { FakeKeyguardTransitionRepository() }
+var Kosmos.fakeKeyguardTransitionRepository by
+    Kosmos.Fixture { FakeKeyguardTransitionRepository(testScope = testScope) }
+var Kosmos.fakeKeyguardTransitionRepositorySpy: FakeKeyguardTransitionRepository by
+    Kosmos.Fixture { spy(fakeKeyguardTransitionRepository) }
 var Kosmos.realKeyguardTransitionRepository: KeyguardTransitionRepository by
     Kosmos.Fixture { KeyguardTransitionRepositoryImpl(testDispatcher) }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractorKosmos.kt
index ef789d1..93a59eb 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractorKosmos.kt
@@ -17,7 +17,7 @@
 package com.android.systemui.keyguard.domain.interactor
 
 import com.android.systemui.deviceentry.data.repository.deviceEntryRepository
-import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
+import com.android.systemui.keyguard.data.repository.keyguardTransitionRepository
 import com.android.systemui.kosmos.Kosmos
 import com.android.systemui.kosmos.applicationCoroutineScope
 import com.android.systemui.kosmos.testDispatcher
@@ -27,7 +27,7 @@
 val Kosmos.fromAodTransitionInteractor by
     Kosmos.Fixture {
         FromAodTransitionInteractor(
-            transitionRepository = fakeKeyguardTransitionRepository,
+            transitionRepository = keyguardTransitionRepository,
             transitionInteractor = keyguardTransitionInteractor,
             internalTransitionInteractor = internalKeyguardTransitionInteractor,
             scope = applicationCoroutineScope,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromGoneTransitionInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromGoneTransitionInteractorKosmos.kt
index c694114..700d7e9 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromGoneTransitionInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromGoneTransitionInteractorKosmos.kt
@@ -18,8 +18,8 @@
 
 import com.android.systemui.communal.domain.interactor.communalSceneInteractor
 import com.android.systemui.keyguard.data.repository.biometricSettingsRepository
-import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
 import com.android.systemui.keyguard.data.repository.keyguardRepository
+import com.android.systemui.keyguard.data.repository.keyguardTransitionRepository
 import com.android.systemui.kosmos.Kosmos
 import com.android.systemui.kosmos.applicationCoroutineScope
 import com.android.systemui.kosmos.testDispatcher
@@ -29,7 +29,7 @@
 val Kosmos.fromGoneTransitionInteractor by
     Kosmos.Fixture {
         FromGoneTransitionInteractor(
-            transitionRepository = fakeKeyguardTransitionRepository,
+            transitionRepository = keyguardTransitionRepository,
             transitionInteractor = keyguardTransitionInteractor,
             internalTransitionInteractor = internalKeyguardTransitionInteractor,
             scope = applicationCoroutineScope,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardClockInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardClockInteractorKosmos.kt
index d52883e..bdb9abb 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardClockInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardClockInteractorKosmos.kt
@@ -27,13 +27,13 @@
 val Kosmos.keyguardClockInteractor by
     Kosmos.Fixture {
         KeyguardClockInteractor(
-            keyguardClockRepository = keyguardClockRepository,
-            applicationScope = applicationCoroutineScope,
             mediaCarouselInteractor = mediaCarouselInteractor,
             activeNotificationsInteractor = activeNotificationsInteractor,
             shadeInteractor = shadeInteractor,
             keyguardInteractor = keyguardInteractor,
             keyguardTransitionInteractor = keyguardTransitionInteractor,
             headsUpNotificationInteractor = headsUpNotificationInteractor,
+            applicationScope = applicationCoroutineScope,
+            keyguardClockRepository = keyguardClockRepository,
         )
     }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryBackgroundViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryBackgroundViewModelKosmos.kt
new file mode 100644
index 0000000..fc4f3a5
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryBackgroundViewModelKosmos.kt
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.keyguard.ui.viewmodel
+
+import android.content.applicationContext
+import com.android.systemui.common.ui.domain.interactor.configurationInteractor
+import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.Kosmos.Fixture
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+
+@ExperimentalCoroutinesApi
+val Kosmos.deviceEntryBackgroundViewModel by Fixture {
+    DeviceEntryBackgroundViewModel(
+        context = applicationContext,
+        deviceEntryIconViewModel = deviceEntryIconViewModel,
+        configurationInteractor = configurationInteractor,
+        keyguardTransitionInteractor = keyguardTransitionInteractor,
+        alternateBouncerToAodTransitionViewModel = alternateBouncerToAodTransitionViewModel,
+        alternateBouncerToDozingTransitionViewModel = alternateBouncerToDozingTransitionViewModel,
+        aodToLockscreenTransitionViewModel = aodToLockscreenTransitionViewModel,
+        dozingToLockscreenTransitionViewModel = dozingToLockscreenTransitionViewModel,
+        dreamingToAodTransitionViewModel = dreamingToAodTransitionViewModel,
+        dreamingToLockscreenTransitionViewModel = dreamingToLockscreenTransitionViewModel,
+        goneToAodTransitionViewModel = goneToAodTransitionViewModel,
+        goneToDozingTransitionViewModel = goneToDozingTransitionViewModel,
+        goneToLockscreenTransitionViewModel = goneToLockscreenTransitionViewModel,
+        lockscreenToAodTransitionViewModel = lockscreenToAodTransitionViewModel,
+        occludedToAodTransitionViewModel = occludedToAodTransitionViewModel,
+        occludedToDozingTransitionViewModel = occludedToDozingTransitionViewModel,
+        occludedToLockscreenTransitionViewModel = occludedToLockscreenTransitionViewModel,
+        offToLockscreenTransitionViewModel = offToLockscreenTransitionViewModel,
+        primaryBouncerToAodTransitionViewModel = primaryBouncerToAodTransitionViewModel,
+        primaryBouncerToDozingTransitionViewModel = primaryBouncerToDozingTransitionViewModel,
+        primaryBouncerToLockscreenTransitionViewModel =
+            primaryBouncerToLockscreenTransitionViewModel,
+        lockscreenToDozingTransitionViewModel = lockscreenToDozingTransitionViewModel,
+    )
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/KosmosJavaAdapter.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/KosmosJavaAdapter.kt
index f97f303..522c387 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/KosmosJavaAdapter.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/KosmosJavaAdapter.kt
@@ -23,6 +23,7 @@
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.bouncer.data.repository.bouncerRepository
 import com.android.systemui.bouncer.data.repository.fakeKeyguardBouncerRepository
+import com.android.systemui.bouncer.domain.interactor.alternateBouncerInteractor
 import com.android.systemui.bouncer.domain.interactor.simBouncerInteractor
 import com.android.systemui.classifier.falsingCollector
 import com.android.systemui.common.ui.data.repository.fakeConfigurationRepository
@@ -152,6 +153,7 @@
     val wifiInteractor by lazy { kosmos.wifiInteractor }
     val fakeWifiRepository by lazy { kosmos.fakeWifiRepository }
     val volumeDialogInteractor by lazy { kosmos.volumeDialogInteractor }
+    val alternateBouncerInteractor by lazy { kosmos.alternateBouncerInteractor }
 
     val ongoingActivityChipsViewModel by lazy { kosmos.ongoingActivityChipsViewModel }
     val scrimController by lazy { kosmos.scrimController }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/plugins/FakeVolumeDialogController.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/plugins/FakeVolumeDialogController.kt
index e4a2a87..b45120e 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/plugins/FakeVolumeDialogController.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/plugins/FakeVolumeDialogController.kt
@@ -37,11 +37,11 @@
     var hasUserActivity: Boolean = false
         private set
 
-    private var hasVibrator: Boolean = true
-
-    private val state = VolumeDialogController.State()
     private val callbacks = CopyOnWriteArraySet<VolumeDialogController.Callbacks>()
 
+    private var hasVibrator: Boolean = true
+    private var state = VolumeDialogController.State()
+
     override fun setActiveStream(stream: Int) {
         // ensure streamState existence for the active stream
         state.states.getOrElse(stream) {
@@ -110,6 +110,11 @@
         hasUserActivity = false
     }
 
+    fun updateState(update: VolumeDialogController.State.() -> Unit) {
+        state = state.copy().apply(update)
+        getState()
+    }
+
     override fun getState() {
         callbacks.sendEvent { it.onStateChanged(state) }
     }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/plugins/statusbar/StatusBarStateControllerKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/plugins/statusbar/StatusBarStateControllerKosmos.kt
index cfc31c7..10b073e 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/plugins/statusbar/StatusBarStateControllerKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/plugins/statusbar/StatusBarStateControllerKosmos.kt
@@ -17,6 +17,7 @@
 package com.android.systemui.plugins.statusbar
 
 import com.android.internal.logging.uiEventLogger
+import com.android.systemui.bouncer.domain.interactor.alternateBouncerInteractor
 import com.android.systemui.deviceentry.domain.interactor.deviceUnlockedInteractor
 import com.android.systemui.jank.interactionJankMonitor
 import com.android.systemui.keyguard.domain.interactor.keyguardClockInteractor
@@ -45,5 +46,6 @@
             { sceneContainerOcclusionInteractor },
             { keyguardClockInteractor },
             { sceneBackInteractor },
+            { alternateBouncerInteractor },
         )
     }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/data/repository/FixedColumnsRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/data/repository/QSColumnsRepositoryKosmos.kt
similarity index 68%
copy from packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/data/repository/FixedColumnsRepositoryKosmos.kt
copy to packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/data/repository/QSColumnsRepositoryKosmos.kt
index 2f5daaa..0ca025f 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/data/repository/FixedColumnsRepositoryKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/data/repository/QSColumnsRepositoryKosmos.kt
@@ -16,6 +16,12 @@
 
 package com.android.systemui.qs.panels.data.repository
 
+import android.content.res.mainResources
+import com.android.systemui.common.ui.data.repository.configurationRepository
 import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.applicationCoroutineScope
 
-val Kosmos.fixedColumnsRepository by Kosmos.Fixture { FixedColumnsRepository() }
+val Kosmos.qsColumnsRepository by
+    Kosmos.Fixture {
+        QSColumnsRepository(applicationCoroutineScope, mainResources, configurationRepository)
+    }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/InfiniteGridLayoutKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/InfiniteGridLayoutKosmos.kt
index 546129f..b4317ad 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/InfiniteGridLayoutKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/InfiniteGridLayoutKosmos.kt
@@ -18,11 +18,11 @@
 
 import com.android.systemui.kosmos.Kosmos
 import com.android.systemui.qs.panels.ui.compose.infinitegrid.InfiniteGridLayout
-import com.android.systemui.qs.panels.ui.viewmodel.fixedColumnsSizeViewModel
 import com.android.systemui.qs.panels.ui.viewmodel.iconTilesViewModel
+import com.android.systemui.qs.panels.ui.viewmodel.qsColumnsViewModel
 import com.android.systemui.qs.panels.ui.viewmodel.tileSquishinessViewModel
 
 val Kosmos.infiniteGridLayout by
     Kosmos.Fixture {
-        InfiniteGridLayout(iconTilesViewModel, fixedColumnsSizeViewModel, tileSquishinessViewModel)
+        InfiniteGridLayout(iconTilesViewModel, qsColumnsViewModel, tileSquishinessViewModel)
     }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/FixedColumnsSizeInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/QSColumnsInteractorKosmos.kt
similarity index 78%
rename from packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/FixedColumnsSizeInteractorKosmos.kt
rename to packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/QSColumnsInteractorKosmos.kt
index f4d281d..02ed264 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/FixedColumnsSizeInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/QSColumnsInteractorKosmos.kt
@@ -17,7 +17,6 @@
 package com.android.systemui.qs.panels.domain.interactor
 
 import com.android.systemui.kosmos.Kosmos
-import com.android.systemui.qs.panels.data.repository.fixedColumnsRepository
+import com.android.systemui.qs.panels.data.repository.qsColumnsRepository
 
-val Kosmos.fixedColumnsSizeInteractor by
-    Kosmos.Fixture { FixedColumnsSizeInteractor(fixedColumnsRepository) }
+val Kosmos.qsColumnsInteractor by Kosmos.Fixture { QSColumnsInteractor(qsColumnsRepository) }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/ui/viewmodel/PaginatedGridViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/ui/viewmodel/PaginatedGridViewModelKosmos.kt
index 85e9265..10d8e1e 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/ui/viewmodel/PaginatedGridViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/ui/viewmodel/PaginatedGridViewModelKosmos.kt
@@ -24,7 +24,7 @@
     Kosmos.Fixture {
         PaginatedGridViewModel(
             iconTilesViewModel,
-            fixedColumnsSizeViewModel,
+            qsColumnsViewModel,
             iconLabelVisibilityViewModel,
             paginatedGridInteractor,
             applicationCoroutineScope,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/ui/viewmodel/FixedColumnsSizeViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/ui/viewmodel/QSColumnsViewModelKosmos.kt
similarity index 77%
rename from packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/ui/viewmodel/FixedColumnsSizeViewModelKosmos.kt
rename to packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/ui/viewmodel/QSColumnsViewModelKosmos.kt
index feadc91..16b2f54 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/ui/viewmodel/FixedColumnsSizeViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/ui/viewmodel/QSColumnsViewModelKosmos.kt
@@ -17,7 +17,6 @@
 package com.android.systemui.qs.panels.ui.viewmodel
 
 import com.android.systemui.kosmos.Kosmos
-import com.android.systemui.qs.panels.domain.interactor.fixedColumnsSizeInteractor
+import com.android.systemui.qs.panels.domain.interactor.qsColumnsInteractor
 
-val Kosmos.fixedColumnsSizeViewModel by
-    Kosmos.Fixture { FixedColumnsSizeViewModelImpl(fixedColumnsSizeInteractor) }
+val Kosmos.qsColumnsViewModel by Kosmos.Fixture { QSColumnsSizeViewModelImpl(qsColumnsInteractor) }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/ui/viewmodel/QuickQuickSettingsViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/ui/viewmodel/QuickQuickSettingsViewModelKosmos.kt
index babbd50..67d9e0e 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/ui/viewmodel/QuickQuickSettingsViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/ui/viewmodel/QuickQuickSettingsViewModelKosmos.kt
@@ -25,7 +25,7 @@
     Kosmos.Fixture {
         QuickQuickSettingsViewModel(
             currentTilesInteractor,
-            fixedColumnsSizeViewModel,
+            qsColumnsViewModel,
             quickQuickSettingsRowInteractor,
             tileSquishinessViewModel,
             iconTilesViewModel,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelKosmos.kt
index 237f7e4..a25a3c0 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelKosmos.kt
@@ -49,6 +49,7 @@
 import com.android.systemui.kosmos.Kosmos.Fixture
 import com.android.systemui.kosmos.applicationCoroutineScope
 import com.android.systemui.shade.domain.interactor.shadeInteractor
+import com.android.systemui.statusbar.notification.stack.domain.interactor.headsUpNotificationInteractor
 import com.android.systemui.statusbar.notification.stack.domain.interactor.notificationStackAppearanceInteractor
 import com.android.systemui.statusbar.notification.stack.domain.interactor.sharedNotificationContainerInteractor
 import com.android.systemui.unfold.domain.interactor.unfoldTransitionInteractor
@@ -92,6 +93,7 @@
             primaryBouncerToLockscreenTransitionViewModel,
         aodBurnInViewModel = aodBurnInViewModel,
         communalSceneInteractor = communalSceneInteractor,
+        headsUpNotificationInteractor = { headsUpNotificationInteractor },
         unfoldTransitionInteractor = unfoldTransitionInteractor,
     )
 }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/domain/interactor/ZenModeInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/domain/interactor/ZenModeInteractorKosmos.kt
index 99cd830..68d08e2 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/domain/interactor/ZenModeInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/domain/interactor/ZenModeInteractorKosmos.kt
@@ -16,7 +16,7 @@
 
 package com.android.systemui.statusbar.policy.domain.interactor
 
-import android.content.testableContext
+import android.content.applicationContext
 import com.android.settingslib.notification.modes.zenIconLoader
 import com.android.systemui.kosmos.Kosmos
 import com.android.systemui.kosmos.Kosmos.Fixture
@@ -28,7 +28,7 @@
 
 val Kosmos.zenModeInteractor by Fixture {
     ZenModeInteractor(
-        context = testableContext,
+        context = applicationContext,
         zenModeRepository = zenModeRepository,
         notificationSettingsRepository = notificationSettingsRepository,
         bgDispatcher = testDispatcher,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/FixedColumnsSizeInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/window/FakeStatusBarWindowControllerFactory.kt
similarity index 61%
copy from packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/FixedColumnsSizeInteractorKosmos.kt
copy to packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/window/FakeStatusBarWindowControllerFactory.kt
index f4d281d..10f328b 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/FixedColumnsSizeInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/window/FakeStatusBarWindowControllerFactory.kt
@@ -14,10 +14,14 @@
  * limitations under the License.
  */
 
-package com.android.systemui.qs.panels.domain.interactor
+package com.android.systemui.statusbar.window
 
-import com.android.systemui.kosmos.Kosmos
-import com.android.systemui.qs.panels.data.repository.fixedColumnsRepository
+import android.content.Context
+import com.android.app.viewcapture.ViewCaptureAwareWindowManager
 
-val Kosmos.fixedColumnsSizeInteractor by
-    Kosmos.Fixture { FixedColumnsSizeInteractor(fixedColumnsRepository) }
+class FakeStatusBarWindowControllerFactory : StatusBarWindowController.Factory {
+    override fun create(
+        context: Context,
+        viewCaptureAwareWindowManager: ViewCaptureAwareWindowManager,
+    ) = FakeStatusBarWindowController()
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/window/FakeStatusBarWindowControllerStore.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/window/FakeStatusBarWindowControllerStore.kt
new file mode 100644
index 0000000..d19e322
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/window/FakeStatusBarWindowControllerStore.kt
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.window
+
+import android.view.Display
+
+class FakeStatusBarWindowControllerStore : StatusBarWindowControllerStore {
+
+    private val perDisplayControllers = mutableMapOf<Int, FakeStatusBarWindowController>()
+
+    override val defaultDisplay
+        get() = forDisplay(Display.DEFAULT_DISPLAY)
+
+    override fun forDisplay(displayId: Int): StatusBarWindowController {
+        return perDisplayControllers.computeIfAbsent(displayId) { FakeStatusBarWindowController() }
+    }
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/window/StatusBarWindowControllerKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/window/StatusBarWindowControllerKosmos.kt
index c198b35..6c6f243 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/window/StatusBarWindowControllerKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/window/StatusBarWindowControllerKosmos.kt
@@ -21,3 +21,15 @@
 val Kosmos.fakeStatusBarWindowController by Kosmos.Fixture { FakeStatusBarWindowController() }
 
 var Kosmos.statusBarWindowController by Kosmos.Fixture { fakeStatusBarWindowController }
+
+val Kosmos.fakeStatusBarWindowControllerStore by
+    Kosmos.Fixture { FakeStatusBarWindowControllerStore() }
+
+var Kosmos.statusBarWindowControllerStore: StatusBarWindowControllerStore by
+    Kosmos.Fixture { fakeStatusBarWindowControllerStore }
+
+val Kosmos.fakeStatusBarWindowControllerFactory by
+    Kosmos.Fixture { FakeStatusBarWindowControllerFactory() }
+
+var Kosmos.statusBarWindowControllerFactory: StatusBarWindowController.Factory by
+    Kosmos.Fixture { fakeStatusBarWindowControllerFactory }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/data/repository/FakeAudioSharingRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/data/repository/FakeAudioSharingRepository.kt
index a4719e5..5da6ee9 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/data/repository/FakeAudioSharingRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/data/repository/FakeAudioSharingRepository.kt
@@ -22,6 +22,7 @@
 import kotlinx.coroutines.flow.StateFlow
 
 class FakeAudioSharingRepository : AudioSharingRepository {
+    private var mutableAvailable: Boolean = false
     private val mutableInAudioSharing: MutableStateFlow<Boolean> = MutableStateFlow(false)
     private val mutablePrimaryGroupId: MutableStateFlow<Int> =
         MutableStateFlow(TEST_GROUP_ID_INVALID)
@@ -34,8 +35,14 @@
     override val secondaryGroupId: StateFlow<Int> = mutableSecondaryGroupId
     override val volumeMap: StateFlow<GroupIdToVolumes> = mutableVolumeMap
 
+    override suspend fun audioSharingAvailable(): Boolean = mutableAvailable
+
     override suspend fun setSecondaryVolume(volume: Int) {}
 
+    fun setAudioSharingAvailable(available: Boolean) {
+        mutableAvailable = available
+    }
+
     fun setInAudioSharing(state: Boolean) {
         mutableInAudioSharing.value = state
     }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/data/repository/FixedColumnsRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/dialog/data/repository/VolumeDialogStateRepositoryKosmos.kt
similarity index 78%
copy from packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/data/repository/FixedColumnsRepositoryKosmos.kt
copy to packages/SystemUI/tests/utils/src/com/android/systemui/volume/dialog/data/repository/VolumeDialogStateRepositoryKosmos.kt
index 2f5daaa..7681111 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/data/repository/FixedColumnsRepositoryKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/dialog/data/repository/VolumeDialogStateRepositoryKosmos.kt
@@ -14,8 +14,9 @@
  * limitations under the License.
  */
 
-package com.android.systemui.qs.panels.data.repository
+package com.android.systemui.volume.dialog.data.repository
 
 import com.android.systemui.kosmos.Kosmos
 
-val Kosmos.fixedColumnsRepository by Kosmos.Fixture { FixedColumnsRepository() }
+val Kosmos.volumeDialogStateRepository: VolumeDialogStateRepository by
+    Kosmos.Fixture { VolumeDialogStateRepository() }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/data/repository/FixedColumnsRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/dialog/data/repository/VolumeDialogVisibilityRepositoryKosmos.kt
similarity index 73%
copy from packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/data/repository/FixedColumnsRepositoryKosmos.kt
copy to packages/SystemUI/tests/utils/src/com/android/systemui/volume/dialog/data/repository/VolumeDialogVisibilityRepositoryKosmos.kt
index 2f5daaa..291dfc0 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/data/repository/FixedColumnsRepositoryKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/dialog/data/repository/VolumeDialogVisibilityRepositoryKosmos.kt
@@ -14,8 +14,9 @@
  * limitations under the License.
  */
 
-package com.android.systemui.qs.panels.data.repository
+package com.android.systemui.volume.dialog.data.repository
 
 import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.volume.dialog.data.VolumeDialogVisibilityRepository
 
-val Kosmos.fixedColumnsRepository by Kosmos.Fixture { FixedColumnsRepository() }
+val Kosmos.volumeDialogVisibilityRepository by Kosmos.Fixture { VolumeDialogVisibilityRepository() }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/dialog/domain/interactor/VolumeDialogStateInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/dialog/domain/interactor/VolumeDialogStateInteractorKosmos.kt
new file mode 100644
index 0000000..8944861
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/dialog/domain/interactor/VolumeDialogStateInteractorKosmos.kt
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.volume.dialog.domain.interactor
+
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.applicationCoroutineScope
+import com.android.systemui.plugins.volumeDialogController
+import com.android.systemui.volume.dialog.data.repository.volumeDialogStateRepository
+
+val Kosmos.volumeDialogStateInteractor: VolumeDialogStateInteractor by
+    Kosmos.Fixture {
+        VolumeDialogStateInteractor(
+            volumeDialogCallbacksInteractor,
+            volumeDialogController,
+            volumeDialogStateRepository,
+            applicationCoroutineScope,
+        )
+    }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/dialog/domain/interactor/VolumeDialogVisibilityInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/dialog/domain/interactor/VolumeDialogVisibilityInteractorKosmos.kt
index e73539e..7376c7f 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/dialog/domain/interactor/VolumeDialogVisibilityInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/dialog/domain/interactor/VolumeDialogVisibilityInteractorKosmos.kt
@@ -18,8 +18,15 @@
 
 import com.android.systemui.kosmos.Kosmos
 import com.android.systemui.kosmos.applicationCoroutineScope
+import com.android.systemui.volume.dialog.data.repository.volumeDialogVisibilityRepository
+import com.android.systemui.volume.dialog.utils.volumeTracer
 
 val Kosmos.volumeDialogVisibilityInteractor by
     Kosmos.Fixture {
-        VolumeDialogVisibilityInteractor(applicationCoroutineScope, volumeDialogCallbacksInteractor)
+        VolumeDialogVisibilityInteractor(
+            applicationCoroutineScope,
+            volumeDialogCallbacksInteractor,
+            volumeTracer,
+            volumeDialogVisibilityRepository,
+        )
     }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/dialog/sliders/domain/interactor/VolumeDialogSlidersInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/dialog/sliders/domain/interactor/VolumeDialogSlidersInteractorKosmos.kt
new file mode 100644
index 0000000..0f573d9
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/dialog/sliders/domain/interactor/VolumeDialogSlidersInteractorKosmos.kt
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.volume.dialog.sliders.domain.interactor
+
+import android.content.packageManager
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.applicationCoroutineScope
+import com.android.systemui.volume.dialog.domain.interactor.volumeDialogStateInteractor
+
+val Kosmos.volumeDialogSlidersInteractor: VolumeDialogSlidersInteractor by
+    Kosmos.Fixture {
+        VolumeDialogSlidersInteractor(
+            volumeDialogStateInteractor,
+            packageManager,
+            applicationCoroutineScope,
+        )
+    }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/FixedColumnsSizeInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/dialog/utils/FakeVolumeTracer.kt
similarity index 65%
copy from packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/FixedColumnsSizeInteractorKosmos.kt
copy to packages/SystemUI/tests/utils/src/com/android/systemui/volume/dialog/utils/FakeVolumeTracer.kt
index f4d281d..a5074eb 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/FixedColumnsSizeInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/dialog/utils/FakeVolumeTracer.kt
@@ -14,10 +14,13 @@
  * limitations under the License.
  */
 
-package com.android.systemui.qs.panels.domain.interactor
+package com.android.systemui.volume.dialog.utils
 
-import com.android.systemui.kosmos.Kosmos
-import com.android.systemui.qs.panels.data.repository.fixedColumnsRepository
+import com.android.systemui.volume.dialog.shared.model.VolumeDialogVisibilityModel
 
-val Kosmos.fixedColumnsSizeInteractor by
-    Kosmos.Fixture { FixedColumnsSizeInteractor(fixedColumnsRepository) }
+class FakeVolumeTracer : VolumeTracer {
+
+    override fun traceVisibilityStart(model: VolumeDialogVisibilityModel) {}
+
+    override fun traceVisibilityEnd(model: VolumeDialogVisibilityModel) {}
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/data/repository/FixedColumnsRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/dialog/utils/VolumeTracerKosmos.kt
similarity index 75%
copy from packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/data/repository/FixedColumnsRepositoryKosmos.kt
copy to packages/SystemUI/tests/utils/src/com/android/systemui/volume/dialog/utils/VolumeTracerKosmos.kt
index 2f5daaa..1382563 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/data/repository/FixedColumnsRepositoryKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/dialog/utils/VolumeTracerKosmos.kt
@@ -14,8 +14,9 @@
  * limitations under the License.
  */
 
-package com.android.systemui.qs.panels.data.repository
+package com.android.systemui.volume.dialog.utils
 
 import com.android.systemui.kosmos.Kosmos
 
-val Kosmos.fixedColumnsRepository by Kosmos.Fixture { FixedColumnsRepository() }
+val Kosmos.fakeVolumeTracer: FakeVolumeTracer by Kosmos.Fixture { FakeVolumeTracer() }
+var Kosmos.volumeTracer: VolumeTracer by Kosmos.Fixture { fakeVolumeTracer }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/MediaOutputComponentInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/MediaOutputComponentInteractorKosmos.kt
index 63a1325..db66c3e 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/MediaOutputComponentInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/MediaOutputComponentInteractorKosmos.kt
@@ -16,6 +16,7 @@
 
 package com.android.systemui.volume.panel.component.mediaoutput.domain.interactor
 
+import android.content.mockedContext
 import com.android.systemui.kosmos.Kosmos
 import com.android.systemui.kosmos.testScope
 import com.android.systemui.volume.domain.interactor.audioModeInteractor
@@ -27,6 +28,7 @@
 val Kosmos.mediaOutputComponentInteractor by
     Kosmos.Fixture {
         MediaOutputComponentInteractor(
+            mockedContext,
             testScope.backgroundScope,
             mediaDeviceSessionInteractor,
             audioOutputInteractor,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/AudioStreamSliderViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/AudioStreamSliderViewModelKosmos.kt
index e6b52f0..55f0a28 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/AudioStreamSliderViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/AudioStreamSliderViewModelKosmos.kt
@@ -19,6 +19,7 @@
 import android.content.applicationContext
 import com.android.internal.logging.uiEventLogger
 import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.statusbar.policy.domain.interactor.zenModeInteractor
 import com.android.systemui.volume.domain.interactor.audioVolumeInteractor
 import com.android.systemui.volume.shared.volumePanelLogger
 import kotlinx.coroutines.CoroutineScope
@@ -36,6 +37,7 @@
                     coroutineScope,
                     applicationContext,
                     audioVolumeInteractor,
+                    zenModeInteractor,
                     uiEventLogger,
                     volumePanelLogger,
                 )
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/wallpapers/data/repository/WallpaperRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/wallpapers/data/repository/WallpaperRepositoryKosmos.kt
new file mode 100644
index 0000000..1d8c891
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/wallpapers/data/repository/WallpaperRepositoryKosmos.kt
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.wallpapers.data.repository
+
+import android.content.applicationContext
+import com.android.app.wallpaperManager
+import com.android.systemui.broadcast.broadcastDispatcher
+import com.android.systemui.keyguard.data.repository.keyguardClockRepository
+import com.android.systemui.keyguard.data.repository.keyguardRepository
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.Kosmos.Fixture
+import com.android.systemui.kosmos.testDispatcher
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.user.data.repository.userRepository
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+
+@OptIn(ExperimentalCoroutinesApi::class)
+val Kosmos.wallpaperRepository by Fixture {
+    WallpaperRepositoryImpl(
+        context = applicationContext,
+        scope = testScope,
+        bgDispatcher = testDispatcher,
+        broadcastDispatcher = broadcastDispatcher,
+        userRepository = userRepository,
+        wallpaperManager = wallpaperManager,
+        keyguardClockRepository = keyguardClockRepository,
+        keyguardRepository = keyguardRepository,
+    )
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/FixedColumnsSizeInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/wallpapers/domain/interactor/WallpaperInteractorKosmos.kt
similarity index 72%
copy from packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/FixedColumnsSizeInteractorKosmos.kt
copy to packages/SystemUI/tests/utils/src/com/android/systemui/wallpapers/domain/interactor/WallpaperInteractorKosmos.kt
index f4d281d..5278351 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/FixedColumnsSizeInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/wallpapers/domain/interactor/WallpaperInteractorKosmos.kt
@@ -14,10 +14,10 @@
  * limitations under the License.
  */
 
-package com.android.systemui.qs.panels.domain.interactor
+package com.android.systemui.wallpapers.domain.interactor
 
 import com.android.systemui.kosmos.Kosmos
-import com.android.systemui.qs.panels.data.repository.fixedColumnsRepository
+import com.android.systemui.wallpapers.data.repository.wallpaperRepository
 
-val Kosmos.fixedColumnsSizeInteractor by
-    Kosmos.Fixture { FixedColumnsSizeInteractor(fixedColumnsRepository) }
+val Kosmos.wallpaperInteractor by
+    Kosmos.Fixture { WallpaperInteractor(wallpaperRepository = wallpaperRepository) }
diff --git a/ravenwood/Android.bp b/ravenwood/Android.bp
index 11b66fc..8896d77 100644
--- a/ravenwood/Android.bp
+++ b/ravenwood/Android.bp
@@ -12,11 +12,19 @@
 }
 
 filegroup {
+    name: "ravenwood-common-policies",
+    srcs: [
+        "texts/ravenwood-common-policies.txt",
+    ],
+    visibility: ["//visibility:private"],
+}
+
+filegroup {
     name: "ravenwood-services-policies",
     srcs: [
         "texts/ravenwood-services-policies.txt",
     ],
-    visibility: ["//visibility:public"],
+    visibility: ["//visibility:private"],
 }
 
 filegroup {
@@ -24,7 +32,7 @@
     srcs: [
         "texts/ravenwood-framework-policies.txt",
     ],
-    visibility: ["//visibility:public"],
+    visibility: ["//visibility:private"],
 }
 
 filegroup {
@@ -32,7 +40,7 @@
     srcs: [
         "texts/ravenwood-standard-options.txt",
     ],
-    visibility: ["//visibility:public"],
+    visibility: ["//visibility:private"],
 }
 
 filegroup {
@@ -40,7 +48,7 @@
     srcs: [
         "texts/ravenwood-annotation-allowed-classes.txt",
     ],
-    visibility: ["//visibility:public"],
+    visibility: ["//visibility:private"],
 }
 
 // This and the next module contain the same classes with different implementations.
@@ -154,6 +162,8 @@
         "framework-annotations-lib",
         "ravenwood-helper-framework-runtime",
         "ravenwood-helper-libcore-runtime",
+        "hoststubgen-helper-runtime.ravenwood",
+        "mockito-ravenwood-prebuilt",
     ],
     visibility: ["//frameworks/base"],
     jarjar_rules: ":ravenwood-services-jarjar-rules",
@@ -335,6 +345,30 @@
     ],
 }
 
+// JARs in "ravenwood-runtime" are set to the classpath, sorted alphabetically.
+// Rename some of the dependencies to make sure they're included in the intended order.
+
+java_library {
+    name: "100-framework-minus-apex.ravenwood",
+    installable: false,
+    static_libs: ["framework-minus-apex.ravenwood"],
+    visibility: ["//visibility:private"],
+}
+
+java_library {
+    name: "200-kxml2-android",
+    installable: false,
+    static_libs: ["kxml2-android"],
+    visibility: ["//visibility:private"],
+}
+
+java_library {
+    name: "z00-all-updatable-modules-system-stubs",
+    installable: false,
+    static_libs: ["all-updatable-modules-system-stubs-for-host"],
+    visibility: ["//visibility:private"],
+}
+
 android_ravenwood_libgroup {
     name: "ravenwood-runtime",
     data: [
@@ -393,3 +427,7 @@
         "inline-mockito-ravenwood-prebuilt",
     ],
 }
+
+build = [
+    "Framework.bp",
+]
diff --git a/ravenwood/Framework.bp b/ravenwood/Framework.bp
new file mode 100644
index 0000000..5cb1479
--- /dev/null
+++ b/ravenwood/Framework.bp
@@ -0,0 +1,292 @@
+// Copyright (C) 2024 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// This file hosts all the genrule and module definitions for all Android specific
+// code that needs further post-processing by hoststubgen to support Ravenwood.
+
+/////////////////////////
+// framework-minus-apex
+/////////////////////////
+
+// Process framework-minus-apex with hoststubgen for Ravenwood.
+// This step takes several tens of seconds, so we manually shard it to multiple modules.
+// All the copies have to be kept in sync.
+// TODO: Do the sharding better, either by making hostsubgen support sharding natively, or
+// making a better build rule.
+
+genrule_defaults {
+    name: "framework-minus-apex.ravenwood-base_defaults",
+    tools: ["hoststubgen"],
+    srcs: [
+        ":framework-minus-apex-for-host",
+        ":ravenwood-common-policies",
+        ":ravenwood-framework-policies",
+        ":ravenwood-standard-options",
+        ":ravenwood-annotation-allowed-classes",
+    ],
+    out: [
+        "ravenwood.jar",
+        "hoststubgen_framework-minus-apex.log",
+    ],
+    visibility: ["//visibility:private"],
+}
+
+framework_minus_apex_cmd = "$(location hoststubgen) " +
+    "@$(location :ravenwood-standard-options) " +
+    "--debug-log $(location hoststubgen_framework-minus-apex.log) " +
+    "--out-jar $(location ravenwood.jar) " +
+    "--in-jar $(location :framework-minus-apex-for-host) " +
+    "--policy-override-file $(location :ravenwood-common-policies) " +
+    "--policy-override-file $(location :ravenwood-framework-policies) " +
+    "--annotation-allowed-classes-file $(location :ravenwood-annotation-allowed-classes) "
+
+java_genrule {
+    name: "framework-minus-apex.ravenwood-base_X0",
+    defaults: ["framework-minus-apex.ravenwood-base_defaults"],
+    cmd: framework_minus_apex_cmd + " --num-shards 10 --shard-index 0",
+}
+
+java_genrule {
+    name: "framework-minus-apex.ravenwood-base_X1",
+    defaults: ["framework-minus-apex.ravenwood-base_defaults"],
+    cmd: framework_minus_apex_cmd + " --num-shards 10 --shard-index 1",
+}
+
+java_genrule {
+    name: "framework-minus-apex.ravenwood-base_X2",
+    defaults: ["framework-minus-apex.ravenwood-base_defaults"],
+    cmd: framework_minus_apex_cmd + " --num-shards 10 --shard-index 2",
+}
+
+java_genrule {
+    name: "framework-minus-apex.ravenwood-base_X3",
+    defaults: ["framework-minus-apex.ravenwood-base_defaults"],
+    cmd: framework_minus_apex_cmd + " --num-shards 10 --shard-index 3",
+}
+
+java_genrule {
+    name: "framework-minus-apex.ravenwood-base_X4",
+    defaults: ["framework-minus-apex.ravenwood-base_defaults"],
+    cmd: framework_minus_apex_cmd + " --num-shards 10 --shard-index 4",
+}
+
+java_genrule {
+    name: "framework-minus-apex.ravenwood-base_X5",
+    defaults: ["framework-minus-apex.ravenwood-base_defaults"],
+    cmd: framework_minus_apex_cmd + " --num-shards 10 --shard-index 5",
+}
+
+java_genrule {
+    name: "framework-minus-apex.ravenwood-base_X6",
+    defaults: ["framework-minus-apex.ravenwood-base_defaults"],
+    cmd: framework_minus_apex_cmd + " --num-shards 10 --shard-index 6",
+}
+
+java_genrule {
+    name: "framework-minus-apex.ravenwood-base_X7",
+    defaults: ["framework-minus-apex.ravenwood-base_defaults"],
+    cmd: framework_minus_apex_cmd + " --num-shards 10 --shard-index 7",
+}
+
+java_genrule {
+    name: "framework-minus-apex.ravenwood-base_X8",
+    defaults: ["framework-minus-apex.ravenwood-base_defaults"],
+    cmd: framework_minus_apex_cmd + " --num-shards 10 --shard-index 8",
+}
+
+java_genrule {
+    name: "framework-minus-apex.ravenwood-base_X9",
+    defaults: ["framework-minus-apex.ravenwood-base_defaults"],
+    cmd: framework_minus_apex_cmd + " --num-shards 10 --shard-index 9",
+}
+
+// Build framework-minus-apex.ravenwood-base without sharding.
+// We extract the various dump files from this one, rather than the sharded ones, because
+// some dumps use the output from other classes (e.g. base classes) which may not be in the
+// same shard. Also some of the dump files ("apis") may be slow even when sharded, because
+// the output contains the information from all the input classes, rather than the output classes.
+// Not using sharding is fine for this module because it's only used for collecting the
+// dump / stats files, which don't have to happen regularly.
+java_genrule {
+    name: "framework-minus-apex.ravenwood-base_all",
+    defaults: ["framework-minus-apex.ravenwood-base_defaults"],
+    cmd: framework_minus_apex_cmd +
+        "--stats-file $(location hoststubgen_framework-minus-apex_stats.csv) " +
+        "--supported-api-list-file $(location hoststubgen_framework-minus-apex_apis.csv) " +
+
+        "--gen-keep-all-file $(location hoststubgen_framework-minus-apex_keep_all.txt) " +
+        "--gen-input-dump-file $(location hoststubgen_framework-minus-apex_dump.txt) ",
+
+    out: [
+        "hoststubgen_framework-minus-apex_keep_all.txt",
+        "hoststubgen_framework-minus-apex_dump.txt",
+        "hoststubgen_framework-minus-apex_stats.csv",
+        "hoststubgen_framework-minus-apex_apis.csv",
+    ],
+}
+
+// Marge all the sharded jars
+java_genrule {
+    name: "framework-minus-apex.ravenwood",
+    defaults: ["ravenwood-internal-only-visibility-java"],
+    cmd: "$(location merge_zips) $(out) $(in)",
+    tools: ["merge_zips"],
+    srcs: [
+        ":framework-minus-apex.ravenwood-base_X0{ravenwood.jar}",
+        ":framework-minus-apex.ravenwood-base_X1{ravenwood.jar}",
+        ":framework-minus-apex.ravenwood-base_X2{ravenwood.jar}",
+        ":framework-minus-apex.ravenwood-base_X3{ravenwood.jar}",
+        ":framework-minus-apex.ravenwood-base_X4{ravenwood.jar}",
+        ":framework-minus-apex.ravenwood-base_X5{ravenwood.jar}",
+        ":framework-minus-apex.ravenwood-base_X6{ravenwood.jar}",
+        ":framework-minus-apex.ravenwood-base_X7{ravenwood.jar}",
+        ":framework-minus-apex.ravenwood-base_X8{ravenwood.jar}",
+        ":framework-minus-apex.ravenwood-base_X9{ravenwood.jar}",
+    ],
+    out: [
+        "framework-minus-apex.ravenwood.jar",
+    ],
+}
+
+//////////////////
+// services.core
+//////////////////
+
+java_library {
+    name: "services.core-for-host",
+    installable: false, // host only jar.
+    static_libs: [
+        "services.core",
+    ],
+    sdk_version: "core_platform",
+    visibility: ["//visibility:private"],
+}
+
+java_genrule {
+    name: "services.core.ravenwood-base",
+    tools: ["hoststubgen"],
+    cmd: "$(location hoststubgen) " +
+        "@$(location :ravenwood-standard-options) " +
+
+        "--debug-log $(location hoststubgen_services.core.log) " +
+        "--stats-file $(location hoststubgen_services.core_stats.csv) " +
+        "--supported-api-list-file $(location hoststubgen_services.core_apis.csv) " +
+        "--gen-keep-all-file $(location hoststubgen_services.core_keep_all.txt) " +
+        "--gen-input-dump-file $(location hoststubgen_services.core_dump.txt) " +
+
+        "--out-jar $(location ravenwood.jar) " +
+        "--in-jar $(location :services.core-for-host) " +
+
+        "--policy-override-file $(location :ravenwood-common-policies) " +
+        "--policy-override-file $(location :ravenwood-services-policies) " +
+        "--annotation-allowed-classes-file $(location :ravenwood-annotation-allowed-classes) ",
+    srcs: [
+        ":services.core-for-host",
+        ":ravenwood-common-policies",
+        ":ravenwood-services-policies",
+        ":ravenwood-standard-options",
+        ":ravenwood-annotation-allowed-classes",
+    ],
+    out: [
+        "ravenwood.jar",
+
+        // Following files are created just as FYI.
+        "hoststubgen_services.core_keep_all.txt",
+        "hoststubgen_services.core_dump.txt",
+
+        "hoststubgen_services.core.log",
+        "hoststubgen_services.core_stats.csv",
+        "hoststubgen_services.core_apis.csv",
+    ],
+    visibility: ["//visibility:private"],
+}
+
+java_genrule {
+    name: "services.core.ravenwood",
+    defaults: ["ravenwood-internal-only-visibility-genrule"],
+    cmd: "cp $(in) $(out)",
+    srcs: [
+        ":services.core.ravenwood-base{ravenwood.jar}",
+    ],
+    out: [
+        "services.core.ravenwood.jar",
+    ],
+}
+
+// TODO(b/313930116) This jarjar is a bit slow. We should use hoststubgen for renaming,
+// but services.core.ravenwood has complex dependencies, so it'll take more than
+// just using hoststubgen "rename"s.
+java_library {
+    name: "services.core.ravenwood-jarjar",
+    defaults: ["ravenwood-internal-only-visibility-java"],
+    installable: false,
+    static_libs: [
+        "services.core.ravenwood",
+    ],
+    jarjar_rules: ":ravenwood-services-jarjar-rules",
+}
+
+///////////////
+// core-icu4j
+///////////////
+
+java_genrule {
+    name: "core-icu4j-for-host.ravenwood-base",
+    tools: ["hoststubgen"],
+    cmd: "$(location hoststubgen) " +
+        "@$(location :ravenwood-standard-options) " +
+
+        "--debug-log $(location hoststubgen_core-icu4j-for-host.log) " +
+        "--stats-file $(location hoststubgen_core-icu4j-for-host_stats.csv) " +
+        "--supported-api-list-file $(location hoststubgen_core-icu4j-for-host_apis.csv) " +
+        "--gen-keep-all-file $(location hoststubgen_core-icu4j-for-host_keep_all.txt) " +
+        "--gen-input-dump-file $(location hoststubgen_core-icu4j-for-host_dump.txt) " +
+
+        "--out-jar $(location ravenwood.jar) " +
+        "--in-jar $(location :core-icu4j-for-host) " +
+
+        "--policy-override-file $(location :ravenwood-common-policies) " +
+        "--policy-override-file $(location :icu-ravenwood-policies) ",
+    srcs: [
+        ":core-icu4j-for-host",
+
+        ":ravenwood-common-policies",
+        ":icu-ravenwood-policies",
+        ":ravenwood-standard-options",
+    ],
+    out: [
+        "ravenwood.jar",
+
+        // Following files are created just as FYI.
+        "hoststubgen_core-icu4j-for-host_keep_all.txt",
+        "hoststubgen_core-icu4j-for-host_dump.txt",
+
+        "hoststubgen_core-icu4j-for-host.log",
+        "hoststubgen_core-icu4j-for-host_stats.csv",
+        "hoststubgen_core-icu4j-for-host_apis.csv",
+    ],
+    visibility: ["//visibility:private"],
+}
+
+java_genrule {
+    name: "core-icu4j-for-host.ravenwood",
+    defaults: ["ravenwood-internal-only-visibility-genrule"],
+    cmd: "cp $(in) $(out)",
+    srcs: [
+        ":core-icu4j-for-host.ravenwood-base{ravenwood.jar}",
+    ],
+    out: [
+        "core-icu4j-for-host.ravenwood.jar",
+    ],
+}
diff --git a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuntimeEnvironmentController.java b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuntimeEnvironmentController.java
index 6e73b2c..908e590 100644
--- a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuntimeEnvironmentController.java
+++ b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuntimeEnvironmentController.java
@@ -21,9 +21,15 @@
 import static com.android.ravenwood.common.RavenwoodCommonUtils.RAVENWOOD_VERBOSE_LOGGING;
 import static com.android.ravenwood.common.RavenwoodCommonUtils.RAVENWOOD_VERSION_JAVA_SYSPROP;
 
+import static org.junit.Assert.assertThrows;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.mock;
+
 import android.app.ActivityManager;
 import android.app.Instrumentation;
 import android.app.ResourcesManager;
+import android.app.UiAutomation;
 import android.content.res.Resources;
 import android.os.Binder;
 import android.os.Build;
@@ -38,6 +44,7 @@
 
 import androidx.test.platform.app.InstrumentationRegistry;
 
+import com.android.hoststubgen.hosthelper.HostTestUtils;
 import com.android.internal.os.RuntimeInit;
 import com.android.ravenwood.RavenwoodRuntimeNative;
 import com.android.ravenwood.common.RavenwoodCommonUtils;
@@ -50,8 +57,10 @@
 import java.io.File;
 import java.io.IOException;
 import java.io.PrintStream;
+import java.util.Collections;
 import java.util.Map;
 import java.util.Objects;
+import java.util.Set;
 import java.util.concurrent.Executors;
 import java.util.concurrent.ScheduledExecutorService;
 import java.util.concurrent.ScheduledFuture;
@@ -123,6 +132,9 @@
 
     private static RavenwoodConfig sConfig;
     private static RavenwoodSystemProperties sProps;
+    // TODO: use the real UiAutomation class instead of a mock
+    private static UiAutomation sMockUiAutomation;
+    private static Set<String> sAdoptedPermissions = Collections.emptySet();
     private static boolean sInitialized = false;
 
     /**
@@ -167,6 +179,9 @@
         // This will let AndroidJUnit4 use the original runner.
         System.setProperty("android.junit.runner",
                 "androidx.test.internal.runner.junit4.AndroidJUnit4ClassRunner");
+
+        assertMockitoVersion();
+        sMockUiAutomation = createMockUiAutomation();
     }
 
     /**
@@ -257,7 +272,7 @@
 
         // Prepare other fields.
         config.mInstrumentation = new Instrumentation();
-        config.mInstrumentation.basicInit(config.mInstContext, config.mTargetContext);
+        config.mInstrumentation.basicInit(instContext, targetContext, sMockUiAutomation);
         InstrumentationRegistry.registerInstance(config.mInstrumentation, Bundle.EMPTY);
 
         RavenwoodSystemServer.init(config);
@@ -296,12 +311,13 @@
         config.mInstrumentation = null;
         if (config.mInstContext != null) {
             ((RavenwoodContext) config.mInstContext).cleanUp();
+            config.mInstContext = null;
         }
         if (config.mTargetContext != null) {
             ((RavenwoodContext) config.mTargetContext).cleanUp();
+            config.mTargetContext = null;
         }
-        config.mInstContext = null;
-        config.mTargetContext = null;
+        sMockUiAutomation.dropShellPermissionIdentity();
 
         if (config.mProvideMainThread) {
             Looper.getMainLooper().quit();
@@ -377,6 +393,53 @@
         }
     }
 
+    private static final String MOCKITO_ERROR = "FATAL: Unsupported Mockito detected!"
+            + " Your test or its dependencies use one of the \"mockito-target-*\""
+            + " modules as static library, which is unusable on host side."
+            + " Please switch over to use \"mockito-ravenwood-prebuilt\" as shared library, or"
+            + " as a last resort, set `ravenizer: { strip_mockito: true }` in your test module.";
+
+    /**
+     * Assert the Mockito version at runtime to ensure no incorrect Mockito classes are loaded.
+     */
+    private static void assertMockitoVersion() {
+        // DexMaker should not exist
+        assertThrows(
+                MOCKITO_ERROR,
+                ClassNotFoundException.class,
+                () -> Class.forName("com.android.dx.DexMaker"));
+        // Mockito 2 should not exist
+        assertThrows(
+                MOCKITO_ERROR,
+                ClassNotFoundException.class,
+                () -> Class.forName("org.mockito.Matchers"));
+    }
+
+    private static UiAutomation createMockUiAutomation() {
+        var mock = mock(UiAutomation.class, inv -> {
+            HostTestUtils.onThrowMethodCalled();
+            return null;
+        });
+        doAnswer(inv -> {
+            sAdoptedPermissions = UiAutomation.ALL_PERMISSIONS;
+            return null;
+        }).when(mock).adoptShellPermissionIdentity();
+        doAnswer(inv -> {
+            if (inv.getArgument(0) == null) {
+                sAdoptedPermissions = UiAutomation.ALL_PERMISSIONS;
+            } else {
+                sAdoptedPermissions = (Set) Set.of(inv.getArguments());
+            }
+            return null;
+        }).when(mock).adoptShellPermissionIdentity(any());
+        doAnswer(inv -> {
+            sAdoptedPermissions = Collections.emptySet();
+            return null;
+        }).when(mock).dropShellPermissionIdentity();
+        doAnswer(inv -> sAdoptedPermissions).when(mock).getAdoptedShellPermissions();
+        return mock;
+    }
+
     @SuppressWarnings("unused")  // Called from native code (ravenwood_sysprop.cpp)
     private static void checkSystemPropertyAccess(String key, boolean write) {
         boolean result = write ? sProps.isKeyWritable(key) : sProps.isKeyReadable(key);
diff --git a/ravenwood/tests/bivalenttest/test/com/android/ravenwoodtest/bivalenttest/RavenwoodUiAutomationTest.java b/ravenwood/tests/bivalenttest/test/com/android/ravenwoodtest/bivalenttest/RavenwoodUiAutomationTest.java
new file mode 100644
index 0000000..eb94827
--- /dev/null
+++ b/ravenwood/tests/bivalenttest/test/com/android/ravenwoodtest/bivalenttest/RavenwoodUiAutomationTest.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.ravenwoodtest.bivalenttest;
+
+import static android.Manifest.permission.OVERRIDE_COMPAT_CHANGE_CONFIG;
+import static android.Manifest.permission.READ_COMPAT_CHANGE_CONFIG;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertThrows;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeTrue;
+
+import android.app.Instrumentation;
+import android.app.UiAutomation;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import com.android.ravenwood.common.RavenwoodCommonUtils;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Set;
+
+@RunWith(AndroidJUnit4.class)
+public class RavenwoodUiAutomationTest {
+
+    private Instrumentation mInstrumentation;
+
+    @Before
+    public void setup() {
+        mInstrumentation = InstrumentationRegistry.getInstrumentation();
+    }
+
+    @Test
+    public void testGetUiAutomation() {
+        assertNotNull(mInstrumentation.getUiAutomation());
+    }
+
+    @Test
+    public void testGetUiAutomationWithFlags() {
+        assertNotNull(mInstrumentation.getUiAutomation(UiAutomation.FLAG_DONT_USE_ACCESSIBILITY));
+    }
+
+    @Test
+    public void testShellPermissionApis() {
+        var uiAutomation = mInstrumentation.getUiAutomation();
+        assertTrue(uiAutomation.getAdoptedShellPermissions().isEmpty());
+        uiAutomation.adoptShellPermissionIdentity();
+        assertEquals(uiAutomation.getAdoptedShellPermissions(), UiAutomation.ALL_PERMISSIONS);
+        uiAutomation.adoptShellPermissionIdentity((String[]) null);
+        assertEquals(uiAutomation.getAdoptedShellPermissions(), UiAutomation.ALL_PERMISSIONS);
+        uiAutomation.adoptShellPermissionIdentity(
+                OVERRIDE_COMPAT_CHANGE_CONFIG, READ_COMPAT_CHANGE_CONFIG);
+        assertEquals(uiAutomation.getAdoptedShellPermissions(),
+                Set.of(OVERRIDE_COMPAT_CHANGE_CONFIG, READ_COMPAT_CHANGE_CONFIG));
+        uiAutomation.dropShellPermissionIdentity();
+        assertTrue(uiAutomation.getAdoptedShellPermissions().isEmpty());
+    }
+
+    @Test
+    public void testUnsupportedMethod() {
+        // Only unsupported on Ravenwood
+        assumeTrue(RavenwoodCommonUtils.isOnRavenwood());
+        assertThrows(RuntimeException.class,
+                () -> mInstrumentation.getUiAutomation().executeShellCommand("echo ok"));
+    }
+}
diff --git a/ravenwood/tests/coretest/test/com/android/ravenwoodtest/coretest/RavenwoodMockitoTest.java b/ravenwood/tests/coretest/test/com/android/ravenwoodtest/coretest/RavenwoodMockitoTest.java
index dd6d259..31884b6 100644
--- a/ravenwood/tests/coretest/test/com/android/ravenwoodtest/coretest/RavenwoodMockitoTest.java
+++ b/ravenwood/tests/coretest/test/com/android/ravenwoodtest/coretest/RavenwoodMockitoTest.java
@@ -16,11 +16,19 @@
 package com.android.ravenwoodtest.coretest;
 
 import static org.junit.Assert.assertThrows;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.mock;
 
 import org.junit.Test;
 
 public class RavenwoodMockitoTest {
 
+    private static class MockClass {
+        void foo() {
+            throw new RuntimeException("Unsupported!!");
+        }
+    }
+
     @Test
     public void checkMockitoClasses() {
         // DexMaker should not exist
@@ -32,4 +40,11 @@
                 ClassNotFoundException.class,
                 () -> Class.forName("org.mockito.Matchers"));
     }
+
+    @Test
+    public void checkMockitoActuallyWorks() {
+        var mock = mock(MockClass.class);
+        doNothing().when(mock).foo();
+        mock.foo();
+    }
 }
diff --git a/ravenwood/texts/ravenwood-common-policies.txt b/ravenwood/texts/ravenwood-common-policies.txt
new file mode 100644
index 0000000..08f53977
--- /dev/null
+++ b/ravenwood/texts/ravenwood-common-policies.txt
@@ -0,0 +1,20 @@
+# Ravenwood "policy" that should apply to all code.
+
+# Keep all AIDL interfaces
+class :aidl keepclass
+
+# Keep all feature flag implementations
+class :feature_flags keepclass
+
+# Keep all sysprops generated code implementations
+class :sysprops keepclass
+
+# Keep all resource R classes
+class :r keepclass
+
+# Support APIs not available in standard JRE
+class java.io.FileDescriptor keep
+    method getInt$ ()I @com.android.ravenwood.RavenwoodJdkPatch.getInt$
+    method setInt$ (I)V @com.android.ravenwood.RavenwoodJdkPatch.setInt$
+class java.util.LinkedHashMap keep
+    method eldest ()Ljava/util/Map$Entry; @com.android.ravenwood.RavenwoodJdkPatch.eldest
diff --git a/ravenwood/texts/ravenwood-framework-policies.txt b/ravenwood/texts/ravenwood-framework-policies.txt
index d962c82..3649f0e 100644
--- a/ravenwood/texts/ravenwood-framework-policies.txt
+++ b/ravenwood/texts/ravenwood-framework-policies.txt
@@ -1,29 +1,10 @@
 # Ravenwood "policy" file for framework-minus-apex.
 
-# Keep all AIDL interfaces
-class :aidl keepclass
-
-# Keep all feature flag implementations
-class :feature_flags keepclass
-
-# Keep all sysprops generated code implementations
-class :sysprops keepclass
-
-# Keep all resource R classes
-class :r keepclass
-
 # To avoid VerifyError on nano proto files (b/324063814), we rename nano proto classes.
 # Note: The "rename" directive must use slashes (/) as a package name separator.
 rename com/.*/nano/   devicenano/
 rename android/.*/nano/   devicenano/
 
-# Support APIs not available in standard JRE
-class java.io.FileDescriptor keep
-    method getInt$ ()I @com.android.ravenwood.RavenwoodJdkPatch.getInt$
-    method setInt$ (I)V @com.android.ravenwood.RavenwoodJdkPatch.setInt$
-class java.util.LinkedHashMap keep
-    method eldest ()Ljava/util/Map$Entry; @com.android.ravenwood.RavenwoodJdkPatch.eldest
-
 # Exported to Mainline modules; cannot use annotations
 class com.android.internal.util.FastXmlSerializer keepclass
 class com.android.internal.util.FileRotator keepclass
diff --git a/ravenwood/texts/ravenwood-services-policies.txt b/ravenwood/texts/ravenwood-services-policies.txt
index 5cdb4f7..cc2fa60 100644
--- a/ravenwood/texts/ravenwood-services-policies.txt
+++ b/ravenwood/texts/ravenwood-services-policies.txt
@@ -1,7 +1 @@
 # Ravenwood "policy" file for services.core.
-
-# Keep all AIDL interfaces
-class :aidl keepclass
-
-# Keep all feature flag implementations
-class :feature_flags keepclass
diff --git a/ravenwood/tools/ravenizer/src/com/android/platform/test/ravenwood/ravenizer/Ravenizer.kt b/ravenwood/tools/ravenizer/src/com/android/platform/test/ravenwood/ravenizer/Ravenizer.kt
index 49f0b59..e67c730 100644
--- a/ravenwood/tools/ravenizer/src/com/android/platform/test/ravenwood/ravenizer/Ravenizer.kt
+++ b/ravenwood/tools/ravenizer/src/com/android/platform/test/ravenwood/ravenizer/Ravenizer.kt
@@ -127,7 +127,7 @@
             }
         }
         if (includeUnsupportedMockito(allClasses)) {
-            log.w("Unsupported Mockito detected in $inJar}!")
+            log.w("Unsupported Mockito detected in $inJar!")
         }
 
         stats.totalProcessTime = log.vTime("$executableName processing $inJar") {
diff --git a/services/accessibility/accessibility.aconfig b/services/accessibility/accessibility.aconfig
index ee3bbca..034127c 100644
--- a/services/accessibility/accessibility.aconfig
+++ b/services/accessibility/accessibility.aconfig
@@ -162,6 +162,13 @@
 }
 
 flag {
+    name: "magnification_enlarge_pointer"
+    namespace: "accessibility"
+    description: "When fullscreen magnification is enabled, pointer icon is enlarged"
+    bug: "355734856"
+}
+
+flag {
     name: "manager_avoid_receiver_timeout"
     namespace: "accessibility"
     description: "Register receivers on background handler so they have more time to complete"
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index d595d02..1451dfa 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -3653,6 +3653,12 @@
             return;
         }
 
+        // Magnification connection should not be requested for visible background users.
+        // (b/332222893)
+        if (mUmi.isVisibleBackgroundFullUser(userState.mUserId)) {
+            return;
+        }
+
         final boolean shortcutEnabled = (userState.isShortcutMagnificationEnabledLocked()
                 || userState.isMagnificationSingleFingerTripleTapEnabledLocked()
                 || (Flags.enableMagnificationMultipleFingerMultipleTapGesture()
diff --git a/services/accessibility/java/com/android/server/accessibility/MouseKeysInterceptor.java b/services/accessibility/java/com/android/server/accessibility/MouseKeysInterceptor.java
index 4b97745..1df5d1a 100644
--- a/services/accessibility/java/com/android/server/accessibility/MouseKeysInterceptor.java
+++ b/services/accessibility/java/com/android/server/accessibility/MouseKeysInterceptor.java
@@ -138,8 +138,8 @@
         DIAGONAL_UP_LEFT_MOVE(KeyEvent.KEYCODE_7),
         UP_MOVE_OR_SCROLL(KeyEvent.KEYCODE_8),
         DIAGONAL_UP_RIGHT_MOVE(KeyEvent.KEYCODE_9),
-        LEFT_MOVE(KeyEvent.KEYCODE_U),
-        RIGHT_MOVE(KeyEvent.KEYCODE_O),
+        LEFT_MOVE_OR_SCROLL(KeyEvent.KEYCODE_U),
+        RIGHT_MOVE_OR_SCROLL(KeyEvent.KEYCODE_O),
         DIAGONAL_DOWN_LEFT_MOVE(KeyEvent.KEYCODE_J),
         DOWN_MOVE_OR_SCROLL(KeyEvent.KEYCODE_K),
         DIAGONAL_DOWN_RIGHT_MOVE(KeyEvent.KEYCODE_L),
@@ -267,6 +267,16 @@
         );
     }
 
+    @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
+    private void sendVirtualMouseScrollEvent(float x, float y) {
+        waitForVirtualMouseCreation();
+        mVirtualMouse.sendScrollEvent(new VirtualMouseScrollEvent.Builder()
+                .setXAxisMovement(x)
+                .setYAxisMovement(y)
+                .build()
+        );
+    }
+
     /**
      * Performs a mouse scroll action based on the provided key code.
      * The scroll action will only be performed if the scroll toggle is on.
@@ -284,19 +294,31 @@
     private void performMouseScrollAction(int keyCode) {
         MouseKeyEvent mouseKeyEvent = MouseKeyEvent.from(
                 keyCode, mActiveInputDeviceId, mDeviceKeyCodeMap);
-        float y = switch (mouseKeyEvent) {
-            case UP_MOVE_OR_SCROLL -> MOUSE_SCROLL_STEP;
-            case DOWN_MOVE_OR_SCROLL -> -MOUSE_SCROLL_STEP;
-            default -> 0.0f;
-        };
-        waitForVirtualMouseCreation();
-        mVirtualMouse.sendScrollEvent(new VirtualMouseScrollEvent.Builder()
-                .setYAxisMovement(y)
-                .build()
-        );
+        float x = 0f;
+        float y = 0f;
+
+        switch (mouseKeyEvent) {
+            case UP_MOVE_OR_SCROLL -> {
+                y = MOUSE_SCROLL_STEP;
+            }
+            case DOWN_MOVE_OR_SCROLL -> {
+                y = -MOUSE_SCROLL_STEP;
+            }
+            case LEFT_MOVE_OR_SCROLL -> {
+                x = MOUSE_SCROLL_STEP;
+            }
+            case RIGHT_MOVE_OR_SCROLL -> {
+                x = -MOUSE_SCROLL_STEP;
+            }
+            default -> {
+                x = 0.0f;
+                y = 0.0f;
+            }
+        }
+        sendVirtualMouseScrollEvent(x, y);
         if (DEBUG) {
             Slog.d(LOG_TAG, "Performed mouse key event: " + mouseKeyEvent.name()
-                    + " for scroll action with axis movement (y=" + y + ")");
+                    + " for scroll action with axis movement (x=" + x + ", y=" + y + ")");
         }
     }
 
@@ -344,8 +366,8 @@
      * The method calculates the relative movement of the mouse pointer
      * and sends the corresponding event to the virtual mouse.
      *
-     * The UP and DOWN pointer actions will only take place for their respective keys
-     * if the scroll toggle is off.
+     * The UP, DOWN, LEFT, RIGHT  pointer actions will only take place for their
+     * respective keys if the scroll toggle is off.
      *
      * @param keyCode The key code representing the direction or button press.
      *                Supported keys are:
@@ -353,8 +375,8 @@
      *                  <li>{@link MouseKeysInterceptor.MouseKeyEvent#DIAGONAL_DOWN_LEFT_MOVE}
      *                  <li>{@link MouseKeysInterceptor.MouseKeyEvent#DOWN_MOVE_OR_SCROLL}
      *                  <li>{@link MouseKeysInterceptor.MouseKeyEvent#DIAGONAL_DOWN_RIGHT_MOVE}
-     *                  <li>{@link MouseKeysInterceptor.MouseKeyEvent#LEFT_MOVE}
-     *                  <li>{@link MouseKeysInterceptor.MouseKeyEvent#RIGHT_MOVE}
+     *                  <li>{@link MouseKeysInterceptor.MouseKeyEvent#LEFT_MOVE_OR_SCROLL}
+     *                  <li>{@link MouseKeysInterceptor.MouseKeyEvent#RIGHT_MOVE_OR_SCROLL}
      *                  <li>{@link MouseKeysInterceptor.MouseKeyEvent#DIAGONAL_UP_LEFT_MOVE}
      *                  <li>{@link MouseKeysInterceptor.MouseKeyEvent#UP_MOVE_OR_SCROLL}
      *                  <li>{@link MouseKeysInterceptor.MouseKeyEvent#DIAGONAL_UP_RIGHT_MOVE}
@@ -381,10 +403,10 @@
                 x = MOUSE_POINTER_MOVEMENT_STEP / sqrt(2);
                 y = MOUSE_POINTER_MOVEMENT_STEP / sqrt(2);
             }
-            case LEFT_MOVE -> {
+            case LEFT_MOVE_OR_SCROLL -> {
                 x = -MOUSE_POINTER_MOVEMENT_STEP;
             }
-            case RIGHT_MOVE -> {
+            case RIGHT_MOVE_OR_SCROLL -> {
                 x = MOUSE_POINTER_MOVEMENT_STEP;
             }
             case DIAGONAL_UP_LEFT_MOVE -> {
@@ -424,7 +446,9 @@
 
     private boolean isMouseScrollKey(int keyCode, InputDevice inputDevice) {
         return keyCode == MouseKeyEvent.UP_MOVE_OR_SCROLL.getKeyCode(inputDevice)
-                || keyCode == MouseKeyEvent.DOWN_MOVE_OR_SCROLL.getKeyCode(inputDevice);
+                || keyCode == MouseKeyEvent.DOWN_MOVE_OR_SCROLL.getKeyCode(inputDevice)
+                || keyCode == MouseKeyEvent.LEFT_MOVE_OR_SCROLL.getKeyCode(inputDevice)
+                || keyCode == MouseKeyEvent.RIGHT_MOVE_OR_SCROLL.getKeyCode(inputDevice);
     }
 
     /**
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationConnectionManager.java b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationConnectionManager.java
index 19e3e69..fe06406 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationConnectionManager.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationConnectionManager.java
@@ -19,6 +19,7 @@
 import static android.accessibilityservice.AccessibilityTrace.FLAGS_MAGNIFICATION_CONNECTION;
 import static android.accessibilityservice.AccessibilityTrace.FLAGS_MAGNIFICATION_CONNECTION_CALLBACK;
 import static android.os.Build.HW_TIMEOUT_MULTIPLIER;
+import static android.os.UserHandle.getCallingUserId;
 import static android.view.accessibility.MagnificationAnimationCallback.STUB_ANIMATION_CALLBACK;
 
 import static com.android.server.accessibility.AccessibilityManagerService.INVALID_SERVICE_ID;
@@ -54,6 +55,7 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.server.LocalServices;
 import com.android.server.accessibility.AccessibilityTraceManager;
+import com.android.server.pm.UserManagerInternal;
 import com.android.server.statusbar.StatusBarManagerInternal;
 import com.android.server.wm.WindowManagerInternal;
 
@@ -209,6 +211,7 @@
     private final Callback mCallback;
     private final AccessibilityTraceManager mTrace;
     private final MagnificationScaleProvider mScaleProvider;
+    private final UserManagerInternal mUserManagerInternal;
 
     public MagnificationConnectionManager(Context context, Object lock, @NonNull Callback callback,
             AccessibilityTraceManager trace, MagnificationScaleProvider scaleProvider) {
@@ -217,6 +220,7 @@
         mCallback = callback;
         mTrace = trace;
         mScaleProvider = scaleProvider;
+        mUserManagerInternal = LocalServices.getService(UserManagerInternal.class);
     }
 
     /**
@@ -280,12 +284,18 @@
      * Requests {@link IMagnificationConnection} through
      * {@link StatusBarManagerInternal#requestMagnificationConnection(boolean)} and
      * destroys all window magnifications if necessary.
+     * NOTE: Currently, this is not allowed to call from visible background users.(b/332222893)
      *
      * @param connect {@code true} if needs connection, otherwise set the connection to null and
      *                destroy all window magnifications.
      * @return {@code true} if {@link IMagnificationConnection} state is going to change.
      */
     public boolean requestConnection(boolean connect) {
+        final int callingUserId = getCallingUserId();
+        if (mUserManagerInternal.isVisibleBackgroundFullUser(callingUserId)) {
+            throw new SecurityException("Visible background user(u" + callingUserId
+                    + " is not permitted to request magnification connection.");
+        }
         if (DBG) {
             Slog.d(TAG, "requestConnection :" + connect);
         }
diff --git a/services/appfunctions/java/com/android/server/appfunctions/AppFunctionDumpHelper.java b/services/appfunctions/java/com/android/server/appfunctions/AppFunctionDumpHelper.java
new file mode 100644
index 0000000..a832545
--- /dev/null
+++ b/services/appfunctions/java/com/android/server/appfunctions/AppFunctionDumpHelper.java
@@ -0,0 +1,188 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.appfunctions;
+
+import static android.app.appfunctions.AppFunctionRuntimeMetadata.PROPERTY_APP_FUNCTION_STATIC_METADATA_QUALIFIED_ID;
+import static android.app.appfunctions.AppFunctionStaticMetadataHelper.APP_FUNCTION_INDEXER_PACKAGE;
+import static android.app.appfunctions.AppFunctionStaticMetadataHelper.PROPERTY_FUNCTION_ID;
+
+import android.Manifest;
+import android.annotation.BinderThread;
+import android.annotation.RequiresPermission;
+import android.annotation.NonNull;
+import android.content.Context;
+import android.content.pm.UserInfo;
+import android.os.UserManager;
+import android.util.IndentingPrintWriter;
+import android.app.appfunctions.AppFunctionRuntimeMetadata;
+import android.app.appfunctions.AppFunctionStaticMetadataHelper;
+import android.app.appsearch.AppSearchManager;
+import android.app.appsearch.AppSearchManager.SearchContext;
+import android.app.appsearch.JoinSpec;
+import android.app.appsearch.GenericDocument;
+import android.app.appsearch.SearchResult;
+import android.app.appsearch.SearchSpec;
+
+import java.io.PrintWriter;
+import java.lang.reflect.Array;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Set;
+
+public final class AppFunctionDumpHelper {
+    private static final String TAG = AppFunctionDumpHelper.class.getSimpleName();
+
+    private AppFunctionDumpHelper() {}
+
+    /** Dumps the state of all app functions for all users. */
+    @BinderThread
+    @RequiresPermission(
+            anyOf = {Manifest.permission.CREATE_USERS, Manifest.permission.MANAGE_USERS})
+    public static void dumpAppFunctionsState(@NonNull Context context, @NonNull PrintWriter w) {
+        UserManager userManager = context.getSystemService(UserManager.class);
+        if (userManager == null) {
+            w.println("Couldn't retrieve UserManager.");
+            return;
+        }
+
+        IndentingPrintWriter pw = new IndentingPrintWriter(w);
+
+        List<UserInfo> userInfos = userManager.getAliveUsers();
+        for (UserInfo userInfo : userInfos) {
+            pw.println(
+                    "AppFunction state for user " + userInfo.getUserHandle().getIdentifier() + ":");
+            pw.increaseIndent();
+            dumpAppFunctionsStateForUser(
+                    context.createContextAsUser(userInfo.getUserHandle(), /* flags= */ 0), pw);
+            pw.decreaseIndent();
+        }
+    }
+
+    private static void dumpAppFunctionsStateForUser(
+            @NonNull Context context, @NonNull IndentingPrintWriter pw) {
+        AppSearchManager appSearchManager = context.getSystemService(AppSearchManager.class);
+        if (appSearchManager == null) {
+            pw.println("Couldn't retrieve AppSearchManager.");
+            return;
+        }
+
+        try (FutureGlobalSearchSession searchSession =
+                new FutureGlobalSearchSession(appSearchManager, Runnable::run)) {
+            pw.println();
+
+            try (FutureSearchResults futureSearchResults =
+                    searchSession.search("", buildAppFunctionMetadataSearchSpec()).get(); ) {
+                List<SearchResult> searchResultsList;
+                do {
+                    searchResultsList = futureSearchResults.getNextPage().get();
+                    for (SearchResult searchResult : searchResultsList) {
+                        dumpAppFunctionMetadata(pw, searchResult);
+                    }
+                } while (!searchResultsList.isEmpty());
+            }
+
+        } catch (Exception e) {
+            pw.println("Failed to dump AppFunction state: " + e);
+        }
+    }
+
+    private static SearchSpec buildAppFunctionMetadataSearchSpec() {
+        SearchSpec runtimeMetadataSearchSpec =
+                new SearchSpec.Builder()
+                        .addFilterPackageNames(APP_FUNCTION_INDEXER_PACKAGE)
+                        .addFilterSchemas(AppFunctionRuntimeMetadata.RUNTIME_SCHEMA_TYPE)
+                        .build();
+        JoinSpec joinSpec =
+                new JoinSpec.Builder(PROPERTY_APP_FUNCTION_STATIC_METADATA_QUALIFIED_ID)
+                        .setNestedSearch(/* queryExpression= */ "", runtimeMetadataSearchSpec)
+                        .build();
+
+        return new SearchSpec.Builder()
+                .addFilterPackageNames(APP_FUNCTION_INDEXER_PACKAGE)
+                .addFilterSchemas(AppFunctionStaticMetadataHelper.STATIC_SCHEMA_TYPE)
+                .setJoinSpec(joinSpec)
+                .build();
+    }
+
+    private static void dumpAppFunctionMetadata(
+            IndentingPrintWriter pw, SearchResult joinedSearchResult) {
+        pw.println(
+                "AppFunctionMetadata for: "
+                        + joinedSearchResult
+                                .getGenericDocument()
+                                .getPropertyString(PROPERTY_FUNCTION_ID));
+        pw.increaseIndent();
+
+        pw.println("Static Metadata:");
+        pw.increaseIndent();
+        writeGenericDocumentProperties(pw, joinedSearchResult.getGenericDocument());
+        pw.decreaseIndent();
+
+        pw.println("Runtime Metadata:");
+        pw.increaseIndent();
+        if (!joinedSearchResult.getJoinedResults().isEmpty()) {
+            writeGenericDocumentProperties(
+                    pw, joinedSearchResult.getJoinedResults().getFirst().getGenericDocument());
+        } else {
+            pw.println("No runtime metadata found.");
+        }
+        pw.decreaseIndent();
+
+        pw.decreaseIndent();
+    }
+
+    private static void writeGenericDocumentProperties(
+            IndentingPrintWriter pw, GenericDocument genericDocument) {
+        Set<String> propertyNames = genericDocument.getPropertyNames();
+        pw.println("{");
+        pw.increaseIndent();
+        for (String propertyName : propertyNames) {
+            Object propertyValue = genericDocument.getProperty(propertyName);
+            pw.print("\"" + propertyName + "\"" + ": [");
+
+            if (propertyValue instanceof GenericDocument[]) {
+                GenericDocument[] documentValues = (GenericDocument[]) propertyValue;
+                for (int i = 0; i < documentValues.length; i++) {
+                    GenericDocument documentValue = documentValues[i];
+                    writeGenericDocumentProperties(pw, documentValue);
+                    if (i != documentValues.length - 1) {
+                        pw.print(", ");
+                    }
+                    pw.println();
+                }
+            } else {
+                int propertyArrLength = Array.getLength(propertyValue);
+                for (int i = 0; i < propertyArrLength; i++) {
+                    Object propertyElement = Array.get(propertyValue, i);
+                    if (propertyElement instanceof String) {
+                        pw.print("\"" + propertyElement + "\"");
+                    } else if (propertyElement instanceof byte[]) {
+                        pw.print(Arrays.toString((byte[]) propertyElement));
+                    } else if (propertyElement != null) {
+                        pw.print(propertyElement.toString());
+                    }
+                    if (i != propertyArrLength - 1) {
+                        pw.print(", ");
+                    }
+                }
+            }
+            pw.println("]");
+        }
+        pw.decreaseIndent();
+        pw.println("}");
+    }
+}
diff --git a/services/appfunctions/java/com/android/server/appfunctions/AppFunctionManagerServiceImpl.java b/services/appfunctions/java/com/android/server/appfunctions/AppFunctionManagerServiceImpl.java
index d31ced3..5d57408 100644
--- a/services/appfunctions/java/com/android/server/appfunctions/AppFunctionManagerServiceImpl.java
+++ b/services/appfunctions/java/com/android/server/appfunctions/AppFunctionManagerServiceImpl.java
@@ -63,10 +63,11 @@
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.infra.AndroidFuture;
+import com.android.internal.util.DumpUtils;
 import com.android.server.SystemService.TargetUser;
-import com.android.server.appfunctions.RemoteServiceCaller.RunServiceCallCallback;
-import com.android.server.appfunctions.RemoteServiceCaller.ServiceUsageCompleteListener;
 
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
 import java.util.Objects;
 import java.util.concurrent.CompletionException;
 import java.util.concurrent.Executor;
@@ -122,6 +123,20 @@
     }
 
     @Override
+    public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args) {
+        if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) {
+            return;
+        }
+
+        final long token = Binder.clearCallingIdentity();
+        try {
+            AppFunctionDumpHelper.dumpAppFunctionsState(mContext, pw);
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
+    }
+
+    @Override
     public ICancellationSignal executeAppFunction(
             @NonNull ExecuteAppFunctionAidlRequest requestInternal,
             @NonNull IExecuteAppFunctionCallback executeAppFunctionCallback) {
@@ -216,6 +231,9 @@
                                                 "Caller does not have permission to execute the"
                                                         + " appfunction",
                                                 /* extras= */ null));
+                                throw new SecurityException(
+                                        "Caller does not have permission to execute the"
+                                                + " appfunction");
                             }
                         })
                 .thenCompose(
@@ -363,7 +381,8 @@
                                     runtimeMetadataSearchSession));
             AppFunctionRuntimeMetadata newMetadata =
                     new AppFunctionRuntimeMetadata.Builder(existingMetadata)
-                            .setEnabled(enabledState).build();
+                            .setEnabled(enabledState)
+                            .build();
             AppSearchBatchResult<String, Void> putDocumentBatchResult =
                     runtimeMetadataSearchSession
                             .put(
@@ -424,7 +443,7 @@
                         targetUser,
                         mServiceConfig.getExecuteAppFunctionCancellationTimeoutMillis(),
                         cancellationSignal,
-                        RunAppFunctionServiceCallback.create(
+                        new RunAppFunctionServiceCallback(
                                 requestInternal,
                                 cancellationCallback,
                                 safeExecuteAppFunctionCallback),
diff --git a/services/appfunctions/java/com/android/server/appfunctions/FutureAppSearchSession.java b/services/appfunctions/java/com/android/server/appfunctions/FutureAppSearchSession.java
index de2034b..b89348c 100644
--- a/services/appfunctions/java/com/android/server/appfunctions/FutureAppSearchSession.java
+++ b/services/appfunctions/java/com/android/server/appfunctions/FutureAppSearchSession.java
@@ -39,20 +39,6 @@
 /** A future API wrapper of {@link AppSearchSession} APIs. */
 public interface FutureAppSearchSession extends Closeable {
 
-    /** Converts a failed app search result codes into an exception. */
-    @NonNull
-    static Exception failedResultToException(@NonNull AppSearchResult<?> appSearchResult) {
-        return switch (appSearchResult.getResultCode()) {
-            case AppSearchResult.RESULT_INVALID_ARGUMENT ->
-                    new IllegalArgumentException(appSearchResult.getErrorMessage());
-            case AppSearchResult.RESULT_IO_ERROR ->
-                    new IOException(appSearchResult.getErrorMessage());
-            case AppSearchResult.RESULT_SECURITY_ERROR ->
-                    new SecurityException(appSearchResult.getErrorMessage());
-            default -> new IllegalStateException(appSearchResult.getErrorMessage());
-        };
-    }
-
     /**
      * Sets the schema that represents the organizational structure of data within the AppSearch
      * database.
@@ -86,17 +72,4 @@
 
     @Override
     void close();
-
-    /** A future API wrapper of {@link android.app.appsearch.SearchResults}. */
-    interface FutureSearchResults {
-
-        /**
-         * Retrieves the next page of {@link SearchResult} objects from the {@link AppSearchSession}
-         * database.
-         *
-         * <p>Continue calling this method to access results until it returns an empty list,
-         * signifying there are no more results.
-         */
-        AndroidFuture<List<SearchResult>> getNextPage();
-    }
 }
diff --git a/services/appfunctions/java/com/android/server/appfunctions/FutureAppSearchSessionImpl.java b/services/appfunctions/java/com/android/server/appfunctions/FutureAppSearchSessionImpl.java
index d24bb87..87589f5 100644
--- a/services/appfunctions/java/com/android/server/appfunctions/FutureAppSearchSessionImpl.java
+++ b/services/appfunctions/java/com/android/server/appfunctions/FutureAppSearchSessionImpl.java
@@ -16,7 +16,7 @@
 
 package com.android.server.appfunctions;
 
-import static com.android.server.appfunctions.FutureAppSearchSession.failedResultToException;
+import static com.android.server.appfunctions.FutureSearchResults.failedResultToException;
 
 import android.annotation.NonNull;
 import android.app.appsearch.AppSearchBatchResult;
@@ -192,33 +192,6 @@
                         });
     }
 
-    private static final class FutureSearchResultsImpl implements FutureSearchResults {
-        private final SearchResults mSearchResults;
-        private final Executor mExecutor;
-
-        private FutureSearchResultsImpl(
-                @NonNull SearchResults searchResults, @NonNull Executor executor) {
-            this.mSearchResults = searchResults;
-            this.mExecutor = executor;
-        }
-
-        @Override
-        public AndroidFuture<List<SearchResult>> getNextPage() {
-            AndroidFuture<AppSearchResult<List<SearchResult>>> nextPageFuture =
-                    new AndroidFuture<>();
-
-            mSearchResults.getNextPage(mExecutor, nextPageFuture::complete);
-            return nextPageFuture.thenApply(
-                    result -> {
-                        if (result.isSuccess()) {
-                            return result.getResultValue();
-                        } else {
-                            throw new RuntimeException(failedResultToException(result));
-                        }
-                    });
-        }
-    }
-
     private static final class BatchResultCallbackAdapter<K, V>
             implements BatchResultCallback<K, V> {
         private final AndroidFuture<AppSearchBatchResult<K, V>> mFuture;
diff --git a/services/appfunctions/java/com/android/server/appfunctions/FutureGlobalSearchSession.java b/services/appfunctions/java/com/android/server/appfunctions/FutureGlobalSearchSession.java
index 874c5da..4cc0817 100644
--- a/services/appfunctions/java/com/android/server/appfunctions/FutureGlobalSearchSession.java
+++ b/services/appfunctions/java/com/android/server/appfunctions/FutureGlobalSearchSession.java
@@ -20,6 +20,7 @@
 import android.app.appsearch.AppSearchManager;
 import android.app.appsearch.AppSearchResult;
 import android.app.appsearch.GlobalSearchSession;
+import android.app.appsearch.SearchSpec;
 import android.app.appsearch.exceptions.AppSearchException;
 import android.app.appsearch.observer.ObserverCallback;
 import android.app.appsearch.observer.ObserverSpec;
@@ -49,12 +50,23 @@
                         return result.getResultValue();
                     } else {
                         throw new RuntimeException(
-                                FutureAppSearchSession.failedResultToException(result));
+                                FutureSearchResults.failedResultToException(result));
                     }
                 });
     }
 
     /**
+     * Retrieves documents from the open {@link GlobalSearchSession} that match a given query string
+     * and type of search provided.
+     */
+    public AndroidFuture<FutureSearchResults> search(
+            String queryExpression, SearchSpec searchSpec) {
+        return getSessionAsync()
+                .thenApply(session -> session.search(queryExpression, searchSpec))
+                .thenApply(result -> new FutureSearchResultsImpl(result, mExecutor));
+    }
+
+    /**
      * Registers an observer callback for the given target package name.
      *
      * @param targetPackageName The package name of the target app.
diff --git a/services/appfunctions/java/com/android/server/appfunctions/FutureSearchResults.java b/services/appfunctions/java/com/android/server/appfunctions/FutureSearchResults.java
new file mode 100644
index 0000000..c38ff14
--- /dev/null
+++ b/services/appfunctions/java/com/android/server/appfunctions/FutureSearchResults.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.appfunctions;
+
+import android.annotation.NonNull;
+import android.app.appsearch.AppSearchResult;
+import android.app.appsearch.AppSearchSession;
+import android.app.appsearch.SearchResult;
+import android.app.appsearch.SearchResults;
+
+import com.android.internal.infra.AndroidFuture;
+
+import java.io.Closeable;
+import java.io.IOException;
+import java.util.List;
+
+/** A future API wrapper of {@link android.app.appsearch.SearchResults}. */
+public interface FutureSearchResults extends Closeable {
+
+    /** Converts a failed app search result codes into an exception. */
+    @NonNull
+    public static Exception failedResultToException(@NonNull AppSearchResult<?> appSearchResult) {
+        return switch (appSearchResult.getResultCode()) {
+            case AppSearchResult.RESULT_INVALID_ARGUMENT ->
+                    new IllegalArgumentException(appSearchResult.getErrorMessage());
+            case AppSearchResult.RESULT_IO_ERROR ->
+                    new IOException(appSearchResult.getErrorMessage());
+            case AppSearchResult.RESULT_SECURITY_ERROR ->
+                    new SecurityException(appSearchResult.getErrorMessage());
+            default -> new IllegalStateException(appSearchResult.getErrorMessage());
+        };
+    }
+
+    /**
+     * Retrieves the next page of {@link SearchResult} objects from the {@link AppSearchSession}
+     * database.
+     *
+     * <p>Continue calling this method to access results until it returns an empty list, signifying
+     * there are no more results.
+     */
+    AndroidFuture<List<SearchResult>> getNextPage();
+
+    @Override
+    void close();
+}
diff --git a/services/appfunctions/java/com/android/server/appfunctions/FutureSearchResultsImpl.java b/services/appfunctions/java/com/android/server/appfunctions/FutureSearchResultsImpl.java
new file mode 100644
index 0000000..c8bc538
--- /dev/null
+++ b/services/appfunctions/java/com/android/server/appfunctions/FutureSearchResultsImpl.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.appfunctions;
+
+import android.annotation.NonNull;
+import android.app.appsearch.AppSearchResult;
+import android.app.appsearch.AppSearchSession;
+import android.app.appsearch.SearchResult;
+import android.app.appsearch.SearchResults;
+
+import com.android.internal.infra.AndroidFuture;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.concurrent.Executor;
+
+public class FutureSearchResultsImpl implements FutureSearchResults {
+    private final SearchResults mSearchResults;
+    private final Executor mExecutor;
+
+    public FutureSearchResultsImpl(
+            @NonNull SearchResults searchResults, @NonNull Executor executor) {
+        this.mSearchResults = searchResults;
+        this.mExecutor = executor;
+    }
+
+    @Override
+    public AndroidFuture<List<SearchResult>> getNextPage() {
+        AndroidFuture<AppSearchResult<List<SearchResult>>> nextPageFuture = new AndroidFuture<>();
+
+        mSearchResults.getNextPage(mExecutor, nextPageFuture::complete);
+        return nextPageFuture
+                .thenApply(
+                        result -> {
+                            if (result.isSuccess()) {
+                                return result.getResultValue();
+                            } else {
+                                throw new RuntimeException(
+                                        FutureSearchResults.failedResultToException(result));
+                            }
+                        });
+    }
+
+    @Override
+    public void close() {
+        mSearchResults.close();
+    }
+}
diff --git a/services/appfunctions/java/com/android/server/appfunctions/MetadataSyncAdapter.java b/services/appfunctions/java/com/android/server/appfunctions/MetadataSyncAdapter.java
index d84b205..96be769 100644
--- a/services/appfunctions/java/com/android/server/appfunctions/MetadataSyncAdapter.java
+++ b/services/appfunctions/java/com/android/server/appfunctions/MetadataSyncAdapter.java
@@ -45,7 +45,6 @@
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.infra.AndroidFuture;
-import com.android.server.appfunctions.FutureAppSearchSession.FutureSearchResults;
 
 import java.security.MessageDigest;
 import java.security.NoSuchAlgorithmException;
@@ -421,26 +420,29 @@
         Objects.requireNonNull(propertyPackageName);
         ArrayMap<String, ArraySet<String>> packageToFunctionIds = new ArrayMap<>();
 
-        FutureSearchResults futureSearchResults =
+        try (FutureSearchResults futureSearchResults =
                 searchSession
                         .search(
                                 "",
                                 buildMetadataSearchSpec(
                                         schemaType, propertyFunctionId, propertyPackageName))
-                        .get();
-        List<SearchResult> searchResultsList = futureSearchResults.getNextPage().get();
-        // TODO(b/357551503): This could be expensive if we have more functions
-        while (!searchResultsList.isEmpty()) {
-            for (SearchResult searchResult : searchResultsList) {
-                String packageName =
-                        searchResult.getGenericDocument().getPropertyString(propertyPackageName);
-                String functionId =
-                        searchResult.getGenericDocument().getPropertyString(propertyFunctionId);
-                packageToFunctionIds
-                        .computeIfAbsent(packageName, k -> new ArraySet<>())
-                        .add(functionId);
+                        .get(); ) {
+            List<SearchResult> searchResultsList = futureSearchResults.getNextPage().get();
+            // TODO(b/357551503): This could be expensive if we have more functions
+            while (!searchResultsList.isEmpty()) {
+                for (SearchResult searchResult : searchResultsList) {
+                    String packageName =
+                            searchResult
+                                    .getGenericDocument()
+                                    .getPropertyString(propertyPackageName);
+                    String functionId =
+                            searchResult.getGenericDocument().getPropertyString(propertyFunctionId);
+                    packageToFunctionIds
+                            .computeIfAbsent(packageName, k -> new ArraySet<>())
+                            .add(functionId);
+                }
+                searchResultsList = futureSearchResults.getNextPage().get();
             }
-            searchResultsList = futureSearchResults.getNextPage().get();
         }
         return packageToFunctionIds;
     }
diff --git a/services/appfunctions/java/com/android/server/appfunctions/RunAppFunctionServiceCallback.java b/services/appfunctions/java/com/android/server/appfunctions/RunAppFunctionServiceCallback.java
index 7820390..129be65 100644
--- a/services/appfunctions/java/com/android/server/appfunctions/RunAppFunctionServiceCallback.java
+++ b/services/appfunctions/java/com/android/server/appfunctions/RunAppFunctionServiceCallback.java
@@ -27,17 +27,17 @@
 import com.android.server.appfunctions.RemoteServiceCaller.RunServiceCallCallback;
 import com.android.server.appfunctions.RemoteServiceCaller.ServiceUsageCompleteListener;
 
-
 /**
  * A callback to forward a request to the {@link IAppFunctionService} and report back the result.
  */
 public class RunAppFunctionServiceCallback implements RunServiceCallCallback<IAppFunctionService> {
+    private static final String TAG = RunAppFunctionServiceCallback.class.getSimpleName();
 
     private final ExecuteAppFunctionAidlRequest mRequestInternal;
     private final SafeOneTimeExecuteAppFunctionCallback mSafeExecuteAppFunctionCallback;
     private final ICancellationCallback mCancellationCallback;
 
-    private RunAppFunctionServiceCallback(
+    public RunAppFunctionServiceCallback(
             ExecuteAppFunctionAidlRequest requestInternal,
             ICancellationCallback cancellationCallback,
             SafeOneTimeExecuteAppFunctionCallback safeExecuteAppFunctionCallback) {
@@ -46,21 +46,6 @@
         this.mCancellationCallback = cancellationCallback;
     }
 
-    /**
-     * Creates a new instance of {@link RunAppFunctionServiceCallback}.
-     *
-     * @param requestInternal a request to send to the service.
-     * @param cancellationCallback a callback to forward cancellation signal to the service.
-     * @param safeExecuteAppFunctionCallback a callback to report back the result of the operation.
-     */
-    public static RunAppFunctionServiceCallback create(
-            ExecuteAppFunctionAidlRequest requestInternal,
-            ICancellationCallback cancellationCallback,
-            SafeOneTimeExecuteAppFunctionCallback safeExecuteAppFunctionCallback) {
-        return new RunAppFunctionServiceCallback(
-                requestInternal, cancellationCallback, safeExecuteAppFunctionCallback);
-    }
-
     @Override
     public void onServiceConnected(
             @NonNull IAppFunctionService service,
@@ -68,6 +53,7 @@
         try {
             service.executeAppFunction(
                     mRequestInternal.getClientRequest(),
+                    mRequestInternal.getCallingPackage(),
                     mCancellationCallback,
                     new IExecuteAppFunctionCallback.Stub() {
                         @Override
@@ -88,7 +74,7 @@
 
     @Override
     public void onFailedToConnect() {
-        Slog.e("AppFunctionManagerServiceImpl", "Failed to connect to service");
+        Slog.e(TAG, "Failed to connect to service");
         mSafeExecuteAppFunctionCallback.onResult(
                 ExecuteAppFunctionResponse.newFailure(
                         ExecuteAppFunctionResponse.RESULT_APP_UNKNOWN_ERROR,
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
index 42f69e9..95281c8 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
@@ -676,7 +676,7 @@
 
             final MacAddress macAddressObj = MacAddress.fromString(macAddress);
             mAssociationRequestsProcessor.createAssociation(userId, packageName, macAddressObj,
-                    null, null, null, false, null, null);
+                    null, null, null, false, null, null, null);
         }
 
         private void checkCanCallNotificationApi(String callingPackage, int userId) {
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java b/services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java
index 4fc9d55..2804945 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java
@@ -106,8 +106,8 @@
                     boolean selfManaged = getNextBooleanArg();
                     final MacAddress macAddress = MacAddress.fromString(address);
                     mAssociationRequestsProcessor.createAssociation(userId, packageName, macAddress,
-                            deviceProfile, deviceProfile, /* associatedDevice */ null, selfManaged,
-                            /* callback */ null, /* resultReceiver */ null);
+                            deviceProfile, deviceProfile, /* associatedDevice */ null, false,
+                            /* callback */ null, /* resultReceiver */ null, /* deviceIcon */ null);
                 }
                 break;
 
diff --git a/services/companion/java/com/android/server/companion/association/AssociationDiskStore.java b/services/companion/java/com/android/server/companion/association/AssociationDiskStore.java
index 0c54720..77b1780 100644
--- a/services/companion/java/com/android/server/companion/association/AssociationDiskStore.java
+++ b/services/companion/java/com/android/server/companion/association/AssociationDiskStore.java
@@ -17,10 +17,12 @@
 package com.android.server.companion.association;
 
 import static com.android.internal.util.XmlUtils.readBooleanAttribute;
+import static com.android.internal.util.XmlUtils.readByteArrayAttribute;
 import static com.android.internal.util.XmlUtils.readIntAttribute;
 import static com.android.internal.util.XmlUtils.readLongAttribute;
 import static com.android.internal.util.XmlUtils.readStringAttribute;
 import static com.android.internal.util.XmlUtils.writeBooleanAttribute;
+import static com.android.internal.util.XmlUtils.writeByteArrayAttribute;
 import static com.android.internal.util.XmlUtils.writeIntAttribute;
 import static com.android.internal.util.XmlUtils.writeLongAttribute;
 import static com.android.internal.util.XmlUtils.writeStringAttribute;
@@ -36,6 +38,7 @@
 import android.annotation.SuppressLint;
 import android.annotation.UserIdInt;
 import android.companion.AssociationInfo;
+import android.graphics.drawable.Icon;
 import android.net.MacAddress;
 import android.os.Environment;
 import android.util.AtomicFile;
@@ -51,6 +54,7 @@
 import org.xmlpull.v1.XmlSerializer;
 
 import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.IOException;
@@ -172,6 +176,7 @@
     private static final String XML_ATTR_TIME_APPROVED = "time_approved";
     private static final String XML_ATTR_LAST_TIME_CONNECTED = "last_time_connected";
     private static final String XML_ATTR_SYSTEM_DATA_SYNC_FLAGS = "system_data_sync_flags";
+    private static final String XML_ATTR_DEVICE_ICON = "device_icon";
 
     private static final String LEGACY_XML_ATTR_DEVICE = "device";
 
@@ -393,7 +398,7 @@
         return new AssociationInfo(associationId, userId, appPackage, tag,
                 MacAddress.fromString(deviceAddress), null, profile, null,
                 /* managedByCompanionApp */ false, notify, /* revoked */ false, /* pending */ false,
-                timeApproved, Long.MAX_VALUE, /* systemDataSyncFlags */ 0);
+                timeApproved, Long.MAX_VALUE, /* systemDataSyncFlags */ 0, null);
     }
 
     private static Associations readAssociationsV1(@NonNull TypedXmlPullParser parser,
@@ -444,10 +449,12 @@
                 parser, XML_ATTR_LAST_TIME_CONNECTED, Long.MAX_VALUE);
         final int systemDataSyncFlags = readIntAttribute(parser,
                 XML_ATTR_SYSTEM_DATA_SYNC_FLAGS, 0);
+        final Icon deviceIcon = byteArrayToIcon(
+                readByteArrayAttribute(parser, XML_ATTR_DEVICE_ICON));
 
         return new AssociationInfo(associationId, userId, appPackage, tag, macAddress, displayName,
                 profile, null, selfManaged, notify, revoked, pending, timeApproved,
-                lastTimeConnected, systemDataSyncFlags);
+                lastTimeConnected, systemDataSyncFlags, deviceIcon);
     }
 
     private static void writeAssociations(@NonNull XmlSerializer parent,
@@ -480,6 +487,8 @@
         writeLongAttribute(
                 serializer, XML_ATTR_LAST_TIME_CONNECTED, a.getLastTimeConnectedMs());
         writeIntAttribute(serializer, XML_ATTR_SYSTEM_DATA_SYNC_FLAGS, a.getSystemDataSyncFlags());
+        writeByteArrayAttribute(
+                serializer, XML_ATTR_DEVICE_ICON, iconToByteArray(a.getDeviceIcon()));
 
         serializer.endTag(null, XML_TAG_ASSOCIATION);
     }
@@ -494,4 +503,24 @@
     private static @Nullable MacAddress stringToMacAddress(@Nullable String address) {
         return address != null ? MacAddress.fromString(address) : null;
     }
+
+    private static byte[] iconToByteArray(Icon deviceIcon)
+            throws IOException {
+        if (deviceIcon == null) {
+            return null;
+        }
+
+        ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
+        deviceIcon.writeToStream(byteStream);
+        return byteStream.toByteArray();
+    }
+
+    private static Icon byteArrayToIcon(byte[] bytes) throws IOException {
+        if (bytes == null) {
+            return null;
+        }
+
+        ByteArrayInputStream byteStream = new ByteArrayInputStream(bytes);
+        return Icon.createFromStream(byteStream);
+    }
 }
diff --git a/services/companion/java/com/android/server/companion/association/AssociationRequestsProcessor.java b/services/companion/java/com/android/server/companion/association/AssociationRequestsProcessor.java
index d56f17b..aebd11a 100644
--- a/services/companion/java/com/android/server/companion/association/AssociationRequestsProcessor.java
+++ b/services/companion/java/com/android/server/companion/association/AssociationRequestsProcessor.java
@@ -48,6 +48,7 @@
 import android.content.Intent;
 import android.content.IntentSender;
 import android.content.pm.PackageManagerInternal;
+import android.graphics.drawable.Icon;
 import android.net.MacAddress;
 import android.os.Binder;
 import android.os.Bundle;
@@ -281,7 +282,7 @@
             createAssociation(userId, packageName, macAddress, request.getDisplayName(),
                     request.getDeviceProfile(), request.getAssociatedDevice(),
                     request.isSelfManaged(),
-                    callback, resultReceiver);
+                    callback, resultReceiver, request.getDeviceIcon());
         });
     }
 
@@ -292,15 +293,15 @@
             @Nullable MacAddress macAddress, @Nullable CharSequence displayName,
             @Nullable String deviceProfile, @Nullable AssociatedDevice associatedDevice,
             boolean selfManaged, @Nullable IAssociationRequestCallback callback,
-            @Nullable ResultReceiver resultReceiver) {
+            @Nullable ResultReceiver resultReceiver, @Nullable Icon deviceIcon) {
         final int id = mAssociationStore.getNextId();
         final long timestamp = System.currentTimeMillis();
 
         final AssociationInfo association = new AssociationInfo(id, userId, packageName,
                 /* tag */ null, macAddress, displayName, deviceProfile, associatedDevice,
                 selfManaged, /* notifyOnDeviceNearby */ false, /* revoked */ false,
-                /* pending */ false, timestamp, Long.MAX_VALUE, /* systemDataSyncFlags */ 0);
-
+                /* pending */ false, timestamp, Long.MAX_VALUE, /* systemDataSyncFlags */ 0,
+                deviceIcon);
         // Add role holder for association (if specified) and add new association to store.
         maybeGrantRoleAndStoreAssociation(association, callback, resultReceiver);
     }
diff --git a/services/companion/java/com/android/server/companion/association/DisassociationProcessor.java b/services/companion/java/com/android/server/companion/association/DisassociationProcessor.java
index 6f0baef..150e8da 100644
--- a/services/companion/java/com/android/server/companion/association/DisassociationProcessor.java
+++ b/services/companion/java/com/android/server/companion/association/DisassociationProcessor.java
@@ -16,7 +16,7 @@
 
 package com.android.server.companion.association;
 
-import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE;
+import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
 import static android.companion.AssociationRequest.DEVICE_PROFILE_AUTOMOTIVE_PROJECTION;
 
 import static com.android.internal.util.CollectionUtils.any;
@@ -107,7 +107,7 @@
                     it -> deviceProfile.equals(it.getDeviceProfile()) && id != it.getId());
 
         final int packageProcessImportance = getPackageProcessImportance(userId, packageName);
-        if (packageProcessImportance <= IMPORTANCE_VISIBLE && deviceProfile != null
+        if (packageProcessImportance <= IMPORTANCE_FOREGROUND && deviceProfile != null
                 && !isRoleInUseByOtherAssociations) {
             // Need to remove the app from the list of role holders, but the process is visible
             // to the user at the moment, so we'll need to do it later.
@@ -238,12 +238,16 @@
      */
     private class OnPackageVisibilityChangeListener implements
             ActivityManager.OnUidImportanceListener {
-
+        // This method is called when the importance of a uid (app) changes.
+        // We only care about changes where the app is moving to the background.
+        // (e.g., the app currently is not at the top of the screen that the user
+        // is interacting with.)
         @Override
         public void onUidImportance(int uid, int importance) {
-            if (importance <= ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE) {
-                // The lower the importance value the more "important" the process is.
-                // We are only interested when the process ceases to be visible.
+            // Higher importance values indicate the app is less important.
+            // We are only interested when the process importance level
+            // is greater than IMPORTANCE_FOREGROUND.
+            if (importance <= IMPORTANCE_FOREGROUND) {
                 return;
             }
 
diff --git a/services/companion/java/com/android/server/companion/utils/PermissionsUtils.java b/services/companion/java/com/android/server/companion/utils/PermissionsUtils.java
index c927cd0..f37e0c9 100644
--- a/services/companion/java/com/android/server/companion/utils/PermissionsUtils.java
+++ b/services/companion/java/com/android/server/companion/utils/PermissionsUtils.java
@@ -86,7 +86,7 @@
             @NonNull AssociationRequest request, int packageUid) {
         enforcePermissionForRequestingProfile(context, request.getDeviceProfile(), packageUid);
 
-        if (request.isSelfManaged()) {
+        if (request.isSelfManaged() || request.getDeviceIcon() != null) {
             enforcePermissionForRequestingSelfManaged(context, packageUid);
         }
     }
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 81ae717..281a2ce 100644
--- a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java
+++ b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java
@@ -16,10 +16,13 @@
 
 package com.android.server.companion.virtual;
 
+import static android.Manifest.permission.ADD_ALWAYS_UNLOCKED_DISPLAY;
+import static android.Manifest.permission.ADD_TRUSTED_DISPLAY;
 import static android.app.admin.DevicePolicyManager.NEARBY_STREAMING_ENABLED;
 import static android.app.admin.DevicePolicyManager.NEARBY_STREAMING_NOT_CONTROLLED_BY_POLICY;
 import static android.app.admin.DevicePolicyManager.NEARBY_STREAMING_SAME_MANAGED_ACCOUNT_ONLY;
 import static android.companion.virtual.VirtualDeviceParams.ACTIVITY_POLICY_DEFAULT_ALLOWED;
+import static android.companion.virtual.VirtualDeviceParams.DEVICE_POLICY_CUSTOM;
 import static android.companion.virtual.VirtualDeviceParams.DEVICE_POLICY_DEFAULT;
 import static android.companion.virtual.VirtualDeviceParams.NAVIGATION_POLICY_DEFAULT_ALLOWED;
 import static android.companion.virtual.VirtualDeviceParams.POLICY_TYPE_ACTIVITY;
@@ -30,7 +33,6 @@
 import static android.companion.virtual.VirtualDeviceParams.POLICY_TYPE_RECENTS;
 import static android.companion.virtualdevice.flags.Flags.virtualCameraServiceDiscovery;
 
-import android.annotation.EnforcePermission;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
@@ -95,10 +97,10 @@
 import android.os.IBinder;
 import android.os.LocaleList;
 import android.os.Looper;
-import android.os.PermissionEnforcer;
 import android.os.PowerManager;
 import android.os.RemoteException;
 import android.os.ResultReceiver;
+import android.os.SystemClock;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.util.ArrayMap;
@@ -203,6 +205,7 @@
     private IVirtualDeviceSoundEffectListener mSoundEffectListener;
     private final DisplayManagerGlobal mDisplayManager;
     private final DisplayManagerInternal mDisplayManagerInternal;
+    private final PowerManager mPowerManager;
     @GuardedBy("mVirtualDeviceLock")
     private final Map<IBinder, IntentFilter> mIntentInterceptors = new ArrayMap<>();
     @NonNull
@@ -213,6 +216,10 @@
     @GuardedBy("mVirtualDeviceLock")
     @Nullable
     private LocaleList mLocaleList = null;
+    @GuardedBy("mVirtualDeviceLock")
+    private boolean mLockdownActive = false;
+    @GuardedBy("mVirtualDeviceLock")
+    private boolean mRequestedToBeAwake = true;
 
     @NonNull
     private final VirtualDevice mPublicVirtualDeviceObject;
@@ -396,7 +403,6 @@
             VirtualDeviceParams params,
             DisplayManagerGlobal displayManager,
             VirtualCameraController virtualCameraController) {
-        super(PermissionEnforcer.fromContext(context));
         mVirtualDeviceLog = virtualDeviceLog;
         mOwnerPackageName = attributionSource.getPackageName();
         mAttributionSource = attributionSource;
@@ -418,6 +424,28 @@
         mDevicePolicies = params.getDevicePolicies();
         mDisplayManager = displayManager;
         mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class);
+        mPowerManager = context.getSystemService(PowerManager.class);
+
+        if (mDevicePolicies.get(POLICY_TYPE_CLIPBOARD, DEVICE_POLICY_DEFAULT)
+                != DEVICE_POLICY_DEFAULT) {
+            if (mContext.checkCallingOrSelfPermission(ADD_TRUSTED_DISPLAY)
+                    != PackageManager.PERMISSION_GRANTED) {
+                throw new SecurityException("Requires ADD_TRUSTED_DISPLAY permission to "
+                        + "set a custom clipboard policy.");
+            }
+        }
+
+        int flags = DEFAULT_VIRTUAL_DISPLAY_FLAGS;
+        if (mParams.getLockState() == VirtualDeviceParams.LOCK_STATE_ALWAYS_UNLOCKED) {
+            if (mContext.checkCallingOrSelfPermission(ADD_ALWAYS_UNLOCKED_DISPLAY)
+                    != PackageManager.PERMISSION_GRANTED) {
+                throw new SecurityException("Requires ADD_ALWAYS_UNLOCKED_DISPLAY permission to "
+                        + "create an always unlocked virtual device.");
+            }
+            flags |= DisplayManager.VIRTUAL_DISPLAY_FLAG_ALWAYS_UNLOCKED;
+        }
+        mBaseVirtualDisplayFlags = flags;
+
         if (inputController == null) {
             mInputController = new InputController(
                     context.getMainThreadHandler(),
@@ -460,12 +488,6 @@
                             : mParams.getAllowedActivities();
         }
 
-        int flags = DEFAULT_VIRTUAL_DISPLAY_FLAGS;
-        if (mParams.getLockState() == VirtualDeviceParams.LOCK_STATE_ALWAYS_UNLOCKED) {
-            flags |= DisplayManager.VIRTUAL_DISPLAY_FLAG_ALWAYS_UNLOCKED;
-        }
-        mBaseVirtualDisplayFlags = flags;
-
         if (Flags.vdmCustomIme() && mParams.getInputMethodComponent() != null) {
             final String imeId = mParams.getInputMethodComponent().flattenToShortString();
             Slog.d(TAG, "Setting custom input method " + imeId + " as default for virtual device "
@@ -475,6 +497,20 @@
         }
     }
 
+    void onLockdownChanged(boolean lockdownActive) {
+        synchronized (mVirtualDeviceLock) {
+            if (lockdownActive != mLockdownActive) {
+                mLockdownActive = lockdownActive;
+                if (mLockdownActive) {
+                    goToSleepInternal(PowerManager.GO_TO_SLEEP_REASON_DISPLAY_GROUPS_TURNED_OFF);
+                } else if (mRequestedToBeAwake) {
+                    wakeUpInternal(PowerManager.WAKE_REASON_DISPLAY_GROUP_TURNED_ON,
+                            "android.server.companion.virtual:LOCKDOWN_ENDED");
+                }
+            }
+        }
+    }
+
     @VisibleForTesting
     SensorController getSensorControllerForTest() {
         return mSensorController;
@@ -526,10 +562,8 @@
      * object is created before the returned VirtualDeviceInternal one.
      */
     @Override // Binder call
-    @EnforcePermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
     public void setListeners(@NonNull IVirtualDeviceActivityListener activityListener,
             @NonNull IVirtualDeviceSoundEffectListener soundEffectListener) {
-        super.setListeners_enforcePermission();
         mActivityListener = Objects.requireNonNull(activityListener);
         mSoundEffectListener = Objects.requireNonNull(soundEffectListener);
     }
@@ -576,14 +610,45 @@
     }
 
     @Override // Binder call
+    public void goToSleep() {
+        checkCallerIsDeviceOwner();
+        synchronized (mVirtualDeviceLock) {
+            mRequestedToBeAwake = false;
+        }
+        final long ident = Binder.clearCallingIdentity();
+        try {
+            goToSleepInternal(PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON);
+        } finally {
+            Binder.restoreCallingIdentity(ident);
+        }
+    }
+
+    @Override // Binder call
+    public void wakeUp() {
+        checkCallerIsDeviceOwner();
+        synchronized (mVirtualDeviceLock) {
+            mRequestedToBeAwake = true;
+            if (mLockdownActive) {
+                Slog.w(TAG, "Cannot wake up device during lockdown.");
+                return;
+            }
+        }
+        final long ident = Binder.clearCallingIdentity();
+        try {
+            wakeUpInternal(PowerManager.WAKE_REASON_POWER_BUTTON,
+                    "android.server.companion.virtual:DEVICE_ON");
+        } finally {
+            Binder.restoreCallingIdentity(ident);
+        }
+    }
+
+    @Override // Binder call
     public void launchPendingIntent(int displayId, PendingIntent pendingIntent,
             ResultReceiver resultReceiver) {
+        checkCallerIsDeviceOwner();
         Objects.requireNonNull(pendingIntent);
         synchronized (mVirtualDeviceLock) {
-            if (!mVirtualDisplays.contains(displayId)) {
-                throw new SecurityException("Display ID " + displayId
-                        + " not found for this virtual device");
-            }
+            checkDisplayOwnedByVirtualDeviceLocked(displayId);
         }
         if (pendingIntent.isActivity()) {
             try {
@@ -615,9 +680,8 @@
     }
 
     @Override // Binder call
-    @EnforcePermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
     public void addActivityPolicyExemption(@NonNull ActivityPolicyExemption exemption) {
-        super.addActivityPolicyExemption_enforcePermission();
+        checkCallerIsDeviceOwner();
         final int displayId = exemption.getDisplayId();
         if (exemption.getComponentName() == null || displayId != Display.INVALID_DISPLAY) {
             if (!android.companion.virtualdevice.flags.Flags.activityControlApi()) {
@@ -653,9 +717,8 @@
     }
 
     @Override // Binder call
-    @EnforcePermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
     public void removeActivityPolicyExemption(@NonNull ActivityPolicyExemption exemption) {
-        super.removeActivityPolicyExemption_enforcePermission();
+        checkCallerIsDeviceOwner();
         final int displayId = exemption.getDisplayId();
         if (exemption.getComponentName() == null || displayId != Display.INVALID_DISPLAY) {
             if (!android.companion.virtualdevice.flags.Flags.activityControlApi()) {
@@ -706,9 +769,7 @@
     }
 
     @Override // Binder call
-    @EnforcePermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
     public void close() {
-        super.close_enforcePermission();
         // Remove about-to-be-closed virtual device from the service before butchering it.
         if (!mService.removeVirtualDevice(mDeviceId)) {
             // Device is already closed.
@@ -783,11 +844,10 @@
     }
 
     @Override // Binder call
-    @EnforcePermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
     public void onAudioSessionStarting(int displayId,
             @NonNull IAudioRoutingCallback routingCallback,
             @Nullable IAudioConfigChangedCallback configChangedCallback) {
-        super.onAudioSessionStarting_enforcePermission();
+        checkCallerIsDeviceOwner();
         synchronized (mVirtualDeviceLock) {
             checkDisplayOwnedByVirtualDeviceLocked(displayId);
             if (mVirtualAudioController == null) {
@@ -801,9 +861,8 @@
     }
 
     @Override // Binder call
-    @EnforcePermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
     public void onAudioSessionEnded() {
-        super.onAudioSessionEnded_enforcePermission();
+        checkCallerIsDeviceOwner();
         synchronized (mVirtualDeviceLock) {
             if (mVirtualAudioController != null) {
                 mVirtualAudioController.stopListening();
@@ -813,10 +872,9 @@
     }
 
     @Override // Binder call
-    @EnforcePermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
     public void setDevicePolicy(@VirtualDeviceParams.DynamicPolicyType int policyType,
             @VirtualDeviceParams.DevicePolicy int devicePolicy) {
-        super.setDevicePolicy_enforcePermission();
+        checkCallerIsDeviceOwner();
         if (!Flags.dynamicPolicy()) {
             return;
         }
@@ -826,8 +884,12 @@
                 synchronized (mVirtualDeviceLock) {
                     mDevicePolicies.put(policyType, devicePolicy);
                     for (int i = 0; i < mVirtualDisplays.size(); i++) {
-                        mVirtualDisplays.valueAt(i).getWindowPolicyController()
-                                .setShowInHostDeviceRecents(devicePolicy == DEVICE_POLICY_DEFAULT);
+                        VirtualDisplayWrapper wrapper = mVirtualDisplays.valueAt(i);
+                        if (wrapper.isTrusted()) {
+                            wrapper.getWindowPolicyController()
+                                    .setShowInHostDeviceRecents(
+                                            devicePolicy == DEVICE_POLICY_DEFAULT);
+                        }
                     }
                 }
                 break;
@@ -847,7 +909,20 @@
                 break;
             case POLICY_TYPE_CLIPBOARD:
                 if (Flags.crossDeviceClipboard()) {
+                    if (devicePolicy == DEVICE_POLICY_CUSTOM
+                            && mContext.checkCallingOrSelfPermission(ADD_TRUSTED_DISPLAY)
+                            != PackageManager.PERMISSION_GRANTED) {
+                        throw new SecurityException("Requires ADD_TRUSTED_DISPLAY permission to "
+                                + "set a custom clipboard policy.");
+                    }
                     synchronized (mVirtualDeviceLock) {
+                        for (int i = 0; i < mVirtualDisplays.size(); i++) {
+                            VirtualDisplayWrapper wrapper = mVirtualDisplays.valueAt(i);
+                            if (!wrapper.isTrusted() && !wrapper.isMirror()) {
+                                throw new SecurityException("All displays must be trusted for "
+                                        + "devices with custom clipboard policy.");
+                            }
+                        }
                         mDevicePolicies.put(policyType, devicePolicy);
                     }
                 }
@@ -866,11 +941,10 @@
     }
 
     @Override // Binder call
-    @EnforcePermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
     public void setDevicePolicyForDisplay(int displayId,
             @VirtualDeviceParams.DynamicDisplayPolicyType int policyType,
             @VirtualDeviceParams.DevicePolicy int devicePolicy) {
-        super.setDevicePolicyForDisplay_enforcePermission();
+        checkCallerIsDeviceOwner();
         if (!android.companion.virtualdevice.flags.Flags.activityControlApi()) {
             return;
         }
@@ -878,8 +952,11 @@
             checkDisplayOwnedByVirtualDeviceLocked(displayId);
             switch (policyType) {
                 case POLICY_TYPE_RECENTS:
-                    mVirtualDisplays.get(displayId).getWindowPolicyController()
-                            .setShowInHostDeviceRecents(devicePolicy == DEVICE_POLICY_DEFAULT);
+                    VirtualDisplayWrapper wrapper = mVirtualDisplays.get(displayId);
+                    if (wrapper.isTrusted()) {
+                        wrapper.getWindowPolicyController()
+                                .setShowInHostDeviceRecents(devicePolicy == DEVICE_POLICY_DEFAULT);
+                    }
                     break;
                 case POLICY_TYPE_ACTIVITY:
                     mVirtualDisplays.get(displayId).getWindowPolicyController()
@@ -893,9 +970,8 @@
     }
 
     @Override // Binder call
-    @EnforcePermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
     public void createVirtualDpad(VirtualDpadConfig config, @NonNull IBinder deviceToken) {
-        super.createVirtualDpad_enforcePermission();
+        checkCallerIsDeviceOwner();
         Objects.requireNonNull(config);
         checkVirtualInputDeviceDisplayIdAssociation(config.getAssociatedDisplayId());
         final long ident = Binder.clearCallingIdentity();
@@ -911,9 +987,8 @@
     }
 
     @Override // Binder call
-    @EnforcePermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
     public void createVirtualKeyboard(VirtualKeyboardConfig config, @NonNull IBinder deviceToken) {
-        super.createVirtualKeyboard_enforcePermission();
+        checkCallerIsDeviceOwner();
         Objects.requireNonNull(config);
         checkVirtualInputDeviceDisplayIdAssociation(config.getAssociatedDisplayId());
         final long ident = Binder.clearCallingIdentity();
@@ -933,9 +1008,8 @@
     }
 
     @Override // Binder call
-    @EnforcePermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
     public void createVirtualMouse(VirtualMouseConfig config, @NonNull IBinder deviceToken) {
-        super.createVirtualMouse_enforcePermission();
+        checkCallerIsDeviceOwner();
         Objects.requireNonNull(config);
         checkVirtualInputDeviceDisplayIdAssociation(config.getAssociatedDisplayId());
         final long ident = Binder.clearCallingIdentity();
@@ -950,10 +1024,9 @@
     }
 
     @Override // Binder call
-    @EnforcePermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
     public void createVirtualTouchscreen(VirtualTouchscreenConfig config,
             @NonNull IBinder deviceToken) {
-        super.createVirtualTouchscreen_enforcePermission();
+        checkCallerIsDeviceOwner();
         Objects.requireNonNull(config);
         checkVirtualInputDeviceDisplayIdAssociation(config.getAssociatedDisplayId());
         final long ident = Binder.clearCallingIdentity();
@@ -969,10 +1042,9 @@
     }
 
     @Override // Binder call
-    @EnforcePermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
     public void createVirtualNavigationTouchpad(VirtualNavigationTouchpadConfig config,
             @NonNull IBinder deviceToken) {
-        super.createVirtualNavigationTouchpad_enforcePermission();
+        checkCallerIsDeviceOwner();
         Objects.requireNonNull(config);
         checkVirtualInputDeviceDisplayIdAssociation(config.getAssociatedDisplayId());
         final long ident = Binder.clearCallingIdentity();
@@ -990,10 +1062,9 @@
     }
 
     @Override // Binder call
-    @EnforcePermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
     public void createVirtualStylus(@NonNull VirtualStylusConfig config,
             @NonNull IBinder deviceToken) {
-        super.createVirtualStylus_enforcePermission();
+        checkCallerIsDeviceOwner();
         Objects.requireNonNull(config);
         Objects.requireNonNull(deviceToken);
         checkVirtualInputDeviceDisplayIdAssociation(config.getAssociatedDisplayId());
@@ -1010,10 +1081,9 @@
     }
 
     @Override // Binder call
-    @EnforcePermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
     public void createVirtualRotaryEncoder(@NonNull VirtualRotaryEncoderConfig config,
             @NonNull IBinder deviceToken) {
-        super.createVirtualRotaryEncoder_enforcePermission();
+        checkCallerIsDeviceOwner();
         Objects.requireNonNull(config);
         Objects.requireNonNull(deviceToken);
         checkVirtualInputDeviceDisplayIdAssociation(config.getAssociatedDisplayId());
@@ -1030,9 +1100,8 @@
     }
 
     @Override // Binder call
-    @EnforcePermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
     public void unregisterInputDevice(IBinder token) {
-        super.unregisterInputDevice_enforcePermission();
+        checkCallerIsDeviceOwner();
         final long ident = Binder.clearCallingIdentity();
         try {
             mInputController.unregisterInputDevice(token);
@@ -1053,9 +1122,8 @@
 
 
     @Override // Binder call
-    @EnforcePermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
     public boolean sendDpadKeyEvent(IBinder token, VirtualKeyEvent event) {
-        super.sendDpadKeyEvent_enforcePermission();
+        checkCallerIsDeviceOwner();
         final long ident = Binder.clearCallingIdentity();
         try {
             return mInputController.sendDpadKeyEvent(token, event);
@@ -1065,9 +1133,8 @@
     }
 
     @Override // Binder call
-    @EnforcePermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
     public boolean sendKeyEvent(IBinder token, VirtualKeyEvent event) {
-        super.sendKeyEvent_enforcePermission();
+        checkCallerIsDeviceOwner();
         final long ident = Binder.clearCallingIdentity();
         try {
             return mInputController.sendKeyEvent(token, event);
@@ -1077,9 +1144,8 @@
     }
 
     @Override // Binder call
-    @EnforcePermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
     public boolean sendButtonEvent(IBinder token, VirtualMouseButtonEvent event) {
-        super.sendButtonEvent_enforcePermission();
+        checkCallerIsDeviceOwner();
         final long ident = Binder.clearCallingIdentity();
         try {
             return mInputController.sendButtonEvent(token, event);
@@ -1089,9 +1155,8 @@
     }
 
     @Override // Binder call
-    @EnforcePermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
     public boolean sendTouchEvent(IBinder token, VirtualTouchEvent event) {
-        super.sendTouchEvent_enforcePermission();
+        checkCallerIsDeviceOwner();
         final long ident = Binder.clearCallingIdentity();
         try {
             return mInputController.sendTouchEvent(token, event);
@@ -1101,9 +1166,8 @@
     }
 
     @Override // Binder call
-    @EnforcePermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
     public boolean sendRelativeEvent(IBinder token, VirtualMouseRelativeEvent event) {
-        super.sendRelativeEvent_enforcePermission();
+        checkCallerIsDeviceOwner();
         final long ident = Binder.clearCallingIdentity();
         try {
             return mInputController.sendRelativeEvent(token, event);
@@ -1113,9 +1177,8 @@
     }
 
     @Override // Binder call
-    @EnforcePermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
     public boolean sendScrollEvent(IBinder token, VirtualMouseScrollEvent event) {
-        super.sendScrollEvent_enforcePermission();
+        checkCallerIsDeviceOwner();
         final long ident = Binder.clearCallingIdentity();
         try {
             return mInputController.sendScrollEvent(token, event);
@@ -1135,10 +1198,9 @@
     }
 
     @Override // Binder call
-    @EnforcePermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
     public boolean sendStylusMotionEvent(@NonNull IBinder token,
             @NonNull VirtualStylusMotionEvent event) {
-        super.sendStylusMotionEvent_enforcePermission();
+        checkCallerIsDeviceOwner();
         Objects.requireNonNull(token);
         Objects.requireNonNull(event);
         final long ident = Binder.clearCallingIdentity();
@@ -1150,10 +1212,9 @@
     }
 
     @Override // Binder call
-    @EnforcePermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
     public boolean sendStylusButtonEvent(@NonNull IBinder token,
             @NonNull VirtualStylusButtonEvent event) {
-        super.sendStylusButtonEvent_enforcePermission();
+        checkCallerIsDeviceOwner();
         Objects.requireNonNull(token);
         Objects.requireNonNull(event);
         final long ident = Binder.clearCallingIdentity();
@@ -1165,10 +1226,9 @@
     }
 
     @Override // Binder call
-    @EnforcePermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
     public boolean sendRotaryEncoderScrollEvent(@NonNull IBinder token,
             @NonNull VirtualRotaryEncoderScrollEvent event) {
-        super.sendRotaryEncoderScrollEvent_enforcePermission();
+        checkCallerIsDeviceOwner();
         final long ident = Binder.clearCallingIdentity();
         try {
             return mInputController.sendRotaryEncoderScrollEvent(token, event);
@@ -1178,17 +1238,19 @@
     }
 
     @Override // Binder call
-    @EnforcePermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
     public void setShowPointerIcon(boolean showPointerIcon) {
-        super.setShowPointerIcon_enforcePermission();
+        checkCallerIsDeviceOwner();
         final long ident = Binder.clearCallingIdentity();
         try {
             synchronized (mVirtualDeviceLock) {
                 mDefaultShowPointerIcon = showPointerIcon;
-            }
-            final int[] displayIds = getDisplayIds();
-            for (int i = 0; i < displayIds.length; ++i) {
-                mInputController.setShowPointerIcon(showPointerIcon, displayIds[i]);
+                for (int i = 0; i < mVirtualDisplays.size(); i++) {
+                    VirtualDisplayWrapper wrapper = mVirtualDisplays.valueAt(i);
+                    if (wrapper.isTrusted() || wrapper.isMirror()) {
+                        mInputController.setShowPointerIcon(
+                                mDefaultShowPointerIcon, mVirtualDisplays.keyAt(i));
+                    }
+                }
             }
         } finally {
             Binder.restoreCallingIdentity(ident);
@@ -1196,14 +1258,10 @@
     }
 
     @Override // Binder call
-    @EnforcePermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
     public void setDisplayImePolicy(int displayId, @WindowManager.DisplayImePolicy int policy) {
-        super.setDisplayImePolicy_enforcePermission();
+        checkCallerIsDeviceOwner();
         synchronized (mVirtualDeviceLock) {
-            if (!mVirtualDisplays.contains(displayId)) {
-                throw new SecurityException("Display ID " + displayId
-                        + " not found for this virtual device");
-            }
+            checkDisplayOwnedByVirtualDeviceLocked(displayId);
         }
         final long ident = Binder.clearCallingIdentity();
         try {
@@ -1214,10 +1272,9 @@
     }
 
     @Override // Binder call
-    @EnforcePermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
     @Nullable
     public List<VirtualSensor> getVirtualSensorList() {
-        super.getVirtualSensorList_enforcePermission();
+        checkCallerIsDeviceOwner();
         return mSensorController.getSensorList();
     }
 
@@ -1227,9 +1284,8 @@
     }
 
     @Override // Binder call
-    @EnforcePermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
     public boolean sendSensorEvent(@NonNull IBinder token, @NonNull VirtualSensorEvent event) {
-        super.sendSensorEvent_enforcePermission();
+        checkCallerIsDeviceOwner();
         final long ident = Binder.clearCallingIdentity();
         try {
             return mSensorController.sendSensorEvent(token, event);
@@ -1239,10 +1295,9 @@
     }
 
     @Override // Binder call
-    @EnforcePermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
     public void registerIntentInterceptor(IVirtualDeviceIntentInterceptor intentInterceptor,
             IntentFilter filter) {
-        super.registerIntentInterceptor_enforcePermission();
+        checkCallerIsDeviceOwner();
         Objects.requireNonNull(intentInterceptor);
         Objects.requireNonNull(filter);
         synchronized (mVirtualDeviceLock) {
@@ -1251,10 +1306,9 @@
     }
 
     @Override // Binder call
-    @EnforcePermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
     public void unregisterIntentInterceptor(
             @NonNull IVirtualDeviceIntentInterceptor intentInterceptor) {
-        super.unregisterIntentInterceptor_enforcePermission();
+        checkCallerIsDeviceOwner();
         Objects.requireNonNull(intentInterceptor);
         synchronized (mVirtualDeviceLock) {
             mIntentInterceptors.remove(intentInterceptor.asBinder());
@@ -1262,10 +1316,9 @@
     }
 
     @Override // Binder call
-    @EnforcePermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
     public void registerVirtualCamera(@NonNull VirtualCameraConfig cameraConfig)
             throws RemoteException {
-        super.registerVirtualCamera_enforcePermission();
+        checkCallerIsDeviceOwner();
         Objects.requireNonNull(cameraConfig);
         if (mVirtualCameraController == null) {
             throw new UnsupportedOperationException("Virtual camera controller is not available");
@@ -1274,10 +1327,9 @@
     }
 
     @Override // Binder call
-    @EnforcePermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
     public void unregisterVirtualCamera(@NonNull VirtualCameraConfig cameraConfig)
             throws RemoteException {
-        super.unregisterVirtualCamera_enforcePermission();
+        checkCallerIsDeviceOwner();
         Objects.requireNonNull(cameraConfig);
         if (mVirtualCameraController == null) {
             throw new UnsupportedOperationException("Virtual camera controller is not available");
@@ -1286,10 +1338,8 @@
     }
 
     @Override // Binder call
-    @EnforcePermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
     public String getVirtualCameraId(@NonNull VirtualCameraConfig cameraConfig)
             throws RemoteException {
-        super.getVirtualCameraId_enforcePermission();
         Objects.requireNonNull(cameraConfig);
         if (mVirtualCameraController == null) {
             throw new UnsupportedOperationException("Virtual camera controller is not available");
@@ -1411,18 +1461,29 @@
         return gwpc;
     }
 
-    int createVirtualDisplay(@NonNull VirtualDisplayConfig virtualDisplayConfig,
-            @NonNull IVirtualDisplayCallback callback, String packageName) {
+    @Override // Binder call
+    public int createVirtualDisplay(@NonNull VirtualDisplayConfig virtualDisplayConfig,
+            @NonNull IVirtualDisplayCallback callback) {
+        checkCallerIsDeviceOwner();
         GenericWindowPolicyController gwpc;
         synchronized (mVirtualDeviceLock) {
             gwpc = createWindowPolicyControllerLocked(virtualDisplayConfig.getDisplayCategories());
         }
         int displayId;
         displayId = mDisplayManagerInternal.createVirtualDisplay(virtualDisplayConfig, callback,
-                this, gwpc, packageName);
+                this, gwpc, mOwnerPackageName);
         boolean isMirrorDisplay =
                 mDisplayManagerInternal.getDisplayIdToMirror(displayId) != Display.INVALID_DISPLAY;
         gwpc.setDisplayId(displayId, isMirrorDisplay);
+        boolean isTrustedDisplay =
+                (mDisplayManagerInternal.getDisplayInfo(displayId).flags & Display.FLAG_TRUSTED)
+                        == Display.FLAG_TRUSTED;
+        if (!isTrustedDisplay) {
+            if (getDevicePolicy(POLICY_TYPE_CLIPBOARD) != DEVICE_POLICY_DEFAULT) {
+                throw new SecurityException("All displays must be trusted for devices with custom"
+                        + "clipboard policy.");
+            }
+        }
 
         boolean showPointer;
         synchronized (mVirtualDeviceLock) {
@@ -1432,22 +1493,24 @@
                         "Virtual device already has a virtual display with ID " + displayId);
             }
 
-            PowerManager.WakeLock wakeLock = createAndAcquireWakeLockForDisplay(displayId);
-            mVirtualDisplays.put(displayId, new VirtualDisplayWrapper(callback, gwpc, wakeLock));
+            PowerManager.WakeLock wakeLock =
+                    isTrustedDisplay ? createAndAcquireWakeLockForDisplay(displayId) : null;
+            mVirtualDisplays.put(displayId, new VirtualDisplayWrapper(callback, gwpc, wakeLock,
+                    isTrustedDisplay, isMirrorDisplay));
             showPointer = mDefaultShowPointerIcon;
         }
 
         final long token = Binder.clearCallingIdentity();
         try {
-            mInputController.setShowPointerIcon(showPointer, displayId);
             mInputController.setMousePointerAccelerationEnabled(false, displayId);
             mInputController.setDisplayEligibilityForPointerCapture(/* isEligible= */ false,
                     displayId);
-            // WM throws a SecurityException if the display is untrusted.
-            if ((mDisplayManagerInternal.getDisplayInfo(displayId).flags & Display.FLAG_TRUSTED)
-                    == Display.FLAG_TRUSTED) {
+            if (isTrustedDisplay) {
+                mInputController.setShowPointerIcon(showPointer, displayId);
                 mInputController.setDisplayImePolicy(displayId,
                         WindowManager.DISPLAY_IME_POLICY_LOCAL);
+            } else {
+                gwpc.setShowInHostDeviceRecents(true);
             }
         } finally {
             Binder.restoreCallingIdentity(token);
@@ -1511,7 +1574,6 @@
         return result;
     }
 
-
     void onVirtualDisplayRemoved(int displayId) {
         /* This is callback invoked by VirtualDeviceManagerService when VirtualDisplay was released
          * by DisplayManager (most probably caused by someone calling VirtualDisplay.close()).
@@ -1549,6 +1611,11 @@
                     != PackageManager.PERMISSION_GRANTED) {
             synchronized (mVirtualDeviceLock) {
                 checkDisplayOwnedByVirtualDeviceLocked(displayId);
+                VirtualDisplayWrapper wrapper = mVirtualDisplays.get(displayId);
+                if (!wrapper.isTrusted() && !wrapper.isMirror()) {
+                    throw new SecurityException(
+                            "Cannot create input device associated with an untrusted display");
+                }
             }
         }
     }
@@ -1562,6 +1629,41 @@
         }
     }
 
+    private void checkCallerIsDeviceOwner() {
+        if (Binder.getCallingUid() != mOwnerUid) {
+            throw new SecurityException(
+                "Caller is not the owner of this virtual device");
+        }
+    }
+
+    void goToSleepInternal(@PowerManager.GoToSleepReason int reason) {
+        final long now = SystemClock.uptimeMillis();
+        synchronized (mVirtualDeviceLock) {
+            for (int i = 0; i < mVirtualDisplays.size(); i++) {
+                VirtualDisplayWrapper wrapper = mVirtualDisplays.valueAt(i);
+                if (!wrapper.isTrusted() || wrapper.isMirror()) {
+                    continue;
+                }
+                int displayId = mVirtualDisplays.keyAt(i);
+                mPowerManager.goToSleep(displayId, now, reason, /* flags= */ 0);
+            }
+        }
+    }
+
+    void wakeUpInternal(@PowerManager.WakeReason int reason, String details) {
+        final long now = SystemClock.uptimeMillis();
+        synchronized (mVirtualDeviceLock) {
+            for (int i = 0; i < mVirtualDisplays.size(); i++) {
+                VirtualDisplayWrapper wrapper = mVirtualDisplays.valueAt(i);
+                if (!wrapper.isTrusted() || wrapper.isMirror()) {
+                    continue;
+                }
+                int displayId = mVirtualDisplays.keyAt(i);
+                mPowerManager.wakeUp(now, reason, details, displayId);
+            }
+        }
+    }
+
     /**
      * Release resources tied to virtual display owned by this VirtualDevice instance.
      *
@@ -1570,7 +1672,7 @@
      * @param virtualDisplayWrapper - VirtualDisplayWrapper to release resources for.
      */
     private void releaseOwnedVirtualDisplayResources(VirtualDisplayWrapper virtualDisplayWrapper) {
-        virtualDisplayWrapper.getWakeLock().release();
+        virtualDisplayWrapper.releaseWakeLock();
         virtualDisplayWrapper.getWindowPolicyController().unregisterRunningAppsChangedListener(
                 this);
     }
@@ -1665,6 +1767,7 @@
         return mInputController.getInputDeviceDescriptors().values().stream().anyMatch(
                 inputDeviceDescriptor -> inputDeviceDescriptor.getInputDeviceId() == inputDeviceId);
     }
+
     void playSoundEffect(int effectType) {
         try {
             mSoundEffectListener.onPlaySoundEffect(effectType);
@@ -1732,21 +1835,35 @@
         private final IVirtualDisplayCallback mToken;
         private final GenericWindowPolicyController mWindowPolicyController;
         private final PowerManager.WakeLock mWakeLock;
+        private final boolean mIsTrusted;
+        private final boolean mIsMirror;
 
         VirtualDisplayWrapper(@NonNull IVirtualDisplayCallback token,
                 @NonNull GenericWindowPolicyController windowPolicyController,
-                @NonNull PowerManager.WakeLock wakeLock) {
+                @Nullable PowerManager.WakeLock wakeLock, boolean isTrusted, boolean isMirror) {
             mToken = Objects.requireNonNull(token);
             mWindowPolicyController = Objects.requireNonNull(windowPolicyController);
-            mWakeLock = Objects.requireNonNull(wakeLock);
+            mWakeLock = wakeLock;
+            mIsTrusted = isTrusted;
+            mIsMirror = isMirror;
         }
 
         GenericWindowPolicyController getWindowPolicyController() {
             return mWindowPolicyController;
         }
 
-        PowerManager.WakeLock getWakeLock() {
-            return mWakeLock;
+        void releaseWakeLock() {
+            if (mWakeLock != null && mWakeLock.isHeld()) {
+                mWakeLock.release();
+            }
+        }
+
+        boolean isTrusted() {
+            return mIsTrusted;
+        }
+
+        boolean isMirror() {
+            return mIsMirror;
         }
 
         IVirtualDisplayCallback getToken() {
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 3cd1ca4..f87e3c3 100644
--- a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java
@@ -21,6 +21,7 @@
 
 import static com.android.server.wm.ActivityInterceptorCallback.VIRTUAL_DEVICE_SERVICE_ORDERED_ID;
 
+import android.annotation.EnforcePermission;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
@@ -44,8 +45,6 @@
 import android.content.Context;
 import android.content.Intent;
 import android.hardware.display.DisplayManagerInternal;
-import android.hardware.display.IVirtualDisplayCallback;
-import android.hardware.display.VirtualDisplayConfig;
 import android.os.Binder;
 import android.os.Handler;
 import android.os.IBinder;
@@ -68,6 +67,7 @@
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.DumpUtils;
+import com.android.internal.widget.LockPatternUtils;
 import com.android.modules.expresslog.Counter;
 import com.android.server.LocalServices;
 import com.android.server.SystemService;
@@ -123,12 +123,31 @@
     private final CompanionDeviceManager.OnAssociationsChangedListener mCdmAssociationListener =
             new CompanionDeviceManager.OnAssociationsChangedListener() {
                 @Override
-                @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
                 public void onAssociationsChanged(@NonNull List<AssociationInfo> associations) {
                     syncVirtualDevicesToCdmAssociations(associations);
                 }
             };
 
+    private class StrongAuthTracker extends LockPatternUtils.StrongAuthTracker {
+        final Set<Integer> mUsersInLockdown = new ArraySet<>();
+
+        StrongAuthTracker(Context context) {
+            super(context);
+        }
+
+        @Override
+        public synchronized void onStrongAuthRequiredChanged(int userId) {
+            if ((getStrongAuthForUser(userId) & STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN) > 0) {
+                if (mUsersInLockdown.add(userId) && mUsersInLockdown.size() == 1) {
+                    onLockdownChanged(true);
+                }
+            } else if (mUsersInLockdown.remove(userId) && mUsersInLockdown.isEmpty()) {
+                onLockdownChanged(false);
+            }
+        }
+    }
+    private StrongAuthTracker mStrongAuthTracker;
+
     private final RemoteCallbackList<IVirtualDeviceListener> mVirtualDeviceListeners =
             new RemoteCallbackList<>();
 
@@ -201,6 +220,20 @@
                         + " will be available.");
             }
         }
+        if (android.companion.virtualdevice.flags.Flags.deviceAwareDisplayPower()) {
+            mStrongAuthTracker = new StrongAuthTracker(getContext());
+            new LockPatternUtils(getContext()).registerStrongAuthTracker(mStrongAuthTracker);
+        }
+    }
+
+    // Called when the global lockdown state changes, i.e. lockdown is considered active if any user
+    // is in lockdown mode, and inactive if no users are in lockdown mode.
+    void onLockdownChanged(boolean lockdownActive) {
+        synchronized (mVirtualDeviceManagerLock) {
+            for (int i = 0; i < mVirtualDevices.size(); i++) {
+                mVirtualDevices.valueAt(i).onLockdownChanged(lockdownActive);
+            }
+        }
     }
 
     void onCameraAccessBlocked(int appUid) {
@@ -306,7 +339,6 @@
         return true;
     }
 
-    @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
     private void syncVirtualDevicesToCdmAssociations(List<AssociationInfo> associations) {
         Set<VirtualDeviceImpl> virtualDevicesToRemove = new HashSet<>();
         synchronized (mVirtualDeviceManagerLock) {
@@ -349,7 +381,6 @@
         cdm.removeOnAssociationsChangedListener(mCdmAssociationListener);
     }
 
-    @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
     void onCdmAssociationsChanged(List<AssociationInfo> associations) {
         ArrayMap<String, AssociationInfo> vdmAssociations = new ArrayMap<>();
         for (int i = 0; i < associations.size(); ++i) {
@@ -419,7 +450,7 @@
                     }
                 };
 
-        @android.annotation.EnforcePermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
+        @EnforcePermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
         @Override // Binder call
         public IVirtualDevice createVirtualDevice(
                 IBinder token,
@@ -505,37 +536,6 @@
         }
 
         @Override // Binder call
-        public int createVirtualDisplay(VirtualDisplayConfig virtualDisplayConfig,
-                IVirtualDisplayCallback callback, IVirtualDevice virtualDevice, String packageName)
-                throws RemoteException {
-            Objects.requireNonNull(virtualDisplayConfig);
-            final int callingUid = getCallingUid();
-            if (!PermissionUtils.validateCallingPackageName(getContext(), packageName)) {
-                throw new SecurityException(
-                        "Package name " + packageName + " does not belong to calling uid "
-                                + callingUid);
-            }
-            VirtualDeviceImpl virtualDeviceImpl;
-            synchronized (mVirtualDeviceManagerLock) {
-                virtualDeviceImpl = mVirtualDevices.get(virtualDevice.getDeviceId());
-                if (virtualDeviceImpl == null) {
-                    throw new SecurityException(
-                            "Invalid VirtualDevice (deviceId = " + virtualDevice.getDeviceId()
-                                    + ")");
-                }
-            }
-            if (virtualDeviceImpl.getOwnerUid() != callingUid) {
-                throw new SecurityException(
-                        "uid " + callingUid
-                                + " is not the owner of the supplied VirtualDevice (deviceId = "
-                                + virtualDevice.getDeviceId() + ")");
-            }
-
-            return virtualDeviceImpl.createVirtualDisplay(
-                    virtualDisplayConfig, callback, packageName);
-        }
-
-        @Override // Binder call
         public List<VirtualDevice> getVirtualDevices() {
             List<VirtualDevice> virtualDevices = new ArrayList<>();
             synchronized (mVirtualDeviceManagerLock) {
diff --git a/services/core/java/com/android/server/SystemConfig.java b/services/core/java/com/android/server/SystemConfig.java
index d80e40c..504137a 100644
--- a/services/core/java/com/android/server/SystemConfig.java
+++ b/services/core/java/com/android/server/SystemConfig.java
@@ -727,10 +727,8 @@
             return;
         }
         // Read configuration of features, libs and priv-app permissions from apex module.
-        int apexPermissionFlag = ALLOW_LIBS | ALLOW_FEATURES | ALLOW_PRIVAPP_PERMISSIONS;
-        if (android.permission.flags.Flags.apexSignaturePermissionAllowlistEnabled()) {
-            apexPermissionFlag |= ALLOW_SIGNATURE_PERMISSIONS;
-        }
+        int apexPermissionFlag = ALLOW_LIBS | ALLOW_FEATURES | ALLOW_PRIVAPP_PERMISSIONS
+                | ALLOW_SIGNATURE_PERMISSIONS;
         // TODO: Use a solid way to filter apex module folders?
         for (File f: FileUtils.listFilesOrEmpty(Environment.getApexDirectory())) {
             if (f.isFile() || f.getPath().contains("@")) {
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index 7442277..39ac515 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -422,9 +422,9 @@
     private int[] mSimultaneousCellularCallingSubIds = {};
 
     private int[] mECBMReason;
-    private boolean[] mECBMStarted;
+    private long[] mECBMDuration;
     private int[] mSCBMReason;
-    private boolean[] mSCBMStarted;
+    private long[] mSCBMDuration;
 
     private boolean[] mCarrierRoamingNtnMode = null;
     private boolean[] mCarrierRoamingNtnEligible = null;
@@ -724,9 +724,9 @@
             mAllowedNetworkTypeReason = copyOf(mAllowedNetworkTypeReason, mNumPhones);
             mAllowedNetworkTypeValue = copyOf(mAllowedNetworkTypeValue, mNumPhones);
             mECBMReason = copyOf(mECBMReason, mNumPhones);
-            mECBMStarted = copyOf(mECBMStarted, mNumPhones);
+            mECBMDuration = copyOf(mECBMDuration, mNumPhones);
             mSCBMReason = copyOf(mSCBMReason, mNumPhones);
-            mSCBMStarted = copyOf(mSCBMStarted, mNumPhones);
+            mSCBMDuration = copyOf(mSCBMDuration, mNumPhones);
             mCarrierRoamingNtnMode = copyOf(mCarrierRoamingNtnMode, mNumPhones);
             mCarrierRoamingNtnEligible = copyOf(mCarrierRoamingNtnEligible, mNumPhones);
             // ds -> ss switch.
@@ -784,9 +784,9 @@
                 mCarrierPrivilegeStates.add(i, new Pair<>(Collections.emptyList(), new int[0]));
                 mCarrierServiceStates.add(i, new Pair<>(null, Process.INVALID_UID));
                 mECBMReason[i] = TelephonyManager.STOP_REASON_UNKNOWN;
-                mECBMStarted[i] = false;
+                mECBMDuration[i] = 0;
                 mSCBMReason[i] = TelephonyManager.STOP_REASON_UNKNOWN;
-                mSCBMStarted[i] = false;
+                mSCBMDuration[i] = 0;
                 mCarrierRoamingNtnMode[i] = false;
                 mCarrierRoamingNtnEligible[i] = false;
             }
@@ -859,9 +859,9 @@
         mCarrierPrivilegeStates = new ArrayList<>();
         mCarrierServiceStates = new ArrayList<>();
         mECBMReason = new int[numPhones];
-        mECBMStarted = new boolean[numPhones];
+        mECBMDuration = new long[numPhones];
         mSCBMReason = new int[numPhones];
-        mSCBMStarted = new boolean[numPhones];
+        mSCBMDuration = new long[numPhones];
         mCarrierRoamingNtnMode = new boolean[numPhones];
         mCarrierRoamingNtnEligible = new boolean[numPhones];
 
@@ -904,9 +904,9 @@
             mCarrierPrivilegeStates.add(i, new Pair<>(Collections.emptyList(), new int[0]));
             mCarrierServiceStates.add(i, new Pair<>(null, Process.INVALID_UID));
             mECBMReason[i] = TelephonyManager.STOP_REASON_UNKNOWN;
-            mECBMStarted[i] = false;
+            mECBMDuration[i] = 0;
             mSCBMReason[i] = TelephonyManager.STOP_REASON_UNKNOWN;
-            mSCBMStarted[i] = false;
+            mSCBMDuration[i] = 0;
             mCarrierRoamingNtnMode[i] = false;
             mCarrierRoamingNtnEligible[i] = false;
         }
@@ -1493,24 +1493,24 @@
                 }
                 if (events.contains(TelephonyCallback.EVENT_EMERGENCY_CALLBACK_MODE_CHANGED)) {
                     try {
-                        boolean ecbmStarted = mECBMStarted[r.phoneId];
-                        if (ecbmStarted) {
-                            r.callback.onCallBackModeStarted(
-                                    TelephonyManager.EMERGENCY_CALLBACK_MODE_CALL);
-                        } else {
-                            r.callback.onCallBackModeStopped(
+                        if (mECBMDuration[r.phoneId] != 0) {
+                            r.callback.onCallbackModeStarted(
                                     TelephonyManager.EMERGENCY_CALLBACK_MODE_CALL,
-                                    mECBMReason[r.phoneId]);
+                                    mECBMDuration[r.phoneId], r.subId);
+                        } else {
+                            r.callback.onCallbackModeStopped(
+                                    TelephonyManager.EMERGENCY_CALLBACK_MODE_CALL,
+                                    mECBMReason[r.phoneId], r.subId);
                         }
 
-                        boolean scbmStarted = mSCBMStarted[r.phoneId];
-                        if (scbmStarted) {
-                            r.callback.onCallBackModeStarted(
-                                    TelephonyManager.EMERGENCY_CALLBACK_MODE_SMS);
-                        } else {
-                            r.callback.onCallBackModeStopped(
+                        if (mSCBMReason[r.phoneId] != 0) {
+                            r.callback.onCallbackModeStarted(
                                     TelephonyManager.EMERGENCY_CALLBACK_MODE_SMS,
-                                    mSCBMReason[r.phoneId]);
+                                    mSCBMDuration[r.phoneId], r.subId);
+                        } else {
+                            r.callback.onCallbackModeStopped(
+                                    TelephonyManager.EMERGENCY_CALLBACK_MODE_SMS,
+                                    mSCBMReason[r.phoneId], r.subId);
                         }
                     } catch (RemoteException ex) {
                         remove(r.binder);
@@ -3457,10 +3457,9 @@
     }
 
     @Override
-    public void notifyCallbackModeStarted(int phoneId, int subId, int type) {
-        if (!checkNotifyPermission("notifyCallbackModeStarted()")) {
-            return;
-        }
+    public void notifyCallbackModeStarted(int phoneId, int subId, int type, long durationMillis) {
+        if (!checkNotifyPermission("notifyCallbackModeStarted()")) return;
+
         if (VDBG) {
             log("notifyCallbackModeStarted: phoneId=" + phoneId + ", subId=" + subId
                     + ", type=" + type);
@@ -3468,9 +3467,9 @@
         synchronized (mRecords) {
             if (validatePhoneId(phoneId)) {
                 if (type == TelephonyManager.EMERGENCY_CALLBACK_MODE_CALL) {
-                    mECBMStarted[phoneId] = true;
+                    mECBMDuration[phoneId] = durationMillis;
                 } else if (type == TelephonyManager.EMERGENCY_CALLBACK_MODE_SMS) {
-                    mSCBMStarted[phoneId] = true;
+                    mSCBMDuration[phoneId] = durationMillis;
                 }
             }
             for (Record r : mRecords) {
@@ -3478,7 +3477,39 @@
                 if (r.matchTelephonyCallbackEvent(
                         TelephonyCallback.EVENT_EMERGENCY_CALLBACK_MODE_CHANGED)) {
                     try {
-                        r.callback.onCallBackModeStarted(type);
+                        r.callback.onCallbackModeStarted(type, durationMillis, subId);
+                    } catch (RemoteException ex) {
+                        mRemoveList.add(r.binder);
+                    }
+                }
+            }
+        }
+        handleRemoveListLocked();
+    }
+
+    @Override
+    public void notifyCallbackModeRestarted(int phoneId, int subId, int type,
+            long durationMillis) {
+        if (!checkNotifyPermission("notifyCallbackModeRestarted()")) return;
+
+        if (VDBG) {
+            log("notifyCallbackModeRestarted: phoneId=" + phoneId + ", subId=" + subId
+                    + ", type=" + type);
+        }
+        synchronized (mRecords) {
+            if (validatePhoneId(phoneId)) {
+                if (type == TelephonyManager.EMERGENCY_CALLBACK_MODE_CALL) {
+                    mECBMDuration[phoneId] = durationMillis;
+                } else if (type == TelephonyManager.EMERGENCY_CALLBACK_MODE_SMS) {
+                    mSCBMDuration[phoneId] = durationMillis;
+                }
+            }
+            for (Record r : mRecords) {
+                // Send to all listeners regardless of subscription
+                if (r.matchTelephonyCallbackEvent(
+                        TelephonyCallback.EVENT_EMERGENCY_CALLBACK_MODE_CHANGED)) {
+                    try {
+                        r.callback.onCallbackModeRestarted(type, durationMillis, subId);
                     } catch (RemoteException ex) {
                         mRemoveList.add(r.binder);
                     }
@@ -3490,9 +3521,8 @@
 
     @Override
     public void notifyCallbackModeStopped(int phoneId, int subId, int type, int reason) {
-        if (!checkNotifyPermission("notifyCallbackModeStopped()")) {
-            return;
-        }
+        if (!checkNotifyPermission("notifyCallbackModeStopped()")) return;
+
         if (VDBG) {
             log("notifyCallbackModeStopped: phoneId=" + phoneId + ", subId=" + subId
                     + ", type=" + type + ", reason=" + reason);
@@ -3500,11 +3530,11 @@
         synchronized (mRecords) {
             if (validatePhoneId(phoneId)) {
                 if (type == TelephonyManager.EMERGENCY_CALLBACK_MODE_CALL) {
-                    mECBMStarted[phoneId] = false;
                     mECBMReason[phoneId] = reason;
+                    mECBMDuration[phoneId] = 0;
                 } else if (type == TelephonyManager.EMERGENCY_CALLBACK_MODE_SMS) {
-                    mSCBMStarted[phoneId] = false;
                     mSCBMReason[phoneId] = reason;
+                    mSCBMDuration[phoneId] = 0;
                 }
             }
             for (Record r : mRecords) {
@@ -3512,7 +3542,7 @@
                 if (r.matchTelephonyCallbackEvent(
                         TelephonyCallback.EVENT_EMERGENCY_CALLBACK_MODE_CHANGED)) {
                     try {
-                        r.callback.onCallBackModeStopped(type, reason);
+                        r.callback.onCallbackModeStopped(type, reason, subId);
                     } catch (RemoteException ex) {
                         mRemoveList.add(r.binder);
                     }
@@ -3662,9 +3692,9 @@
                 pw.println("mPhysicalChannelConfigs=" + mPhysicalChannelConfigs.get(i));
                 pw.println("mLinkCapacityEstimateList=" + mLinkCapacityEstimateLists.get(i));
                 pw.println("mECBMReason=" + mECBMReason[i]);
-                pw.println("mECBMStarted=" + mECBMStarted[i]);
+                pw.println("mECBMDuration=" + mECBMDuration[i]);
                 pw.println("mSCBMReason=" + mSCBMReason[i]);
-                pw.println("mSCBMStarted=" + mSCBMStarted[i]);
+                pw.println("mSCBMDuration=" + mSCBMDuration[i]);
                 pw.println("mCarrierRoamingNtnMode=" + mCarrierRoamingNtnMode[i]);
                 pw.println("mCarrierRoamingNtnEligible=" + mCarrierRoamingNtnEligible[i]);
 
diff --git a/services/core/java/com/android/server/UiModeManagerService.java b/services/core/java/com/android/server/UiModeManagerService.java
index 7daf158..f8857d3 100644
--- a/services/core/java/com/android/server/UiModeManagerService.java
+++ b/services/core/java/com/android/server/UiModeManagerService.java
@@ -2064,12 +2064,14 @@
 
     private void updateComputedNightModeLocked(boolean activate) {
         boolean newComputedValue = activate;
+        boolean appliedOverrides = false;
         if (mNightMode.get() != MODE_NIGHT_YES && mNightMode.get() != UiModeManager.MODE_NIGHT_NO) {
             if (mOverrideNightModeOn && !newComputedValue) {
                 newComputedValue = true;
             } else if (mOverrideNightModeOff && newComputedValue) {
                 newComputedValue = false;
             }
+            appliedOverrides = true;
         }
 
         if (modesApi()) {
@@ -2079,8 +2081,10 @@
                 case (UiModeManager.MODE_ATTENTION_THEME_OVERLAY_DAY) -> false;
                 default -> newComputedValue; // case OFF
             };
-        } else {
-            mComputedNightMode = newComputedValue;
+        }
+
+        if (appliedOverrides) {
+            return;
         }
 
         if (mNightMode.get() != MODE_NIGHT_AUTO || (mTwilightManager != null
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 3666524..3f540ad 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -1189,8 +1189,8 @@
             if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "START SERVICE WHILE RESTART PENDING: " + r);
         }
         final boolean wasStartRequested = r.startRequested;
-        r.lastActivity = SystemClock.uptimeMillis();
-        r.startRequested = true;
+        mAm.mProcessStateController.setServiceLastActivityTime(r, SystemClock.uptimeMillis());
+        mAm.mProcessStateController.setStartRequested(r, true);
         r.delayedStop = false;
         r.fgRequired = fgRequired;
         r.pendingStarts.add(new ServiceRecord.StartItem(r, false, r.makeNextStartId(),
@@ -1623,7 +1623,7 @@
             FrameworkStatsLog.write(FrameworkStatsLog.SERVICE_STATE_CHANGED, uid, packageName,
                     serviceName, FrameworkStatsLog.SERVICE_STATE_CHANGED__STATE__STOP);
             mAm.mBatteryStatsService.noteServiceStopRunning(uid, packageName, serviceName);
-            service.startRequested = false;
+            mAm.mProcessStateController.setStartRequested(service, false);
             if (service.tracker != null) {
                 synchronized (mAm.mProcessStats.mLock) {
                     service.tracker.setStarted(false, mAm.mProcessStats.getMemFactorLocked(),
@@ -1812,7 +1812,7 @@
             FrameworkStatsLog.write(FrameworkStatsLog.SERVICE_STATE_CHANGED, uid, packageName,
                     serviceName, FrameworkStatsLog.SERVICE_STATE_CHANGED__STATE__STOP);
             mAm.mBatteryStatsService.noteServiceStopRunning(uid, packageName, serviceName);
-            r.startRequested = false;
+            mAm.mProcessStateController.setStartRequested(r, false);
             if (r.tracker != null) {
                 synchronized (mAm.mProcessStats.mLock) {
                     r.tracker.setStarted(false, mAm.mProcessStats.getMemFactorLocked(),
@@ -2618,7 +2618,7 @@
                     }
                     notification.flags |= Notification.FLAG_FOREGROUND_SERVICE;
                     r.foregroundNoti = notification;
-                    r.foregroundServiceType = foregroundServiceType;
+                    mAm.mProcessStateController.setForegroundServiceType(r, foregroundServiceType);
                     if (!r.isForeground) {
                         final ServiceMap smap = getServiceMapLocked(r.userId);
                         if (smap != null) {
@@ -2643,7 +2643,7 @@
                             }
                             active.mNumActive++;
                         }
-                        r.isForeground = true;
+                        mAm.mProcessStateController.setIsForegroundService(r, true);
 
                         // The logging of FOREGROUND_SERVICE_STATE_CHANGED__STATE__ENTER event could
                         // be deferred, make a copy of mAllowStartForeground and
@@ -2772,7 +2772,7 @@
                     }
                 }
 
-                r.isForeground = false;
+                mAm.mProcessStateController.setIsForegroundService(r, false);
                 r.mFgsExitTime = SystemClock.uptimeMillis();
                 synchronized (mAm.mProcessStats.mLock) {
                     final ServiceState stracker = r.getTracker();
@@ -3565,7 +3565,7 @@
     private void maybeUpdateShortFgsTrackingLocked(ServiceRecord sr,
             boolean extendTimeout) {
         if (!sr.isShortFgs()) {
-            sr.clearShortFgsInfo(); // Just in case we have it.
+            mAm.mProcessStateController.clearShortFgsInfo(sr); // Just in case we have it.
             unscheduleShortFgsTimeoutLocked(sr);
             return;
         }
@@ -3581,7 +3581,7 @@
                 }
             }
             traceInstant("short FGS start/extend: ", sr);
-            sr.setShortFgsInfo(SystemClock.uptimeMillis());
+            mAm.mProcessStateController.setShortFgsInfo(sr, SystemClock.uptimeMillis());
 
             // We'll restart the timeout.
             unscheduleShortFgsTimeoutLocked(sr);
@@ -3605,7 +3605,7 @@
      * Stop the timeout for a ServiceRecord, if it's of a short-FGS.
      */
     private void maybeStopShortFgsTimeoutLocked(ServiceRecord sr) {
-        sr.clearShortFgsInfo(); // Always clear, just in case.
+        mAm.mProcessStateController.clearShortFgsInfo(sr); // Always clear, just in case.
         if (!sr.isShortFgs()) {
             return;
         }
@@ -3993,7 +3993,7 @@
     private void stopServiceAndUpdateAllowlistManagerLocked(ServiceRecord service) {
         maybeStopShortFgsTimeoutLocked(service);
         final ProcessServiceRecord psr = service.app.mServices;
-        psr.stopService(service);
+        mAm.mProcessStateController.stopService(psr, service);
         psr.updateBoundClientUids();
         if (service.allowlistManager) {
             updateAllowlistManagerLocked(psr);
@@ -4047,7 +4047,7 @@
             }
         }
         if (anyClientActivities != psr.hasClientActivities()) {
-            psr.setHasClientActivities(anyClientActivities);
+            mAm.mProcessStateController.setHasClientActivities(psr, anyClientActivities);
             if (updateLru) {
                 mAm.updateLruProcessLocked(psr.mApp, anyClientActivities, null);
             }
@@ -4216,7 +4216,8 @@
             }
 
             if ((flags&Context.BIND_AUTO_CREATE) != 0) {
-                s.lastActivity = SystemClock.uptimeMillis();
+                mAm.mProcessStateController.setServiceLastActivityTime(s,
+                        SystemClock.uptimeMillis());
                 if (!s.hasAutoCreateConnections()) {
                     // This is the first binding, let the tracker know.
                     synchronized (mAm.mProcessStats.mLock) {
@@ -4253,12 +4254,12 @@
             if (activity != null) {
                 activity.addConnection(c);
             }
-            clientPsr.addConnection(c);
+            mAm.mProcessStateController.addConnection(clientPsr, c);
             c.startAssociationIfNeeded();
             // Don't set hasAboveClient if binding to self to prevent modifyRawOomAdj() from
             // dropping the process' adjustment level.
             if (b.client != s.app && c.hasFlag(Context.BIND_ABOVE_CLIENT)) {
-                clientPsr.setHasAboveClient(true);
+                mAm.mProcessStateController.setHasAboveClient(clientPsr, true);
             }
             if (c.hasFlag(BIND_ALLOW_WHITELIST_MANAGEMENT)) {
                 s.allowlistManager = true;
@@ -4274,7 +4275,8 @@
             if (s.app != null && s.app.mState != null
                     && s.app.mState.getCurProcState() <= PROCESS_STATE_TOP
                     && c.hasFlag(Context.BIND_ALMOST_PERCEPTIBLE)) {
-                s.lastTopAlmostPerceptibleBindRequestUptimeMs = SystemClock.uptimeMillis();
+                mAm.mProcessStateController.setLastTopAlmostPerceptibleBindRequest(s,
+                        SystemClock.uptimeMillis());
             }
 
             if (s.app != null) {
@@ -4312,7 +4314,8 @@
 
             boolean needOomAdj = false;
             if (c.hasFlag(Context.BIND_AUTO_CREATE)) {
-                s.lastActivity = SystemClock.uptimeMillis();
+                mAm.mProcessStateController.setServiceLastActivityTime(s,
+                        SystemClock.uptimeMillis());
                 needOomAdj = (serviceBindingOomAdjPolicy
                         & SERVICE_BIND_OOMADJ_POLICY_SKIP_OOM_UPDATE_ON_CREATE) == 0;
                 if (bringUpServiceLocked(s, service.getFlags(), callerFg, false,
@@ -4328,7 +4331,7 @@
             if (s.app != null) {
                 ProcessServiceRecord servicePsr = s.app.mServices;
                 if (c.hasFlag(Context.BIND_TREAT_LIKE_ACTIVITY)) {
-                    servicePsr.setTreatLikeActivity(true);
+                    mAm.mProcessStateController.setTreatLikeActivity(servicePsr, true);
                 }
                 if (s.allowlistManager) {
                     servicePsr.mAllowlistManager = true;
@@ -4575,7 +4578,9 @@
                     }
                     // This could have made the service less important.
                     if (r.hasFlag(Context.BIND_TREAT_LIKE_ACTIVITY)) {
-                        psr.setTreatLikeActivity(true);
+                        // TODO(b/367545398): the following line is a bug. A service unbind
+                        //  should potentially lower a process's importance, not elevate it.
+                        mAm.mProcessStateController.setTreatLikeActivity(psr, true);
                         mAm.updateLruProcessLocked(app, true, null);
                     }
                     // If the bindee is more important than the binder, we may skip the OomAdjuster.
@@ -5077,7 +5082,10 @@
                         + " requires " + r.permission);
                 return new ServiceLookupResult(r.permission);
             } else if ((Manifest.permission.BIND_HOTWORD_DETECTION_SERVICE.equals(r.permission)
-                    || Manifest.permission.BIND_VISUAL_QUERY_DETECTION_SERVICE.equals(r.permission))
+                    || Manifest.permission.BIND_VISUAL_QUERY_DETECTION_SERVICE.equals(r.permission)
+                    || Manifest.permission.BIND_WEARABLE_SENSING_SERVICE.equals(r.permission)
+                    || Manifest.permission.BIND_ON_DEVICE_SANDBOXED_INFERENCE_SERVICE.equals(
+                    r.permission))
                     && callingUid != Process.SYSTEM_UID) {
                 // Hotword detection and visual query detection must run in its own sandbox, and we
                 // don't even trust its enclosing application to bind to it - only the system.
@@ -5162,8 +5170,9 @@
             }
             if (r.app != null) {
                 psr = r.app.mServices;
-                psr.startExecutingService(r);
-                psr.setExecServicesFg(psr.shouldExecServicesFg() || fg);
+                mAm.mProcessStateController.startExecutingService(psr, r);
+                mAm.mProcessStateController.setExecServicesFg(psr,
+                        psr.shouldExecServicesFg() || fg);
                 if (timeoutNeeded && psr.numberOfExecutingServices() == 1) {
                     if (!shouldSkipTimeout) {
                         scheduleServiceTimeoutLocked(r.app);
@@ -5175,7 +5184,7 @@
         } else if (r.app != null && fg) {
             psr = r.app.mServices;
             if (!psr.shouldExecServicesFg()) {
-                psr.setExecServicesFg(true);
+                mAm.mProcessStateController.setExecServicesFg(psr, true);
                 if (timeoutNeeded) {
                     if (!shouldSkipTimeout) {
                         scheduleServiceTimeoutLocked(r.app);
@@ -6020,11 +6029,13 @@
             Slog.v(TAG_MU, "realStartServiceLocked, ServiceRecord.uid = " + r.appInfo.uid
                     + ", ProcessRecord.uid = " + app.uid);
         r.setProcess(app, thread, pid, uidRecord);
-        r.restartTime = r.lastActivity = SystemClock.uptimeMillis();
+        final long now = SystemClock.uptimeMillis();
+        r.restartTime = now;
+        mAm.mProcessStateController.setServiceLastActivityTime(r, now);
         final boolean skipOomAdj = (serviceBindingOomAdjPolicy
                 & SERVICE_BIND_OOMADJ_POLICY_SKIP_OOM_UPDATE_ON_CREATE) != 0;
         final ProcessServiceRecord psr = app.mServices;
-        final boolean newService = psr.startService(r);
+        final boolean newService = mAm.mProcessStateController.startService(psr, r);
         bumpServiceExecutingLocked(r, execInFg, "create",
                 OOM_ADJ_REASON_NONE /* use "none" to avoid extra oom adj */,
                 skipOomAdj /* skipTimeoutIfPossible */);
@@ -6083,7 +6094,7 @@
 
                 // Cleanup.
                 if (newService) {
-                    psr.stopService(r);
+                    mAm.mProcessStateController.stopService(psr, r);
                     r.setProcess(null, null, 0, null);
                 }
 
@@ -6428,7 +6439,7 @@
             mAm.updateForegroundServiceUsageStats(r.name, r.userId, false);
         }
 
-        r.isForeground = false;
+        mAm.mProcessStateController.setIsForegroundService(r, false);
         r.mFgsNotificationWasDeferred = false;
         dropFgsNotificationStateLocked(r);
         r.foregroundId = 0;
@@ -6579,9 +6590,9 @@
         }
         if (b.client != skipApp) {
             final ProcessServiceRecord psr = b.client.mServices;
-            psr.removeConnection(c);
+            mAm.mProcessStateController.removeConnection(psr, c);
             if (c.hasFlag(Context.BIND_ABOVE_CLIENT)) {
-                psr.updateHasAboveClientLocked();
+                mAm.mProcessStateController.updateHasAboveClientLocked(psr);
             }
             // If this connection requested allowlist management, see if we should
             // now clear that state.
@@ -6597,7 +6608,7 @@
             }
             // And for almost perceptible exceptions.
             if (c.hasFlag(Context.BIND_ALMOST_PERCEPTIBLE)) {
-                psr.updateHasTopStartedAlmostPerceptibleServices();
+                mAm.mProcessStateController.updateHasTopStartedAlmostPerceptibleServices(psr);
             }
             if (s.app != null) {
                 updateServiceClientActivitiesLocked(s.app.mServices, c, true);
@@ -6796,8 +6807,8 @@
                 final ProcessServiceRecord psr = r.app.mServices;
                 if (DEBUG_SERVICE) Slog.v(TAG_SERVICE,
                         "Nesting at 0 of " + r.shortInstanceName);
-                psr.setExecServicesFg(false);
-                psr.stopExecutingService(r);
+                mAm.mProcessStateController.setExecServicesFg(psr, false);
+                mAm.mProcessStateController.stopExecutingService(psr, r);
                 if (psr.numberOfExecutingServices() == 0) {
                     if (DEBUG_SERVICE || DEBUG_SERVICE_EXECUTING) Slog.v(TAG_SERVICE_EXECUTING,
                             "No more executingServices of " + r.shortInstanceName);
@@ -6806,7 +6817,7 @@
                     // Need to re-evaluate whether the app still needs to be in the foreground.
                     for (int i = psr.numberOfExecutingServices() - 1; i >= 0; i--) {
                         if (psr.getExecutingServiceAt(i).executeFg) {
-                            psr.setExecServicesFg(true);
+                            mAm.mProcessStateController.setExecServicesFg(psr, true);
                             break;
                         }
                     }
@@ -6819,9 +6830,9 @@
                 }
                 if (oomAdjReason != OOM_ADJ_REASON_NONE) {
                     if (enqueueOomAdj) {
-                        mAm.enqueueOomAdjTargetLocked(r.app);
+                        mAm.mProcessStateController.enqueueUpdateTarget(r.app);
                     } else {
-                        mAm.updateOomAdjLocked(r.app, oomAdjReason);
+                        mAm.mProcessStateController.runUpdate(r.app, oomAdjReason);
                     }
                 } else {
                     // Skip oom adj if it wasn't bumped during the bumpServiceExecutingLocked()
@@ -7206,8 +7217,7 @@
             removeConnectionLocked(r, app, null, true);
         }
         updateServiceConnectionActivitiesLocked(psr);
-        psr.removeAllConnections();
-        psr.removeAllSdkSandboxConnections();
+        mAm.mProcessStateController.removeAllConnections(psr);
 
         psr.mAllowlistManager = false;
 
@@ -7217,7 +7227,7 @@
             mAm.mBatteryStatsService.noteServiceStopLaunch(sr.appInfo.uid, sr.name.getPackageName(),
                     sr.name.getClassName());
             if (sr.app != app && sr.app != null && !sr.app.isPersistent()) {
-                sr.app.mServices.stopService(sr);
+                mAm.mProcessStateController.stopService(sr.app.mServices, sr);
                 sr.app.mServices.updateBoundClientUids();
             }
             sr.setProcess(null, null, 0, null);
@@ -7287,7 +7297,7 @@
             // Unless the process is persistent, this process record is going away,
             // so make sure the service is cleaned out of it.
             if (!app.isPersistent()) {
-                psr.stopService(sr);
+                mAm.mProcessStateController.stopService(psr, sr);
                 psr.updateBoundClientUids();
             }
 
@@ -7328,7 +7338,7 @@
                     // Update to stopped state because the explicit start is gone. The service is
                     // scheduled to restart for other reason (e.g. connections) so we don't bring
                     // down it.
-                    sr.startRequested = false;
+                    mAm.mProcessStateController.setStartRequested(sr, false);
                     if (sr.tracker != null) {
                         synchronized (mAm.mProcessStats.mLock) {
                             sr.tracker.setStarted(false, mAm.mProcessStats.getMemFactorLocked(),
@@ -7342,7 +7352,7 @@
         mAm.updateOomAdjPendingTargetsLocked(OOM_ADJ_REASON_STOP_SERVICE);
 
         if (!allowRestart) {
-            psr.stopAllServices();
+            mAm.mProcessStateController.stopAllServices(psr);
             psr.clearBoundClientUids();
 
             // Make sure there are no more restarting services for this process.
@@ -7384,7 +7394,7 @@
             }
         }
 
-        psr.stopAllExecutingServices();
+        mAm.mProcessStateController.stopAllExecutingServices(psr);
         psr.noteScheduleServiceTimeoutPending(false);
     }
 
@@ -9210,14 +9220,14 @@
                 new ForegroundServiceDelegation(options, connection);
         r.mFgsDelegation = delegation;
         mFgsDelegations.put(delegation, r);
-        r.isForeground = true;
+        mAm.mProcessStateController.setIsForegroundService(r, true);
         r.mFgsEnterTime = SystemClock.uptimeMillis();
-        r.foregroundServiceType = options.mForegroundServiceTypes;
+        mAm.mProcessStateController.setForegroundServiceType(r, options.mForegroundServiceTypes);
         r.updateOomAdjSeq();
         setFgsRestrictionLocked(callingPackage, callingPid, callingUid, intent, r, userId,
                 BackgroundStartPrivileges.NONE,  false /* isBindService */);
         final ProcessServiceRecord psr = callerApp.mServices;
-        final boolean newService = psr.startService(r);
+        final boolean newService = mAm.mProcessStateController.startService(psr, r);
         // updateOomAdj.
         updateServiceForegroundLocked(psr, /* oomAdj= */ true);
 
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 9219cc12..7f1d912 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -130,6 +130,7 @@
 import static android.provider.Settings.Global.ALWAYS_FINISH_ACTIVITIES;
 import static android.provider.Settings.Global.DEBUG_APP;
 import static android.provider.Settings.Global.WAIT_FOR_DEBUGGER;
+import static android.security.Flags.preventIntentRedirect;
 import static android.util.FeatureFlagUtils.SETTINGS_ENABLE_MONITOR_PHANTOM_PROCS;
 import static android.view.Display.INVALID_DISPLAY;
 
@@ -420,6 +421,7 @@
 import com.android.internal.util.FrameworkStatsLog;
 import com.android.internal.util.MemInfoReader;
 import com.android.internal.util.Preconditions;
+import com.android.internal.util.function.pooled.PooledLambda;
 import com.android.server.AlarmManagerInternal;
 import com.android.server.BootReceiver;
 import com.android.server.DeviceIdleInternal;
@@ -439,6 +441,7 @@
 import com.android.server.appop.AppOpsService;
 import com.android.server.compat.PlatformCompat;
 import com.android.server.contentcapture.ContentCaptureManagerInternal;
+import com.android.server.crashrecovery.CrashRecoveryAdaptor;
 import com.android.server.crashrecovery.CrashRecoveryHelper;
 import com.android.server.criticalevents.CriticalEventLog;
 import com.android.server.firewall.IntentFirewall;
@@ -624,6 +627,8 @@
             DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSSZ");
 
     OomAdjuster mOomAdjuster;
+    @GuardedBy("this")
+    ProcessStateController mProcessStateController;
 
     static final String EXTRA_TITLE = "android.intent.extra.TITLE";
     static final String EXTRA_DESCRIPTION = "android.intent.extra.DESCRIPTION";
@@ -1956,7 +1961,7 @@
                         new HostingRecord(HostingRecord.HOSTING_TYPE_SYSTEM));
                 app.setPersistent(true);
                 app.setPid(MY_PID);
-                app.mState.setMaxAdj(ProcessList.SYSTEM_ADJ);
+                mProcessStateController.setMaxAdj(app, ProcessList.SYSTEM_ADJ);
                 app.makeActive(new ApplicationThreadDeferred(mSystemThread.getApplicationThread()),
                         mProcessStats);
                 app.mProfile.addHostingComponentType(HOSTING_COMPONENT_TYPE_SYSTEM);
@@ -2206,7 +2211,7 @@
                 mService.mBroadcastController.startBroadcastObservers();
             } else if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) {
                 if (!refactorCrashrecovery()) {
-                    mService.mPackageWatchdog.onPackagesReady();
+                    CrashRecoveryAdaptor.packageWatchdogOnPackagesReady(mService.mPackageWatchdog);
                 } else {
                     mService.mCrashRecoveryHelper.registerConnectivityModuleHealthListener();
                 }
@@ -2392,9 +2397,11 @@
         mProcessList.init(this, activeUids, mPlatformCompat);
         mAppProfiler = new AppProfiler(this, BackgroundThread.getHandler().getLooper(), null);
         mPhantomProcessList = new PhantomProcessList(this);
-        mOomAdjuster = mConstants.ENABLE_NEW_OOMADJ
-                ? new OomAdjusterModernImpl(this, mProcessList, activeUids, handlerThread)
-                : new OomAdjuster(this, mProcessList, activeUids, handlerThread);
+        mProcessStateController = new ProcessStateController.Builder(this, mProcessList, activeUids)
+                .setHandlerThread(handlerThread)
+                .useModernOomAdjuster(mConstants.ENABLE_NEW_OOMADJ)
+                .build();
+        mOomAdjuster = mProcessStateController.getOomAdjuster();
 
         mIntentFirewall = injector.getIntentFirewall();
         mProcessStats = new ProcessStatsService(this, mContext.getCacheDir());
@@ -2420,6 +2427,7 @@
         mBroadcastController = new BroadcastController(mContext, this, mBroadcastQueue);
         mComponentAliasResolver = new ComponentAliasResolver(this);
         mApplicationSharedMemoryReadOnlyFd = null;
+        sCreatorTokenCacheCleaner = new Handler(mHandlerThread.getLooper());
     }
 
     // Note: This method is invoked on the main thread but may need to attach various
@@ -2456,9 +2464,10 @@
         mAppProfiler = new AppProfiler(this, BackgroundThread.getHandler().getLooper(),
                 new LowMemDetector(this));
         mPhantomProcessList = new PhantomProcessList(this);
-        mOomAdjuster = mConstants.ENABLE_NEW_OOMADJ
-                ? new OomAdjusterModernImpl(this, mProcessList, activeUids)
-                : new OomAdjuster(this, mProcessList, activeUids);
+        mProcessStateController = new ProcessStateController.Builder(this, mProcessList, activeUids)
+                .useModernOomAdjuster(mConstants.ENABLE_NEW_OOMADJ)
+                .build();
+        mOomAdjuster = mProcessStateController.getOomAdjuster();
 
         mBroadcastQueue = mInjector.getBroadcastQueue(this);
         mBroadcastController = new BroadcastController(mContext, this, mBroadcastQueue);
@@ -2526,6 +2535,7 @@
         mPendingStartActivityUids = new PendingStartActivityUids();
         mTraceErrorLogger = new TraceErrorLogger();
         mComponentAliasResolver = new ComponentAliasResolver(this);
+        sCreatorTokenCacheCleaner = new Handler(mHandlerThread.getLooper());
         try {
             mApplicationSharedMemoryReadOnlyFd =
                     ApplicationSharedMemory.getInstance().getReadOnlyFileDescriptor();
@@ -4570,7 +4580,7 @@
         EventLogTags.writeAmProcBound(app.userId, pid, app.processName);
 
         synchronized (mProcLock) {
-            mOomAdjuster.setAttachingProcessStatesLSP(app);
+            mProcessStateController.setAttachingProcessStatesLSP(app);
             clearProcessForegroundLocked(app);
             app.setDebugging(false);
             app.setKilledByAm(false);
@@ -4766,7 +4776,7 @@
                 app.makeActive(new ApplicationThreadDeferred(thread), mProcessStats);
                 checkTime(startTime, "attachApplicationLocked: immediately after bindApplication");
             }
-            app.setPendingFinishAttach(true);
+            mProcessStateController.setPendingFinishAttach(app, true);
 
             updateLruProcessLocked(app, false, null);
             checkTime(startTime, "attachApplicationLocked: after updateLruProcessLocked");
@@ -4850,7 +4860,7 @@
 
         synchronized (this) {
             // Mark the finish attach application phase as completed
-            app.setPendingFinishAttach(false);
+            mProcessStateController.setPendingFinishAttach(app, false);
 
             final boolean normalMode = mProcessesReady || isAllowedWhileBooting(app.info);
             final String processName = app.processName;
@@ -5005,7 +5015,7 @@
         // If another follow up update is needed, it will be scheduled by OomAdjuster.
         mHandler.removeMessages(FOLLOW_UP_OOMADJUSTER_UPDATE_MSG);
         synchronized (this) {
-            mOomAdjuster.updateOomAdjFollowUpTargetsLocked();
+            mProcessStateController.runFollowUpUpdate();
         }
     }
 
@@ -5532,6 +5542,7 @@
     public int sendIntentSender(IApplicationThread caller, IIntentSender target,
             IBinder allowlistToken, int code, Intent intent, String resolvedType,
             IIntentReceiver finishedReceiver, String requiredPermission, Bundle options) {
+        addCreatorToken(intent);
         if (target instanceof PendingIntentRecord) {
             final PendingIntentRecord originalRecord = (PendingIntentRecord) target;
 
@@ -5799,10 +5810,10 @@
                 if (pr == null) {
                     return;
                 }
-                pr.mState.setForcingToImportant(null);
+                mProcessStateController.setForcingToImportant(pr, null);
                 clearProcessForegroundLocked(pr);
             }
-            updateOomAdjLocked(pr, OOM_ADJ_REASON_UI_VISIBILITY);
+            mProcessStateController.runUpdate(pr, OOM_ADJ_REASON_UI_VISIBILITY);
         }
     }
 
@@ -5825,7 +5836,7 @@
                     oldToken.token.unlinkToDeath(oldToken, 0);
                     mImportantProcesses.remove(pid);
                     if (pr != null) {
-                        pr.mState.setForcingToImportant(null);
+                        mProcessStateController.setForcingToImportant(pr, null);
                     }
                     changed = true;
                 }
@@ -5839,7 +5850,7 @@
                     try {
                         token.linkToDeath(newToken, 0);
                         mImportantProcesses.put(pid, newToken);
-                        pr.mState.setForcingToImportant(newToken);
+                        mProcessStateController.setForcingToImportant(pr, newToken);
                         changed = true;
                     } catch (RemoteException e) {
                         // If the process died while doing this, we will later
@@ -5849,7 +5860,7 @@
             }
 
             if (changed) {
-                updateOomAdjLocked(pr, OOM_ADJ_REASON_UI_VISIBILITY);
+                mProcessStateController.runUpdate(pr, OOM_ADJ_REASON_UI_VISIBILITY);
             }
         }
     }
@@ -7269,7 +7280,7 @@
 
         if ((info.flags & PERSISTENT_MASK) == PERSISTENT_MASK) {
             app.setPersistent(true);
-            app.mState.setMaxAdj(ProcessList.PERSISTENT_PROC_ADJ);
+            mProcessStateController.setMaxAdj(app, ProcessList.PERSISTENT_PROC_ADJ);
         }
         if (app.getThread() == null && mPersistentStartingProcesses.indexOf(app) < 0) {
             mPersistentStartingProcesses.add(app);
@@ -7372,7 +7383,7 @@
                 mServices.updateScreenStateLocked(isAwake);
                 reportCurWakefulnessUsageEvent();
                 mActivityTaskManager.onScreenAwakeChanged(isAwake);
-                mOomAdjuster.onWakefulnessChanged(wakefulness);
+                mProcessStateController.setWakefulness(wakefulness);
 
                 updateOomAdjLocked(OOM_ADJ_REASON_UI_VISIBILITY);
             }
@@ -8269,7 +8280,16 @@
                         setThreadScheduler(proc.getRenderThreadTid(),
                                 SCHED_FIFO | SCHED_RESET_ON_FORK, 1);
                     } else {
-                        setThreadPriority(proc.getRenderThreadTid(), THREAD_PRIORITY_TOP_APP_BOOST);
+                        if (Flags.resetOnForkEnabled()) {
+                            if (Process.getThreadScheduler(proc.getRenderThreadTid())
+                                    == Process.SCHED_OTHER) {
+                                Process.setThreadScheduler(proc.getRenderThreadTid(),
+                                    Process.SCHED_OTHER | Process.SCHED_RESET_ON_FORK,
+                                    0);
+                            }
+                        }
+                        setThreadPriority(proc.getRenderThreadTid(),
+                            THREAD_PRIORITY_TOP_APP_BOOST);
                     }
                 }
             } else {
@@ -8332,16 +8352,10 @@
                         Slog.w(TAG, "setHasTopUi called on unknown pid: " + pid);
                         return;
                     }
-                    if (pr.mState.hasTopUi() != hasTopUi) {
-                        if (DEBUG_OOM_ADJ) {
-                            Slog.d(TAG, "Setting hasTopUi=" + hasTopUi + " for pid=" + pid);
-                        }
-                        pr.mState.setHasTopUi(hasTopUi);
-                        changed = true;
-                    }
+                    changed = mProcessStateController.setHasTopUi(pr, hasTopUi);
                 }
                 if (changed) {
-                    updateOomAdjLocked(pr, OOM_ADJ_REASON_UI_VISIBILITY);
+                    mProcessStateController.runUpdate(pr, OOM_ADJ_REASON_UI_VISIBILITY);
                 }
             }
         } finally {
@@ -12811,6 +12825,8 @@
             final long lostRAM = memInfo.getTotalSizeKb()
                     - (ss[INDEX_TOTAL_PSS] - ss[INDEX_TOTAL_SWAP_PSS])
                     - memInfo.getFreeSizeKb() - memInfo.getCachedSizeKb()
+                    // NR_SHMEM is subtracted twice (getCachedSizeKb() and getKernelUsedSizeKb())
+                    + memInfo.getShmemSizeKb()
                     - kernelUsed - memInfo.getZramTotalSizeKb();
             if (!opts.isCompact) {
                 pw.print(" Used RAM: "); pw.print(stringifyKBSize(ss[INDEX_TOTAL_PSS] - cachedPss
@@ -13324,6 +13340,8 @@
             long lostRAM = memInfo.getTotalSizeKb()
                     - (ss[INDEX_TOTAL_PSS] - ss[INDEX_TOTAL_SWAP_PSS])
                     - memInfo.getFreeSizeKb() - memInfo.getCachedSizeKb()
+                    // NR_SHMEM is subtracted twice (getCachedSizeKb() and getKernelUsedSizeKb())
+                    + memInfo.getShmemSizeKb()
                     - memInfo.getKernelUsedSizeKb() - memInfo.getZramTotalSizeKb();
             proto.write(MemInfoDumpProto.USED_PSS_KB, ss[INDEX_TOTAL_PSS] - cachedPss);
             proto.write(MemInfoDumpProto.USED_KERNEL_KB, memInfo.getKernelUsedSizeKb());
@@ -13610,6 +13628,7 @@
             throws TransactionTooLargeException {
         enforceNotIsolatedCaller("startService");
         enforceAllowedToStartOrBindServiceIfSdkSandbox(service);
+        addCreatorToken(service);
         if (service != null) {
             // Refuse possible leaked file descriptors
             if (service.hasFileDescriptors()) {
@@ -13871,6 +13890,7 @@
 
         validateServiceInstanceName(instanceName);
 
+        addCreatorToken(service);
         try {
             if (Trace.isTagEnabled(Trace.TRACE_TAG_ACTIVITY_MANAGER)) {
                 final ComponentName cn = service.getComponent();
@@ -14068,10 +14088,14 @@
                 proc.setInFullBackup(true);
             }
             r.app = proc;
+            // TODO(b/369300367): This code suggests there could be a previous backup being
+            //  replaced here, but an OomAdjsuter update is not triggered on the previous app
+            //  (whose state will change from being removed from mBackupTargets).
             final BackupRecord backupTarget = mBackupTargets.get(targetUserId);
             oldBackupUid = backupTarget != null ? backupTarget.appInfo.uid : -1;
             newBackupUid = proc.isInFullBackup() ? r.appInfo.uid : -1;
             mBackupTargets.put(targetUserId, r);
+            mProcessStateController.setBackupTarget(proc, targetUserId);
 
             proc.mProfile.addHostingComponentType(HOSTING_COMPONENT_TYPE_BACKUP);
 
@@ -14125,6 +14149,7 @@
                 }
                 mBackupTargets.removeAt(indexOfKey);
             }
+            mProcessStateController.stopBackupTarget(userId);
         }
 
         JobSchedulerInternal js = LocalServices.getService(JobSchedulerInternal.class);
@@ -14203,6 +14228,8 @@
 
                 // Not backing this app up any more; reset its OOM adjustment
                 final ProcessRecord proc = backupTarget.app;
+                // TODO(b/369300367): Triggering the update before the state is actually set
+                //  seems wrong.
                 updateOomAdjLocked(proc, OOM_ADJ_REASON_BACKUP);
                 proc.setInFullBackup(false);
                 proc.mProfile.clearHostingComponentType(HOSTING_COMPONENT_TYPE_BACKUP);
@@ -14221,6 +14248,7 @@
                 }
             } finally {
                 mBackupTargets.delete(userId);
+                mProcessStateController.stopBackupTarget(userId);
             }
         }
 
@@ -15293,7 +15321,8 @@
                             proc.info.packageName, proc.info.uid, proc.getPid(), isForeground);
                 }
             }
-            psr.setHasForegroundServices(isForeground, fgServiceTypes, hasTypeNoneFgs);
+            mProcessStateController.setHasForegroundServices(psr, isForeground, fgServiceTypes,
+                    hasTypeNoneFgs);
             ArrayList<ProcessRecord> curProcs = mForegroundPackages.get(proc.info.packageName,
                     proc.info.uid);
             if (isForeground) {
@@ -15324,7 +15353,7 @@
                     ProcessChangeItem.CHANGE_FOREGROUND_SERVICES, fgServiceTypes);
         }
         if (oomAdj) {
-            updateOomAdjLocked(proc, OOM_ADJ_REASON_UI_VISIBILITY);
+            mProcessStateController.runUpdate(proc, OOM_ADJ_REASON_UI_VISIBILITY);
         }
     }
 
@@ -15374,7 +15403,7 @@
      */
     @GuardedBy("this")
     void enqueueOomAdjTargetLocked(ProcessRecord app) {
-        mOomAdjuster.enqueueOomAdjTargetLocked(app);
+        mProcessStateController.enqueueUpdateTarget(app);
     }
 
     /**
@@ -15382,7 +15411,7 @@
      */
     @GuardedBy("this")
     void removeOomAdjTargetLocked(ProcessRecord app, boolean procDied) {
-        mOomAdjuster.removeOomAdjTargetLocked(app, procDied);
+        mProcessStateController.removeUpdateTarget(app, procDied);
     }
 
     /**
@@ -15391,7 +15420,7 @@
      */
     @GuardedBy("this")
     void updateOomAdjPendingTargetsLocked(@OomAdjReason int oomAdjReason) {
-        mOomAdjuster.updateOomAdjPendingTargetsLocked(oomAdjReason);
+        mProcessStateController.runPendingUpdate(oomAdjReason);
     }
 
     static final class ProcStatsRunnable implements Runnable {
@@ -15410,7 +15439,7 @@
 
     @GuardedBy("this")
     final void updateOomAdjLocked(@OomAdjReason int oomAdjReason) {
-        mOomAdjuster.updateOomAdjLocked(oomAdjReason);
+        mProcessStateController.runFullUpdate(oomAdjReason);
     }
 
     /**
@@ -15422,7 +15451,7 @@
      */
     @GuardedBy("this")
     final boolean updateOomAdjLocked(ProcessRecord app, @OomAdjReason int oomAdjReason) {
-        return mOomAdjuster.updateOomAdjLocked(app, oomAdjReason);
+        return mProcessStateController.runUpdate(app, oomAdjReason);
     }
 
     @Override
@@ -15687,7 +15716,7 @@
 
     @GuardedBy({"this", "mProcLock"})
     final void setUidTempAllowlistStateLSP(int uid, boolean onAllowlist) {
-        mOomAdjuster.setUidTempAllowlistStateLSP(uid, onAllowlist);
+        mProcessStateController.setUidTempAllowlistStateLSP(uid, onAllowlist);
     }
 
     private void trimApplications(boolean forceFullOomAdj, @OomAdjReason int oomAdjReason) {
@@ -16737,12 +16766,9 @@
                         return;
                     }
                 }
-                if (pr.mState.hasOverlayUi() == hasOverlayUi) {
-                    return;
+                if (mProcessStateController.setHasOverlayUi(pr, hasOverlayUi)) {
+                    mProcessStateController.runUpdate(pr, OOM_ADJ_REASON_UI_VISIBILITY);
                 }
-                pr.mState.setHasOverlayUi(hasOverlayUi);
-                //Slog.i(TAG, "Setting hasOverlayUi=" + pr.hasOverlayUi + " for pid=" + pid);
-                updateOomAdjLocked(pr, OOM_ADJ_REASON_UI_VISIBILITY);
             }
         }
 
@@ -17148,6 +17174,7 @@
                 Slog.v(TAG_SERVICE,
                         "startServiceInPackage: " + service + " type=" + resolvedType);
             }
+            addCreatorToken(service);
             final long origId = Binder.clearCallingIdentity();
             ComponentName res;
             try {
@@ -17973,6 +18000,11 @@
                         userId, reason, exitInfoReason);
             }
         }
+
+        @Override
+        public void addCreatorToken(Intent intent) {
+            ActivityManagerService.this.addCreatorToken(intent);
+        }
     }
 
     long inputDispatchingTimedOut(int pid, final boolean aboveSystem, TimeoutRecord timeoutRecord) {
@@ -19114,6 +19146,7 @@
     private static final Map<IntentCreatorToken.Key, WeakReference<IntentCreatorToken>>
             sIntentCreatorTokenCache = new ConcurrentHashMap<>();
 
+    private static Handler sCreatorTokenCacheCleaner;
     /**
      * A binder token used to keep track of which app created the intent. This token can be used to
      * defend against intent redirect attacks. It stores uid of the intent creator and key fields of
@@ -19121,13 +19154,16 @@
      *
      * @hide
      */
+    @VisibleForTesting
     public static final class IntentCreatorToken extends Binder {
         @NonNull
         private final Key mKeyFields;
+        private final WeakReference<IntentCreatorToken> mRef;
 
         public IntentCreatorToken(int creatorUid, Intent intent) {
             super();
             this.mKeyFields = new Key(creatorUid, intent);
+            mRef = new WeakReference<>(this);
         }
 
         public int getCreatorUid() {
@@ -19145,6 +19181,26 @@
                     new Key(token.mKeyFields.mCreatorUid, intent));
         }
 
+        @Override
+        protected void finalize() throws Throwable {
+            try {
+                sCreatorTokenCacheCleaner.sendMessage(PooledLambda.obtainMessage(
+                        IntentCreatorToken::completeFinalize, this));
+            } finally {
+                super.finalize();
+            }
+        }
+
+        private void completeFinalize() {
+            synchronized (sIntentCreatorTokenCache) {
+                WeakReference<IntentCreatorToken> current = sIntentCreatorTokenCache.get(
+                        mKeyFields);
+                if (current == mRef) {
+                    sIntentCreatorTokenCache.remove(mKeyFields);
+                }
+            }
+        }
+
         private static class Key {
             private Key(int creatorUid, Intent intent) {
                 this.mCreatorUid = creatorUid;
@@ -19187,9 +19243,57 @@
             @Override
             public int hashCode() {
                 return Objects.hash(mCreatorUid, mAction, mData, mType, mPackage, mComponent,
-                        mFlags,
-                        mClipDataUris);
+                        mFlags, mClipDataUris);
             }
         }
     }
+
+    /**
+     * Add a creator token for all embedded intents (stored as extra) of the given intent.
+     *
+     * @param intent The given intent
+     * @hide
+     */
+    public void addCreatorToken(@Nullable Intent intent) {
+        if (!preventIntentRedirect()) return;
+
+        if (intent == null || intent.getExtraIntentKeys() == null) return;
+        for (String key : intent.getExtraIntentKeys()) {
+            try {
+                Intent extraIntent = intent.getParcelableExtra(key, Intent.class);
+                if (extraIntent == null) {
+                    Slog.w(TAG, "The key {" + key
+                            + "} does not correspond to an intent in the extra bundle.");
+                    continue;
+                }
+                Slog.wtf(TAG, "A creator token is added to an intent.");
+                IBinder creatorToken = createIntentCreatorToken(extraIntent);
+                if (creatorToken != null) {
+                    extraIntent.setCreatorToken(creatorToken);
+                }
+            } catch (Exception e) {
+                Slog.wtf(TAG,
+                        "Something went wrong when trying to add creator token for embedded "
+                                + "intents of intent: ."
+                                + intent, e);
+            }
+        }
+    }
+
+    private IBinder createIntentCreatorToken(Intent intent) {
+        if (IntentCreatorToken.isValid(intent)) return null;
+        int creatorUid = getCallingUid();
+        IntentCreatorToken.Key key = new IntentCreatorToken.Key(creatorUid, intent);
+        IntentCreatorToken token;
+        synchronized (sIntentCreatorTokenCache) {
+            WeakReference<IntentCreatorToken> ref = sIntentCreatorTokenCache.get(key);
+            if (ref == null || ref.get() == null) {
+                token = new IntentCreatorToken(creatorUid, intent);
+                sIntentCreatorTokenCache.put(key, token.mRef);
+            } else {
+                token = ref.get();
+            }
+        }
+        return token;
+    }
 }
diff --git a/services/core/java/com/android/server/am/AppProfiler.java b/services/core/java/com/android/server/am/AppProfiler.java
index dda48ad..4f2d69e 100644
--- a/services/core/java/com/android/server/am/AppProfiler.java
+++ b/services/core/java/com/android/server/am/AppProfiler.java
@@ -1356,6 +1356,7 @@
     @GuardedBy("mService")
     void setMemFactorOverrideLocked(@MemFactor int factor) {
         mMemFactorOverride = factor;
+        mService.mProcessStateController.setIsLastMemoryLevelNormal(isLastMemoryLevelNormal());
     }
 
     @GuardedBy({"mService", "mProcLock"})
@@ -1423,6 +1424,7 @@
         }
 
         mLastMemoryLevel = memFactor;
+        mService.mProcessStateController.setIsLastMemoryLevelNormal(isLastMemoryLevelNormal());
         mLastNumProcesses = mService.mProcessList.getLruSizeLOSP();
 
         // Dispatch UI_HIDDEN to processes that need it
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index 4ac42ec..592d89e 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -833,6 +833,14 @@
         return sService;
     }
 
+    /**
+     * Override the {@link IBatteryStats} service, for testing.
+     */
+    @VisibleForTesting
+    public static void overrideService(IBatteryStats service) {
+        sService = service;
+    }
+
     @Override
     public int getServiceType() {
         return ServiceType.BATTERY_STATS;
diff --git a/services/core/java/com/android/server/am/ContentProviderHelper.java b/services/core/java/com/android/server/am/ContentProviderHelper.java
index da40826..6e09a84 100644
--- a/services/core/java/com/android/server/am/ContentProviderHelper.java
+++ b/services/core/java/com/android/server/am/ContentProviderHelper.java
@@ -90,7 +90,7 @@
 import com.android.internal.util.FrameworkStatsLog;
 import com.android.server.LocalManagerRegistry;
 import com.android.server.LocalServices;
-import com.android.server.RescueParty;
+import com.android.server.crashrecovery.CrashRecoveryAdaptor;
 import com.android.server.pm.UserManagerInternal;
 import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.sdksandbox.SdkSandboxManagerLocal;
@@ -325,7 +325,8 @@
                     final int verifiedAdj = cpr.proc.mState.getVerifiedAdj();
                     boolean success = !serviceBindingOomAdjPolicy()
                             || mService.mOomAdjuster.evaluateProviderConnectionAdd(r, cpr.proc)
-                            ? mService.updateOomAdjLocked(cpr.proc, OOM_ADJ_REASON_GET_PROVIDER)
+                            ? mService.mProcessStateController.runUpdate(cpr.proc,
+                            OOM_ADJ_REASON_GET_PROVIDER)
                             : true;
                     // XXX things have changed so updateOomAdjLocked doesn't actually tell us
                     // if the process has been successfully adjusted.  So to reduce races with
@@ -534,10 +535,9 @@
                             if (ActivityManagerDebugConfig.DEBUG_PROVIDER) {
                                 Slog.d(TAG, "Installing in existing process " + proc);
                             }
-                            final ProcessProviderRecord pr = proc.mProviders;
-                            if (!pr.hasProvider(cpi.name)) {
+                            if (mService.mProcessStateController.addPublishedProvider(proc,
+                                    cpi.name, cpr)) {
                                 checkTime(startTime, "getContentProviderImpl: scheduling install");
-                                pr.installProvider(cpi.name, cpr);
                                 mService.mOomAdjuster.unfreezeTemporarily(proc,
                                         CachedAppOptimizer.UNFREEZE_REASON_GET_PROVIDER);
                                 try {
@@ -881,7 +881,8 @@
             ComponentName comp = new ComponentName(cpr.info.packageName, cpr.info.name);
             ContentProviderRecord localCpr = mProviderMap.getProviderByClass(comp, userId);
             if (localCpr.hasExternalProcessHandles()) {
-                if (localCpr.removeExternalProcessHandleLocked(token)) {
+                if (mService.mProcessStateController.removeExternalProviderClient(localCpr,
+                        token)) {
                     mService.updateOomAdjLocked(localCpr.proc, OOM_ADJ_REASON_REMOVE_PROVIDER);
                 } else {
                     Slog.e(TAG, "Attempt to remove content provider " + localCpr
@@ -1381,7 +1382,7 @@
         mService.mOomAdjuster.initSettings();
 
         // Now that the settings provider is published we can consider sending in a rescue party.
-        RescueParty.onSettingsProviderPublished(mService.mContext);
+        CrashRecoveryAdaptor.rescuePartyOnSettingsProviderPublished(mService.mContext);
     }
 
     /**
@@ -1447,7 +1448,8 @@
             String callingPackage, String callingTag, boolean stable, boolean updateLru,
             long startTime, ProcessList processList, @UserIdInt int expectedUserId) {
         if (r == null) {
-            cpr.addExternalProcessHandleLocked(externalProcessToken, callingUid, callingTag);
+            mService.mProcessStateController.addExternalProviderClient(cpr, externalProcessToken,
+                    callingUid, callingTag);
             return null;
         }
 
@@ -1470,7 +1472,7 @@
         if (cpr.proc != null) {
             cpr.proc.mProfile.addHostingComponentType(HOSTING_COMPONENT_TYPE_PROVIDER);
         }
-        pr.addProviderConnection(conn);
+        mService.mProcessStateController.addProviderConnection(r, conn);
         mService.startAssociationLocked(r.uid, r.processName, r.mState.getCurProcState(),
                 cpr.uid, cpr.appInfo.longVersionCode, cpr.name, cpr.info.processName);
         if (updateLru && cpr.proc != null
@@ -1493,7 +1495,8 @@
             ContentProviderRecord cpr, IBinder externalProcessToken, boolean stable,
             boolean enforceDelay, boolean updateOomAdj) {
         if (conn == null) {
-            cpr.removeExternalProcessHandleLocked(externalProcessToken);
+            mService.mProcessStateController.removeExternalProviderClient(cpr,
+                    externalProcessToken);
             return false;
         }
 
@@ -1537,14 +1540,15 @@
             if (cpr.proc != null && !hasProviderConnectionLocked(cpr.proc)) {
                 cpr.proc.mProfile.clearHostingComponentType(HOSTING_COMPONENT_TYPE_PROVIDER);
             }
-            conn.client.mProviders.removeProviderConnection(conn);
+            mService.mProcessStateController.removeProviderConnection(conn.client, conn);
             if (conn.client.mState.getSetProcState()
                     < ActivityManager.PROCESS_STATE_LAST_ACTIVITY) {
                 // The client is more important than last activity -- note the time this
                 // is happening, so we keep the old provider process around a bit as last
                 // activity to avoid thrashing it.
                 if (cpr.proc != null) {
-                    cpr.proc.mProviders.setLastProviderTime(SystemClock.uptimeMillis());
+                    mService.mProcessStateController.setLastProviderTime(cpr.proc,
+                            SystemClock.uptimeMillis());
                 }
             }
             mService.stopAssociationLocked(conn.client.uid, conn.client.processName, cpr.uid,
@@ -1821,7 +1825,7 @@
                 }
             }
             if (removed && cpr.proc != null) {
-                cpr.proc.mProviders.removeProvider(cpr.info.name);
+                mService.mProcessStateController.removePublishedProvider(cpr.proc, cpr.info.name);
             }
         }
 
diff --git a/services/core/java/com/android/server/am/OWNERS b/services/core/java/com/android/server/am/OWNERS
index 2a30ad0..61079fc 100644
--- a/services/core/java/com/android/server/am/OWNERS
+++ b/services/core/java/com/android/server/am/OWNERS
@@ -54,8 +54,9 @@
 per-file *Permission* = patb@google.com
 per-file *Package* = patb@google.com
 
-# OOM Adjuster
+# OOM Adjuster & ProcessStateController
 per-file *Oom* = file:/OOM_ADJUSTER_OWNERS
+per-file ProcessStateController.java = file:/OOM_ADJUSTER_OWNERS
 
 # Miscellaneous
 per-file SettingsToPropertiesMapper.java = omakoto@google.com, yamasani@google.com, dzshen@google.com, zhidou@google.com, tedbauer@google.com
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index 796de19..776a345 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -130,6 +130,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.UserIdInt;
 import android.app.ActivityManager;
 import android.app.ActivityManagerInternal.OomAdjReason;
 import android.app.ActivityThread;
@@ -376,6 +377,7 @@
 
     final ActivityManagerService mService;
     final Injector mInjector;
+    final GlobalState mGlobalState;
     final ProcessList mProcessList;
     final ActivityManagerGlobalLock mProcLock;
 
@@ -459,25 +461,34 @@
 
         void setThreadPriority(int tid, int priority) {
             if (Flags.resetOnForkEnabled()) {
-                Process.setThreadScheduler(tid,
-                    Process.SCHED_OTHER | Process.SCHED_RESET_ON_FORK,
-                    priority);
-            } else {
-                 Process.setThreadPriority(tid, priority);
+                if (Process.getThreadScheduler(tid) == Process.SCHED_OTHER) {
+                    Process.setThreadScheduler(tid,
+                        Process.SCHED_OTHER | Process.SCHED_RESET_ON_FORK,
+                        0);
+                }
             }
+            Process.setThreadPriority(tid, priority);
         }
 
     }
 
+    // TODO(b/346822474): hook up global state usage.
+    interface GlobalState {
+        /** Is device's screen on. */
+        boolean isAwake();
+
+        /** What process is running a backup for a given userId. */
+        ProcessRecord getBackupTarget(@UserIdInt int userId);
+
+        /** Is memory level normal since last evaluation. */
+        boolean isLastMemoryLevelNormal();
+    }
+
     boolean isChangeEnabled(@CachedCompatChangeId int cachedCompatChangeId,
             ApplicationInfo app, boolean defaultValue) {
         return mInjector.isChangeEnabled(cachedCompatChangeId, app, defaultValue);
     }
 
-    OomAdjuster(ActivityManagerService service, ProcessList processList, ActiveUids activeUids) {
-        this(service, processList, activeUids, createAdjusterThread());
-    }
-
     static ServiceThread createAdjusterThread() {
         // The process group is usually critical to the response time of foreground app, so the
         // setter should apply it as soon as possible.
@@ -488,18 +499,9 @@
     }
 
     OomAdjuster(ActivityManagerService service, ProcessList processList, ActiveUids activeUids,
-            ServiceThread adjusterThread) {
-        this(service, processList, activeUids, adjusterThread, new Injector());
-    }
-
-    OomAdjuster(ActivityManagerService service, ProcessList processList, ActiveUids activeUids,
-            Injector injector) {
-        this(service, processList, activeUids, createAdjusterThread(), injector);
-    }
-
-    OomAdjuster(ActivityManagerService service, ProcessList processList, ActiveUids activeUids,
-            ServiceThread adjusterThread, Injector injector) {
+            ServiceThread adjusterThread, GlobalState globalState, Injector injector) {
         mService = service;
+        mGlobalState = globalState;
         mInjector = injector;
         mProcessList = processList;
         mProcLock = service.mProcLock;
@@ -1815,9 +1817,36 @@
         }
     }
 
+    private boolean isDeviceFullyAwake() {
+        if (Flags.pushGlobalStateToOomadjuster()) {
+            return mGlobalState.isAwake();
+        } else {
+            return mService.mWakefulness.get() == PowerManagerInternal.WAKEFULNESS_AWAKE;
+        }
+    }
+
     private boolean isScreenOnOrAnimatingLocked(ProcessStateRecord state) {
-        return mService.mWakefulness.get() == PowerManagerInternal.WAKEFULNESS_AWAKE
-                || state.isRunningRemoteAnimation();
+        return isDeviceFullyAwake() || state.isRunningRemoteAnimation();
+    }
+
+    private boolean isBackupProcess(ProcessRecord app) {
+        if (Flags.pushGlobalStateToOomadjuster()) {
+            return app == mGlobalState.getBackupTarget(app.userId);
+        } else {
+            final BackupRecord backupTarget = mService.mBackupTargets.get(app.userId);
+            if (backupTarget == null) {
+                return false;
+            }
+            return app == backupTarget.app;
+        }
+    }
+
+    private boolean isLastMemoryLevelNormal() {
+        if (Flags.pushGlobalStateToOomadjuster()) {
+            return mGlobalState.isLastMemoryLevelNormal();
+        } else {
+            return mService.mAppProfiler.isLastMemoryLevelNormal();
+        }
     }
 
     @GuardedBy({"mService", "mProcLock"})
@@ -2258,8 +2287,7 @@
         state.setHasStartedServices(false);
         state.setAdjSeq(mAdjSeq);
 
-        final BackupRecord backupTarget = mService.mBackupTargets.get(app.userId);
-        if (backupTarget != null && app == backupTarget.app) {
+        if (isBackupProcess(app)) {
             // If possible we want to avoid killing apps while they're being backed up
             if (adj > BACKUP_APP_ADJ) {
                 if (DEBUG_BACKUP) Slog.v(TAG_BACKUP, "oom BACKUP_APP_ADJ for " + app);
@@ -2525,8 +2553,7 @@
                     double cachedRestoreThreshold =
                             mProcessList.getCachedRestoreThresholdKb() * thresholdModifier;
 
-                    if (!mService.mAppProfiler.isLastMemoryLevelNormal()
-                            && lastPssOrRss >= cachedRestoreThreshold) {
+                    if (!isLastMemoryLevelNormal() && lastPssOrRss >= cachedRestoreThreshold) {
                         state.setServiceHighRam(true);
                         state.setServiceB(true);
                         //Slog.i(TAG, "ADJ " + app + " high ram!");
@@ -2620,7 +2647,7 @@
         // Put bound foreground services in a special sched group for additional
         // restrictions on screen off
         if (state.getCurProcState() >= PROCESS_STATE_BOUND_FOREGROUND_SERVICE
-                && mService.mWakefulness.get() != PowerManagerInternal.WAKEFULNESS_AWAKE
+                && !isDeviceFullyAwake()
                 && !state.shouldScheduleLikeTopApp()) {
             if (schedGroup > SCHED_GROUP_RESTRICTED) {
                 schedGroup = SCHED_GROUP_RESTRICTED;
@@ -2909,8 +2936,7 @@
                         clientProcState = PROCESS_STATE_FOREGROUND_SERVICE;
                     } else if (cr.hasFlag(Context.BIND_FOREGROUND_SERVICE)) {
                         clientProcState = PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
-                    } else if (mService.mWakefulness.get()
-                            == PowerManagerInternal.WAKEFULNESS_AWAKE
+                    } else if (isDeviceFullyAwake()
                             && cr.hasFlag(Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE)) {
                         clientProcState = PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
                     } else {
diff --git a/services/core/java/com/android/server/am/OomAdjusterModernImpl.java b/services/core/java/com/android/server/am/OomAdjusterModernImpl.java
index fb1c2e9..e452c45 100644
--- a/services/core/java/com/android/server/am/OomAdjusterModernImpl.java
+++ b/services/core/java/com/android/server/am/OomAdjusterModernImpl.java
@@ -756,18 +756,9 @@
             new ComputeConnectionsConsumer();
 
     OomAdjusterModernImpl(ActivityManagerService service, ProcessList processList,
-            ActiveUids activeUids) {
-        this(service, processList, activeUids, createAdjusterThread());
-    }
-
-    OomAdjusterModernImpl(ActivityManagerService service, ProcessList processList,
-            ActiveUids activeUids, ServiceThread adjusterThread) {
-        super(service, processList, activeUids, adjusterThread);
-    }
-
-    OomAdjusterModernImpl(ActivityManagerService service, ProcessList processList,
-            ActiveUids activeUids, Injector injector) {
-        super(service, processList, activeUids, injector);
+            ActiveUids activeUids, ServiceThread adjusterThread, GlobalState globalState,
+            Injector injector) {
+        super(service, processList, activeUids, adjusterThread, globalState, injector);
     }
 
     private final ProcessRecordNodes mProcessRecordProcStateNodes = new ProcessRecordNodes(
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index 57922d5..5236b03 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -3439,12 +3439,12 @@
             state.setCurrentSchedulingGroup(ProcessList.SCHED_GROUP_DEFAULT);
             state.setSetSchedGroup(ProcessList.SCHED_GROUP_DEFAULT);
             r.setPersistent(true);
-            state.setMaxAdj(ProcessList.PERSISTENT_PROC_ADJ);
+            mService.mProcessStateController.setMaxAdj(r, ProcessList.PERSISTENT_PROC_ADJ);
         }
         if (isolated && isolatedUid != 0) {
             // Special case for startIsolatedProcess (internal only) - assume the process
             // is required by the system server to prevent it being killed.
-            state.setMaxAdj(ProcessList.PERSISTENT_SERVICE_ADJ);
+            mService.mProcessStateController.setMaxAdj(r, ProcessList.PERSISTENT_SERVICE_ADJ);
         }
         addProcessNameLocked(r);
         return r;
@@ -3629,42 +3629,68 @@
     }
 
     @GuardedBy({"mService", "mProcLock"})
-    private int updateLruProcessInternalLSP(ProcessRecord app, long now, int index,
-            int lruSeq, String what, Object obj, ProcessRecord srcApp) {
+    private int offerLruProcessInternalLSP(ProcessRecord app, long now, String what, Object obj,
+            ProcessRecord srcApp) {
         app.setLastActivityTime(now);
 
         if (app.hasActivitiesOrRecentTasks()) {
             // Don't want to touch dependent processes that are hosting activities.
-            return index;
+            return -1;
         }
 
-        int lrui = mLruProcesses.lastIndexOf(app);
+        final int lrui = mLruProcesses.lastIndexOf(app);
         if (lrui < 0) {
             Slog.wtf(TAG, "Adding dependent process " + app + " not on LRU list: "
                     + what + " " + obj + " from " + srcApp);
-            return index;
         }
+        return lrui;
+    }
 
-        if (lrui >= index) {
-            // Don't want to cause this to move dependent processes *back* in the
-            // list as if they were less frequently used.
-            return index;
-        }
+    /**
+     * This method is called after the indices array is populated by the indices offered by
+     * {@link #offerLruProcessInternalLSP} to actually move the processes to the desired locations
+     * in the LRU list. Since the indices array is a SparseBooleanArray, the indices are sorted
+     * and this allows us to preserve the previous order of the processes relative to each other.
+     * Key of the indices array holds the current index of the process in the LRU list and the value
+     * is a boolean indicating whether the process is an activity process or not. Activity processes
+     * are moved to the nextActivityIndex and non-activity processes are moved to the nextIndex
+     * positions, which are provided by the caller.
+     *
+     * @param indices The indices of the processes to move.
+     * @param nextActivityIndex The next index to insert an activity process.
+     * @param nextIndex The next index to insert a non-activity process.
+     */
+    @GuardedBy({"mService", "mProcLock"})
+    private void completeLruProcessInternalLSP(SparseBooleanArray indices, int nextActivityIndex,
+            int nextIndex) {
+        for (int i = indices.size() - 1; i >= 0; i--) {
+            final int lrui = indices.keyAt(i);
+            if (lrui < 0) {
+                // Rest of the indices are invalid, we can return early.
+                return;
+            }
+            final boolean isActivity = indices.valueAt(i);
+            int index = isActivity ? nextActivityIndex : nextIndex;
 
-        if (lrui >= mLruProcessActivityStart && index < mLruProcessActivityStart) {
-            // Don't want to touch dependent processes that are hosting activities.
-            return index;
-        }
+            if (lrui >= index) {
+                // Don't want to cause this to move dependent processes *back* in the
+                // list as if they were less frequently used.
+                continue;
+            }
 
-        mLruProcesses.remove(lrui);
-        if (index > 0) {
+            final ProcessRecord app = mLruProcesses.remove(lrui);
             index--;
+            if (DEBUG_LRU) Slog.d(TAG_LRU, "Moving dep from " + lrui + " to " + index
+                    + " in LRU list: " + app);
+            mLruProcesses.add(index, app);
+            app.setLruSeq(mLruSeq);
+
+            if (isActivity) {
+                nextActivityIndex = index;
+            } else {
+                nextIndex = index;
+            }
         }
-        if (DEBUG_LRU) Slog.d(TAG_LRU, "Moving dep from " + lrui + " to " + index
-                + " in LRU list: " + app);
-        mLruProcesses.add(index, app);
-        app.setLruSeq(lruSeq);
-        return index;
     }
 
     /**
@@ -4058,6 +4084,15 @@
 
         app.setLruSeq(mLruSeq);
 
+        // Key of the indices array holds the current index of the process in the LRU list and the
+        // value is a boolean indicating whether the process is an activity process or not.
+        // Activity processes will be moved to the nextActivityIndex and non-activity processes will
+        // be moved to the nextIndex positions when completeLruProcessInternalLSP is called.
+        // Since SparseBooleanArray's keys are sorted, we'll be able to keep the existing order of
+        // the processes relative to each other after the move.
+        final SparseBooleanArray indices = new SparseBooleanArray(psr.numberOfConnections()
+                + app.mProviders.numberOfProviderConnections());
+
         // If the app is currently using a content provider or service,
         // bump those processes as well.
         for (int j = psr.numberOfConnections() - 1; j >= 0; j--) {
@@ -4069,16 +4104,12 @@
                     && !cr.binding.service.app.isPersistent()) {
                 if (cr.binding.service.app.mServices.hasClientActivities()) {
                     if (nextActivityIndex >= 0) {
-                        nextActivityIndex = updateLruProcessInternalLSP(cr.binding.service.app,
-                                now,
-                                nextActivityIndex, mLruSeq,
-                                "service connection", cr, app);
+                        indices.append(offerLruProcessInternalLSP(cr.binding.service.app, now,
+                                "service connection", cr, app), true);
                     }
                 } else {
-                    nextIndex = updateLruProcessInternalLSP(cr.binding.service.app,
-                            now,
-                            nextIndex, mLruSeq,
-                            "service connection", cr, app);
+                    indices.append(offerLruProcessInternalLSP(cr.binding.service.app, now,
+                            "service connection", cr, app), false);
                 }
             }
         }
@@ -4086,10 +4117,11 @@
         for (int j = ppr.numberOfProviderConnections() - 1; j >= 0; j--) {
             ContentProviderRecord cpr = ppr.getProviderConnectionAt(j).provider;
             if (cpr.proc != null && cpr.proc.getLruSeq() != mLruSeq && !cpr.proc.isPersistent()) {
-                nextIndex = updateLruProcessInternalLSP(cpr.proc, now, nextIndex, mLruSeq,
-                        "provider reference", cpr, app);
+                indices.append(offerLruProcessInternalLSP(cpr.proc, now,
+                        "provider reference", cpr, app), false);
             }
         }
+        completeLruProcessInternalLSP(indices, nextActivityIndex, nextIndex);
     }
 
     @GuardedBy(anyOf = {"mService", "mProcLock"})
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index 3e71d00..b51db13 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -17,6 +17,7 @@
 package com.android.server.am;
 
 import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_ACTIVITY;
+import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_UI_VISIBILITY;
 
 import static com.android.internal.util.Preconditions.checkArgument;
 import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
@@ -1192,7 +1193,7 @@
         setWaitingToKill(null);
 
         mState.onCleanupApplicationRecordLSP();
-        mServices.onCleanupApplicationRecordLocked();
+        mService.mProcessStateController.onCleanupApplicationRecord(mServices);
         mReceivers.onCleanupApplicationRecordLocked();
         mService.mOomAdjuster.onProcessEndLocked(this);
 
@@ -1638,7 +1639,7 @@
             updateProcessInfo(false /* updateServiceConnectionActivities */,
                     true /* activityChange */, true /* updateOomAdj */);
             setPendingUiClean(true);
-            mState.setHasShownUi(true);
+            mService.mProcessStateController.setHasShownUi(this, true);
             mState.forceProcessStateUpTo(topProcessState);
         }
     }
@@ -1657,7 +1658,10 @@
             return;
         }
         synchronized (mService) {
-            mState.setRunningRemoteAnimation(runningRemoteAnimation);
+            if (mService.mProcessStateController.setRunningRemoteAnimation(this,
+                    runningRemoteAnimation)) {
+                mService.mProcessStateController.runUpdate(this, OOM_ADJ_REASON_UI_VISIBILITY);
+            }
         }
     }
 
diff --git a/services/core/java/com/android/server/am/ProcessStateController.java b/services/core/java/com/android/server/am/ProcessStateController.java
new file mode 100644
index 0000000..01468c6
--- /dev/null
+++ b/services/core/java/com/android/server/am/ProcessStateController.java
@@ -0,0 +1,644 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.am;
+
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_OOM_ADJ;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.UserIdInt;
+import android.app.ActivityManager;
+import android.app.ActivityManagerInternal;
+import android.content.pm.ServiceInfo;
+import android.os.IBinder;
+import android.os.PowerManagerInternal;
+import android.util.Slog;
+import android.util.SparseArray;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.server.ServiceThread;
+
+/**
+ * ProcessStateController is responsible for maintaining state that can affect the OomAdjuster
+ * computations of a process. Any state that can affect a process's importance must be set by
+ * only ProcessStateController.
+ */
+public class ProcessStateController {
+    public static String TAG = "ProcessStateController";
+
+    private final OomAdjuster mOomAdjuster;
+
+    private final GlobalState mGlobalState = new GlobalState();
+
+    private ProcessStateController(ActivityManagerService ams, ProcessList processList,
+            ActiveUids activeUids, ServiceThread handlerThread, OomAdjuster.Injector oomAdjInjector,
+            boolean useOomAdjusterModernImpl) {
+        mOomAdjuster = useOomAdjusterModernImpl
+                ? new OomAdjusterModernImpl(ams, processList, activeUids, handlerThread,
+                mGlobalState, oomAdjInjector)
+                : new OomAdjuster(ams, processList, activeUids, handlerThread, mGlobalState,
+                        oomAdjInjector);
+    }
+
+    /**
+     * Get the instance of OomAdjuster that ProcessStateController is using.
+     * Must only be interacted with while holding the ActivityManagerService lock.
+     */
+    public OomAdjuster getOomAdjuster() {
+        return mOomAdjuster;
+    }
+
+    /**
+     * Add a process to evaluated the next time an update is run.
+     */
+    public void enqueueUpdateTarget(@NonNull ProcessRecord proc) {
+        mOomAdjuster.enqueueOomAdjTargetLocked(proc);
+    }
+
+    /**
+     * Remove a process that was added by {@link #enqueueUpdateTarget}.
+     */
+    public void removeUpdateTarget(@NonNull ProcessRecord proc, boolean procDied) {
+        mOomAdjuster.removeOomAdjTargetLocked(proc, procDied);
+    }
+
+    /**
+     * Trigger an update on a single process (and any processes that have been enqueued with
+     * {@link #enqueueUpdateTarget}).
+     */
+    public boolean runUpdate(@NonNull ProcessRecord proc,
+            @ActivityManagerInternal.OomAdjReason int oomAdjReason) {
+        return mOomAdjuster.updateOomAdjLocked(proc, oomAdjReason);
+    }
+
+    /**
+     * Trigger an update on all processes that have been enqueued with {@link #enqueueUpdateTarget}.
+     */
+    public void runPendingUpdate(@ActivityManagerInternal.OomAdjReason int oomAdjReason) {
+        mOomAdjuster.updateOomAdjPendingTargetsLocked(oomAdjReason);
+    }
+
+    /**
+     * Trigger an update on all processes.
+     */
+    public void runFullUpdate(@ActivityManagerInternal.OomAdjReason int oomAdjReason) {
+        mOomAdjuster.updateOomAdjLocked(oomAdjReason);
+    }
+
+    /**
+     * Trigger an update on any processes that have been marked for follow up during a previous
+     * update.
+     */
+    public void runFollowUpUpdate() {
+        mOomAdjuster.updateOomAdjFollowUpTargetsLocked();
+    }
+
+    private static class GlobalState implements OomAdjuster.GlobalState {
+        public boolean isAwake = true;
+        // TODO(b/369300367): Maintaining global state for backup processes is a bit convoluted.
+        //  ideally the state gets migrated to ProcessStateRecord.
+        public final SparseArray<ProcessRecord> backupTargets = new SparseArray<>();
+        public boolean isLastMemoryLevelNormal = true;
+
+        public boolean isAwake() {
+            return isAwake;
+        }
+
+        public ProcessRecord getBackupTarget(@UserIdInt int userId) {
+            return backupTargets.get(userId);
+        }
+
+        public boolean isLastMemoryLevelNormal() {
+            return isLastMemoryLevelNormal;
+        }
+    }
+
+    /*************************** Global State Events ***************************/
+    /**
+     * Set which process state Top processes should get.
+     */
+    public void setTopProcessState(@ActivityManager.ProcessState int procState) {
+        // TODO(b/302575389): Migrate state pulled from ATMS to a pushed model
+        throw new UnsupportedOperationException("Not implemented yet");
+    }
+
+    /**
+     * Set whether to give Top processes the Top sched group.
+     */
+    public void setUseTopSchedGroupForTopProcess(boolean useTopSchedGroup) {
+        // TODO(b/302575389): Migrate state pulled from ATMS to a pushed model
+        throw new UnsupportedOperationException("Not implemented yet");
+    }
+
+    /**
+     * Set the Top process.
+     */
+    public void setTopApp(@Nullable ProcessRecord proc) {
+        // TODO(b/302575389): Migrate state pulled from ATMS to a pushed model
+        throw new UnsupportedOperationException("Not implemented yet");
+    }
+
+    /**
+     * Set which process is considered the Home process, if any.
+     */
+    public void setHomeProcess(@Nullable ProcessRecord proc) {
+        // TODO(b/302575389): Migrate state pulled from ATMS to a pushed model
+        throw new UnsupportedOperationException("Not implemented yet");
+    }
+
+    /**
+     * Set which process is considered the Heavy Weight process, if any.
+     */
+    public void setHeavyWeightProcess(@Nullable ProcessRecord proc) {
+        // TODO(b/302575389): Migrate state pulled from ATMS to a pushed model
+        throw new UnsupportedOperationException("Not implemented yet");
+    }
+
+    /**
+     * Set which process is showing UI while the screen is off, if any.
+     */
+    public void setVisibleDozeUiProcess(@Nullable ProcessRecord proc) {
+        // TODO(b/302575389): Migrate state pulled from ATMS to a pushed model
+        throw new UnsupportedOperationException("Not implemented yet");
+    }
+
+    /**
+     * Set which process is considered the Previous process, if any.
+     */
+    public void setPreviousProcess(@Nullable ProcessRecord proc) {
+        // TODO(b/302575389): Migrate state pulled from ATMS to a pushed model
+        throw new UnsupportedOperationException("Not implemented yet");
+    }
+
+    /**
+     * Set what wakefulness state the screen is in.
+     */
+    public void setWakefulness(int wakefulness) {
+        mGlobalState.isAwake = (wakefulness == PowerManagerInternal.WAKEFULNESS_AWAKE);
+        mOomAdjuster.onWakefulnessChanged(wakefulness);
+    }
+
+    /**
+     * Set for a given user what process is currently running a backup, if any.
+     */
+    public void setBackupTarget(@NonNull ProcessRecord proc, @UserIdInt int userId) {
+        mGlobalState.backupTargets.put(userId, proc);
+    }
+
+    /**
+     * No longer consider any process running a backup for a given user.
+     */
+    public void stopBackupTarget(@UserIdInt int userId) {
+        mGlobalState.backupTargets.delete(userId);
+    }
+
+    /**
+     * Set whether the last known memory level is normal.
+     */
+    public void setIsLastMemoryLevelNormal(boolean isMemoryNormal) {
+        mGlobalState.isLastMemoryLevelNormal = isMemoryNormal;
+    }
+
+    /***************************** UID State Events ****************************/
+    /**
+     * Set a UID as temp allowlisted.
+     */
+    public void setUidTempAllowlistStateLSP(int uid, boolean allowList) {
+        mOomAdjuster.setUidTempAllowlistStateLSP(uid, allowList);
+    }
+
+    /*********************** Process Miscellaneous Events **********************/
+    /**
+     * Set the maximum adj score a process can be assigned.
+     */
+    public void setMaxAdj(@NonNull ProcessRecord proc, int adj) {
+        proc.mState.setMaxAdj(adj);
+    }
+
+    /**
+     * Initialize a process that is being attached.
+     */
+    @GuardedBy({"mService", "mProcLock"})
+    public void setAttachingProcessStatesLSP(@NonNull ProcessRecord proc) {
+        mOomAdjuster.setAttachingProcessStatesLSP(proc);
+    }
+
+    /**
+     * Note whether a process is pending attach or not.
+     */
+    public void setPendingFinishAttach(@NonNull ProcessRecord proc, boolean pendingFinishAttach) {
+        proc.setPendingFinishAttach(pendingFinishAttach);
+    }
+
+    /**
+     * Set what sched group to grant a process due to running a broadcast.
+     * {@link ProcessList.SCHED_GROUP_UNDEFINED} means the process is not running a broadcast.
+     */
+    public void setBroadcastSchedGroup(@NonNull ProcessRecord proc, int schedGroup) {
+        // TODO(b/302575389): Migrate state pulled from BroadcastQueue to a pushed model
+        throw new UnsupportedOperationException("Not implemented yet");
+    }
+
+    /********************* Process Visibility State Events *********************/
+    /**
+     * Note whether a process has Top UI or not.
+     *
+     * @return true if the state changed, otherwise returns false.
+     */
+    public boolean setHasTopUi(@NonNull ProcessRecord proc, boolean hasTopUi) {
+        if (proc.mState.hasTopUi() == hasTopUi) return false;
+        if (DEBUG_OOM_ADJ) {
+            Slog.d(TAG, "Setting hasTopUi=" + hasTopUi + " for pid=" + proc.getPid());
+        }
+        proc.mState.setHasTopUi(hasTopUi);
+        return true;
+    }
+
+    /**
+     * Note whether a process is displaying Overlay UI or not.
+     *
+     * @return true if the state changed, otherwise returns false.
+     */
+    public boolean setHasOverlayUi(@NonNull ProcessRecord proc, boolean hasOverlayUi) {
+        if (proc.mState.hasOverlayUi() == hasOverlayUi) return false;
+        proc.mState.setHasOverlayUi(hasOverlayUi);
+        return true;
+    }
+
+
+    /**
+     * Note whether a process is running a remote animation.
+     *
+     * @return true if the state changed, otherwise returns false.
+     */
+    public boolean setRunningRemoteAnimation(@NonNull ProcessRecord proc,
+            boolean runningRemoteAnimation) {
+        if (proc.mState.isRunningRemoteAnimation() == runningRemoteAnimation) return false;
+        if (DEBUG_OOM_ADJ) {
+            Slog.i(TAG, "Setting runningRemoteAnimation=" + runningRemoteAnimation
+                    + " for pid=" + proc.getPid());
+        }
+        proc.mState.setRunningRemoteAnimation(runningRemoteAnimation);
+        return true;
+    }
+
+    /**
+     * Note that the process is showing a toast.
+     */
+    public void setForcingToImportant(@NonNull ProcessRecord proc,
+            @Nullable Object forcingToImportant) {
+        if (proc.mState.getForcingToImportant() == forcingToImportant) return;
+        proc.mState.setForcingToImportant(forcingToImportant);
+    }
+
+    /**
+     * Note that the process has shown UI at some point in its life.
+     */
+    public void setHasShownUi(@NonNull ProcessRecord proc, boolean hasShownUi) {
+        // This arguably should be turned into an internal state of OomAdjuster.
+        if (proc.mState.hasShownUi() == hasShownUi) return;
+        proc.mState.setHasShownUi(hasShownUi);
+    }
+
+    /**
+     * Note whether the process has an activity or not.
+     */
+    public void setHasActivity(@NonNull ProcessRecord proc, boolean hasActivity) {
+        // TODO(b/302575389): Migrate state pulled from ATMS to a pushed model
+        // Possibly not needed, maybe can use ActivityStateFlags.
+        throw new UnsupportedOperationException("Not implemented yet");
+    }
+
+    /**
+     * Note whether the process has a visibly activity or not.
+     */
+    public void setHasVisibleActivity(@NonNull ProcessRecord proc, boolean hasVisibleActivity) {
+        // TODO(b/302575389): Migrate state pulled from ATMS to a pushed model
+        // maybe used ActivityStateFlags instead.
+        throw new UnsupportedOperationException("Not implemented yet");
+    }
+
+    /**
+     * Set the Activity State Flags for a process.
+     */
+    public void setActivityStateFlags(@NonNull ProcessRecord proc, int flags) {
+        // TODO(b/302575389): Migrate state pulled from ATMS to a pushed model
+        throw new UnsupportedOperationException("Not implemented yet");
+    }
+
+    /********************** Content Provider State Events **********************/
+    /**
+     * Note that a process is hosting a content provider.
+     */
+    public boolean addPublishedProvider(@NonNull ProcessRecord proc, String name,
+            ContentProviderRecord cpr) {
+        final ProcessProviderRecord providers = proc.mProviders;
+        if (providers.hasProvider(name)) return false;
+        providers.installProvider(name, cpr);
+        return true;
+    }
+
+    /**
+     * Remove a published content provider from a process.
+     */
+    public void removePublishedProvider(@NonNull ProcessRecord proc, String name) {
+        final ProcessProviderRecord providers = proc.mProviders;
+        providers.removeProvider(name);
+    }
+
+    /**
+     * Note that a content provider has an external client.
+     */
+    public void addExternalProviderClient(@NonNull ContentProviderRecord cpr,
+            IBinder externalProcessToken, int callingUid, String callingTag) {
+        cpr.addExternalProcessHandleLocked(externalProcessToken, callingUid, callingTag);
+    }
+
+    /**
+     * Remove an external client from a conetnt provider.
+     */
+    public boolean removeExternalProviderClient(@NonNull ContentProviderRecord cpr,
+            IBinder externalProcessToken) {
+        return cpr.removeExternalProcessHandleLocked(externalProcessToken);
+    }
+
+    /**
+     * Note the time a process is no longer hosting any content providers.
+     */
+    public void setLastProviderTime(@NonNull ProcessRecord proc, long uptimeMs) {
+        proc.mProviders.setLastProviderTime(uptimeMs);
+    }
+
+    /**
+     * Note that a process has connected to a content provider.
+     */
+    public void addProviderConnection(@NonNull ProcessRecord client,
+            ContentProviderConnection cpc) {
+        client.mProviders.addProviderConnection(cpc);
+    }
+
+    /**
+     * Note that a process is no longer connected to a content provider.
+     */
+    public void removeProviderConnection(@NonNull ProcessRecord client,
+            ContentProviderConnection cpc) {
+        client.mProviders.removeProviderConnection(cpc);
+    }
+
+    /*************************** Service State Events **************************/
+    /**
+     * Note that a process has started hosting a service.
+     */
+    public boolean startService(@NonNull ProcessServiceRecord psr, ServiceRecord sr) {
+        return psr.startService(sr);
+    }
+
+    /**
+     * Note that a process has stopped hosting a service.
+     */
+    public boolean stopService(@NonNull ProcessServiceRecord psr, ServiceRecord sr) {
+        return psr.stopService(sr);
+    }
+
+    /**
+     * Remove all services that the process is hosting.
+     */
+    public void stopAllServices(@NonNull ProcessServiceRecord psr) {
+        psr.stopAllServices();
+    }
+
+    /**
+     * Note that a process's service has started executing.
+     */
+    public void startExecutingService(@NonNull ProcessServiceRecord psr, ServiceRecord sr) {
+        psr.startExecutingService(sr);
+    }
+
+    /**
+     * Note that a process's service has stopped executing.
+     */
+    public void stopExecutingService(@NonNull ProcessServiceRecord psr, ServiceRecord sr) {
+        psr.stopExecutingService(sr);
+    }
+
+    /**
+     * Note all executing services a process has has stopped.
+     */
+    public void stopAllExecutingServices(@NonNull ProcessServiceRecord psr) {
+        psr.stopAllExecutingServices();
+    }
+
+    /**
+     * Note that process has bound to a service.
+     */
+    public void addConnection(@NonNull ProcessServiceRecord psr, ConnectionRecord cr) {
+        psr.addConnection(cr);
+    }
+
+    /**
+     * Note that process has unbound from a service.
+     */
+    public void removeConnection(@NonNull ProcessServiceRecord psr, ConnectionRecord cr) {
+        psr.removeConnection(cr);
+    }
+
+    /**
+     * Remove all bindings a process has to services.
+     */
+    public void removeAllConnections(@NonNull ProcessServiceRecord psr) {
+        psr.removeAllConnections();
+        psr.removeAllSdkSandboxConnections();
+    }
+
+    /**
+     * Note whether an executing service should be considered in the foreground or not.
+     */
+    public void setExecServicesFg(@NonNull ProcessServiceRecord psr, boolean execServicesFg) {
+        psr.setExecServicesFg(execServicesFg);
+    }
+
+    /**
+     * Note whether a service is in the foreground or not and what type of FGS, if so.
+     */
+    public void setHasForegroundServices(@NonNull ProcessServiceRecord psr,
+            boolean hasForegroundServices,
+            int fgServiceTypes, boolean hasTypeNoneFgs) {
+        psr.setHasForegroundServices(hasForegroundServices, fgServiceTypes, hasTypeNoneFgs);
+    }
+
+    /**
+     * Note whether a service has a client activity or not.
+     */
+    public void setHasClientActivities(@NonNull ProcessServiceRecord psr,
+            boolean hasClientActivities) {
+        psr.setHasClientActivities(hasClientActivities);
+    }
+
+    /**
+     * Note whether a service should be treated like an activity or not.
+     */
+    public void setTreatLikeActivity(@NonNull ProcessServiceRecord psr, boolean treatLikeActivity) {
+        psr.setTreatLikeActivity(treatLikeActivity);
+    }
+
+    /**
+     * Note whether a process has bound to a service with
+     * {@link android.content.Context.BIND_ABOVE_CLIENT} or not.
+     */
+    public void setHasAboveClient(@NonNull ProcessServiceRecord psr, boolean hasAboveClient) {
+        psr.setHasAboveClient(hasAboveClient);
+    }
+
+    /**
+     * Recompute whether a process has bound to a service with
+     * {@link android.content.Context.BIND_ABOVE_CLIENT} or not.
+     */
+    public void updateHasAboveClientLocked(@NonNull ProcessServiceRecord psr) {
+        psr.updateHasAboveClientLocked();
+    }
+
+    /**
+     * Cleanup a process's state.
+     */
+    public void onCleanupApplicationRecord(@NonNull ProcessServiceRecord psr) {
+        psr.onCleanupApplicationRecordLocked();
+    }
+
+    /**
+     * Set which process is hosting a service.
+     */
+    public void setHostProcess(@NonNull ServiceRecord sr, @Nullable ProcessRecord host) {
+        sr.app = host;
+    }
+
+    /**
+     * Note whether a service is a Foreground Service or not
+     */
+    public void setIsForegroundService(@NonNull ServiceRecord sr, boolean isFgs) {
+        sr.isForeground = isFgs;
+    }
+
+    /**
+     * Note the Foreground Service type of a service.
+     */
+    public void setForegroundServiceType(@NonNull ServiceRecord sr,
+            @ServiceInfo.ForegroundServiceType int fgsType) {
+        sr.foregroundServiceType = fgsType;
+    }
+
+    /**
+     * Note the start time of a short foreground service.
+     */
+    public void setShortFgsInfo(@NonNull ServiceRecord sr, long uptimeNow) {
+        sr.setShortFgsInfo(uptimeNow);
+    }
+
+    /**
+     * Note that a short foreground service has stopped.
+     */
+    public void clearShortFgsInfo(@NonNull ServiceRecord sr) {
+        sr.clearShortFgsInfo();
+    }
+
+    /**
+     * Note the last time a service was active.
+     */
+    public void setServiceLastActivityTime(@NonNull ServiceRecord sr, long lastActivityUpdateMs) {
+        sr.lastActivity = lastActivityUpdateMs;
+    }
+
+    /**
+     * Note that a service start was requested.
+     */
+    public void setStartRequested(@NonNull ServiceRecord sr, boolean startRequested) {
+        sr.startRequested = startRequested;
+    }
+
+    /**
+     * Note the last time the service was bound by a Top process with
+     * {@link android.content.Context.BIND_ALMOST_PERCEPTIBLE}
+     */
+    public void setLastTopAlmostPerceptibleBindRequest(@NonNull ServiceRecord sr,
+            long lastTopAlmostPerceptibleBindRequestUptimeMs) {
+        sr.lastTopAlmostPerceptibleBindRequestUptimeMs =
+                lastTopAlmostPerceptibleBindRequestUptimeMs;
+    }
+
+    /**
+     * Recompute whether a process has bound to a service with
+     * {@link android.content.Context.BIND_ALMOST_PERCEPTIBLE} or not.
+     */
+    public void updateHasTopStartedAlmostPerceptibleServices(@NonNull ProcessServiceRecord psr) {
+        psr.updateHasTopStartedAlmostPerceptibleServices();
+    }
+
+    /**
+     * Builder for ProcessStateController.
+     */
+    public static class Builder {
+        private final ActivityManagerService mAms;
+        private final ProcessList mProcessList;
+        private final ActiveUids mActiveUids;
+
+        private ServiceThread mHandlerThread = null;
+        private OomAdjuster.Injector mOomAdjInjector = null;
+        private boolean mUseOomAdjusterModernImpl = false;
+
+        public Builder(ActivityManagerService ams, ProcessList processList, ActiveUids activeUids) {
+            mAms = ams;
+            mProcessList = processList;
+            mActiveUids = activeUids;
+        }
+
+        /**
+         * Build the ProcessStateController object.
+         */
+        public ProcessStateController build() {
+            if (mHandlerThread == null) {
+                mHandlerThread = OomAdjuster.createAdjusterThread();
+            }
+            if (mOomAdjInjector == null) {
+                mOomAdjInjector = new OomAdjuster.Injector();
+            }
+            return new ProcessStateController(mAms, mProcessList, mActiveUids, mHandlerThread,
+                    mOomAdjInjector, mUseOomAdjusterModernImpl);
+        }
+
+        /**
+         * For Testing Purposes. Set what thread OomAdjuster will offload tasks on to.
+         */
+        public Builder setHandlerThread(ServiceThread handlerThread) {
+            mHandlerThread = handlerThread;
+            return this;
+        }
+
+        /**
+         * For Testing Purposes. Set an injector for OomAdjuster.
+         */
+        public Builder setOomAdjusterInjector(OomAdjuster.Injector injector) {
+            mOomAdjInjector = injector;
+            return this;
+        }
+
+        /**
+         * Set which implementation of OomAdjuster to use.
+         */
+        public Builder useModernOomAdjuster(boolean use) {
+            mUseOomAdjusterModernImpl = use;
+            return this;
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/am/ProcessStateRecord.java b/services/core/java/com/android/server/am/ProcessStateRecord.java
index bc990d9..b0f808b 100644
--- a/services/core/java/com/android/server/am/ProcessStateRecord.java
+++ b/services/core/java/com/android/server/am/ProcessStateRecord.java
@@ -19,14 +19,11 @@
 import static android.app.ActivityManager.PROCESS_CAPABILITY_NONE;
 import static android.app.ActivityManager.PROCESS_STATE_CACHED_EMPTY;
 import static android.app.ActivityManager.PROCESS_STATE_NONEXISTENT;
-import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_UI_VISIBILITY;
 import static android.app.ProcessMemoryState.HOSTING_COMPONENT_TYPE_ACTIVITY;
 import static android.app.ProcessMemoryState.HOSTING_COMPONENT_TYPE_BROADCAST_RECEIVER;
 import static android.app.ProcessMemoryState.HOSTING_COMPONENT_TYPE_STARTED_SERVICE;
 
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_OOM_ADJ;
 import static com.android.server.am.ProcessList.CACHED_APP_MIN_ADJ;
-import static com.android.server.am.ProcessRecord.TAG;
 import static com.android.server.wm.WindowProcessController.ACTIVITY_STATE_FLAG_IS_PAUSING_OR_PAUSED;
 import static com.android.server.wm.WindowProcessController.ACTIVITY_STATE_FLAG_IS_STOPPING;
 import static com.android.server.wm.WindowProcessController.ACTIVITY_STATE_FLAG_IS_STOPPING_FINISHING;
@@ -38,7 +35,6 @@
 import android.content.ComponentName;
 import android.os.SystemClock;
 import android.os.Trace;
-import android.util.Slog;
 import android.util.TimeUtils;
 
 import com.android.internal.annotations.CompositeRWLock;
@@ -790,15 +786,7 @@
 
     @GuardedBy("mService")
     void setRunningRemoteAnimation(boolean runningRemoteAnimation) {
-        if (mRunningRemoteAnimation == runningRemoteAnimation) {
-            return;
-        }
         mRunningRemoteAnimation = runningRemoteAnimation;
-        if (DEBUG_OOM_ADJ) {
-            Slog.i(TAG, "Setting runningRemoteAnimation=" + runningRemoteAnimation
-                    + " for pid=" + mApp.getPid());
-        }
-        mService.updateOomAdjLocked(mApp, OOM_ADJ_REASON_UI_VISIBILITY);
     }
 
     @GuardedBy({"mService", "mProcLock"})
diff --git a/services/core/java/com/android/server/am/ServiceRecord.java b/services/core/java/com/android/server/am/ServiceRecord.java
index b9cdf27..92d33c9 100644
--- a/services/core/java/com/android/server/am/ServiceRecord.java
+++ b/services/core/java/com/android/server/am/ServiceRecord.java
@@ -1248,7 +1248,7 @@
             app.mServices.updateBoundClientUids();
             app.mServices.updateHostingComonentTypeForBindingsLocked();
         }
-        app = proc;
+        ams.mProcessStateController.setHostProcess(this, proc);
         updateProcessStateOnRequest();
         if (pendingConnectionGroup > 0 && proc != null) {
             final ProcessServiceRecord psr = proc.mServices;
diff --git a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
index bae9a67..a815f72 100644
--- a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
+++ b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
@@ -138,6 +138,7 @@
     // The list is sorted.
     @VisibleForTesting
     static final String[] sDeviceConfigAconfigScopes = new String[] {
+        "aaos_sdv",
         "accessibility",
         "android_core_networking",
         "android_health_services",
@@ -150,6 +151,7 @@
         "art_performance",
         "attack_tools",
         "avic",
+        "desktop_firmware",
         "biometrics",
         "biometrics_framework",
         "biometrics_integration",
@@ -211,6 +213,7 @@
         "preload_safety",
         "printing",
         "privacy_infra_policy",
+        "ravenwood",
         "resource_manager",
         "responsible_apis",
         "rust",
@@ -243,8 +246,10 @@
         "wear_system_health",
         "wear_systems",
         "wear_sysui",
+        "wear_system_managed_surfaces",
         "window_surfaces",
         "windowing_frontend",
+        "xr",
     };
 
     public static final String NAMESPACE_REBOOT_STAGING = "staged";
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index 262c76e..31ae966 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -1920,175 +1920,8 @@
                 return false;
             }
 
-            boolean needStart = false;
-            boolean updateUmState = false;
-            UserState uss;
-
-            // If the user we are switching to is not currently started, then
-            // we need to start it now.
-            t.traceBegin("updateStartedUserArrayStarting");
-            synchronized (mLock) {
-                uss = mStartedUsers.get(userId);
-                if (uss == null) {
-                    uss = new UserState(UserHandle.of(userId));
-                    uss.mUnlockProgress.addListener(new UserProgressListener());
-                    mStartedUsers.put(userId, uss);
-                    updateStartedUserArrayLU();
-                    needStart = true;
-                    updateUmState = true;
-                } else if (uss.state == UserState.STATE_SHUTDOWN
-                        || mDoNotAbortShutdownUserIds.contains(userId)) {
-                    Slogf.i(TAG, "User #" + userId
-                            + " is shutting down - will start after full shutdown");
-                    mPendingUserStarts.add(new PendingUserStart(userId, userStartMode,
-                            unlockListener));
-                    t.traceEnd(); // updateStartedUserArrayStarting
-                    return true;
-                }
-            }
-
-            // No matter what, the fact that we're requested to start the user (even if it is
-            // already running) puts it towards the end of the mUserLru list.
-            addUserToUserLru(userId);
-            if (android.multiuser.Flags.scheduleStopOfBackgroundUser()) {
-                mHandler.removeEqualMessages(SCHEDULED_STOP_BACKGROUND_USER_MSG,
-                        Integer.valueOf(userId));
-            }
-
-            if (unlockListener != null) {
-                uss.mUnlockProgress.addListener(unlockListener);
-            }
-            t.traceEnd(); // updateStartedUserArrayStarting
-
-            if (updateUmState) {
-                t.traceBegin("setUserState");
-                mInjector.getUserManagerInternal().setUserState(userId, uss.state);
-                t.traceEnd();
-            }
-            t.traceBegin("updateConfigurationAndProfileIds");
-            if (foreground) {
-                // Make sure the old user is no longer considering the display to be on.
-                mInjector.reportGlobalUsageEvent(UsageEvents.Event.SCREEN_NON_INTERACTIVE);
-                boolean userSwitchUiEnabled;
-                synchronized (mLock) {
-                    mCurrentUserId = userId;
-                    ActivityManager.invalidateGetCurrentUserIdCache();
-                    userSwitchUiEnabled = mUserSwitchUiEnabled;
-                }
-                mInjector.updateUserConfiguration();
-                // NOTE: updateProfileRelatedCaches() is called on both if and else parts, ideally
-                // it should be moved outside, but for now it's not as there are many calls to
-                // external components here afterwards
-                updateProfileRelatedCaches();
-                dispatchOnBeforeUserSwitching(userId);
-                mInjector.getWindowManager().setCurrentUser(userId);
-                mInjector.reportCurWakefulnessUsageEvent();
-                // Once the internal notion of the active user has switched, we lock the device
-                // with the option to show the user switcher on the keyguard.
-                if (userSwitchUiEnabled) {
-                    mInjector.getWindowManager().setSwitchingUser(true);
-                    // Only lock if the user has a secure keyguard PIN/Pattern/Pwd
-                    if (mInjector.getKeyguardManager().isDeviceSecure(userId)) {
-                        // Make sure the device is locked before moving on with the user switch
-                        mInjector.lockDeviceNowAndWaitForKeyguardShown();
-                    }
-                }
-
-            } else {
-                updateProfileRelatedCaches();
-                // We are starting a non-foreground user. They have already been added to the end
-                // of mUserLru, so we need to ensure that the foreground user isn't displaced.
-                addUserToUserLru(mCurrentUserId);
-            }
-            if (userStartMode == USER_START_MODE_BACKGROUND && !userInfo.isProfile()) {
-                scheduleStopOfBackgroundUser(userId);
-            }
-            t.traceEnd();
-
-            // Make sure user is in the started state.  If it is currently
-            // stopping, we need to knock that off.
-            if (uss.state == UserState.STATE_STOPPING) {
-                t.traceBegin("updateStateStopping");
-                // If we are stopping, we haven't sent ACTION_SHUTDOWN,
-                // so we can just fairly silently bring the user back from
-                // the almost-dead.
-                uss.setState(uss.lastState);
-                mInjector.getUserManagerInternal().setUserState(userId, uss.state);
-                synchronized (mLock) {
-                    updateStartedUserArrayLU();
-                }
-                needStart = true;
-                t.traceEnd();
-            } else if (uss.state == UserState.STATE_SHUTDOWN) {
-                t.traceBegin("updateStateShutdown");
-                // This means ACTION_SHUTDOWN has been sent, so we will
-                // need to treat this as a new boot of the user.
-                uss.setState(UserState.STATE_BOOTING);
-                mInjector.getUserManagerInternal().setUserState(userId, uss.state);
-                synchronized (mLock) {
-                    updateStartedUserArrayLU();
-                }
-                needStart = true;
-                t.traceEnd();
-            }
-
-            if (uss.state == UserState.STATE_BOOTING) {
-                t.traceBegin("updateStateBooting");
-                // Give user manager a chance to propagate user restrictions
-                // to other services and prepare app storage
-                mInjector.getUserManager().onBeforeStartUser(userId);
-
-                // Booting up a new user, need to tell system services about it.
-                // Note that this is on the same handler as scheduling of broadcasts,
-                // which is important because it needs to go first.
-                mHandler.sendMessage(mHandler.obtainMessage(USER_START_MSG, userId, NO_ARG2));
-                t.traceEnd();
-            }
-
-            t.traceBegin("sendMessages");
-            if (foreground) {
-                mHandler.sendMessage(mHandler.obtainMessage(USER_CURRENT_MSG, userId, oldUserId));
-                mHandler.removeMessages(REPORT_USER_SWITCH_MSG);
-                mHandler.removeMessages(USER_SWITCH_TIMEOUT_MSG);
-                mHandler.sendMessage(mHandler.obtainMessage(REPORT_USER_SWITCH_MSG,
-                        oldUserId, userId, uss));
-                mHandler.sendMessageDelayed(mHandler.obtainMessage(USER_SWITCH_TIMEOUT_MSG,
-                        oldUserId, userId, uss), getUserSwitchTimeoutMs());
-            }
-
-            if (userInfo.preCreated) {
-                needStart = false;
-            }
-
-            // In most cases, broadcast for the system user starting/started is sent by
-            // ActivityManagerService#systemReady(). However on some HSUM devices (e.g. tablets)
-            // the user switches from the system user to a secondary user while running
-            // ActivityManagerService#systemReady(), thus broadcast is not sent for the system user.
-            // Therefore we send the broadcast for the system user here as well in HSUM.
-            // TODO(b/266158156): Improve/refactor the way broadcasts are sent for the system user
-            // in HSUM. Ideally it'd be best to have one single place that sends this notification.
-            final boolean isSystemUserInHeadlessMode = (userId == UserHandle.USER_SYSTEM)
-                    && mInjector.isHeadlessSystemUserMode();
-            if (needStart || isSystemUserInHeadlessMode) {
-                sendUserStartedBroadcast(userId, callingUid, callingPid);
-            }
-            t.traceEnd();
-
-            if (foreground) {
-                t.traceBegin("moveUserToForeground");
-                moveUserToForeground(uss, userId);
-                t.traceEnd();
-            } else {
-                t.traceBegin("finishUserBoot");
-                finishUserBoot(uss);
-                t.traceEnd();
-            }
-
-            if (needStart || isSystemUserInHeadlessMode) {
-                t.traceBegin("sendRestartBroadcast");
-                sendUserStartingBroadcast(userId, callingUid, callingPid);
-                t.traceEnd();
-            }
+            mHandler.post(() -> startUserInternalOnHandler(userId, oldUserId, userStartMode,
+                    unlockListener, callingUid, callingPid));
         } finally {
             Binder.restoreCallingIdentity(ident);
         }
@@ -2096,6 +1929,183 @@
         return true;
     }
 
+    private void startUserInternalOnHandler(int userId, int oldUserId, int userStartMode,
+            IProgressListener unlockListener, int callingUid, int callingPid) {
+        final TimingsTraceAndSlog t = new TimingsTraceAndSlog();
+        final boolean foreground = userStartMode == USER_START_MODE_FOREGROUND;
+        final UserInfo userInfo = getUserInfo(userId);
+
+        boolean needStart = false;
+        boolean updateUmState = false;
+        UserState uss;
+
+        // If the user we are switching to is not currently started, then
+        // we need to start it now.
+        t.traceBegin("updateStartedUserArrayStarting");
+        synchronized (mLock) {
+            uss = mStartedUsers.get(userId);
+            if (uss == null) {
+                uss = new UserState(UserHandle.of(userId));
+                uss.mUnlockProgress.addListener(new UserProgressListener());
+                mStartedUsers.put(userId, uss);
+                updateStartedUserArrayLU();
+                needStart = true;
+                updateUmState = true;
+            } else if (uss.state == UserState.STATE_SHUTDOWN
+                    || mDoNotAbortShutdownUserIds.contains(userId)) {
+                Slogf.i(TAG, "User #" + userId
+                        + " is shutting down - will start after full shutdown");
+                mPendingUserStarts.add(new PendingUserStart(userId, userStartMode,
+                        unlockListener));
+                t.traceEnd(); // updateStartedUserArrayStarting
+                return;
+            }
+        }
+
+        // No matter what, the fact that we're requested to start the user (even if it is
+        // already running) puts it towards the end of the mUserLru list.
+        addUserToUserLru(userId);
+        if (android.multiuser.Flags.scheduleStopOfBackgroundUser()) {
+            mHandler.removeEqualMessages(SCHEDULED_STOP_BACKGROUND_USER_MSG,
+                    Integer.valueOf(userId));
+        }
+
+        if (unlockListener != null) {
+            uss.mUnlockProgress.addListener(unlockListener);
+        }
+        t.traceEnd(); // updateStartedUserArrayStarting
+
+        if (updateUmState) {
+            t.traceBegin("setUserState");
+            mInjector.getUserManagerInternal().setUserState(userId, uss.state);
+            t.traceEnd();
+        }
+        t.traceBegin("updateConfigurationAndProfileIds");
+        if (foreground) {
+            // Make sure the old user is no longer considering the display to be on.
+            mInjector.reportGlobalUsageEvent(UsageEvents.Event.SCREEN_NON_INTERACTIVE);
+            boolean userSwitchUiEnabled;
+            synchronized (mLock) {
+                mCurrentUserId = userId;
+                ActivityManager.invalidateGetCurrentUserIdCache();
+                userSwitchUiEnabled = mUserSwitchUiEnabled;
+            }
+            mInjector.updateUserConfiguration();
+            // NOTE: updateProfileRelatedCaches() is called on both if and else parts, ideally
+            // it should be moved outside, but for now it's not as there are many calls to
+            // external components here afterwards
+            updateProfileRelatedCaches();
+            dispatchOnBeforeUserSwitching(userId);
+            mInjector.getWindowManager().setCurrentUser(userId);
+            mInjector.reportCurWakefulnessUsageEvent();
+            // Once the internal notion of the active user has switched, we lock the device
+            // with the option to show the user switcher on the keyguard.
+            if (userSwitchUiEnabled) {
+                mInjector.getWindowManager().setSwitchingUser(true);
+                // Only lock if the user has a secure keyguard PIN/Pattern/Pwd
+                if (mInjector.getKeyguardManager().isDeviceSecure(userId)) {
+                    // Make sure the device is locked before moving on with the user switch
+                    mInjector.lockDeviceNowAndWaitForKeyguardShown();
+                }
+            }
+
+        } else {
+            updateProfileRelatedCaches();
+            // We are starting a non-foreground user. They have already been added to the end
+            // of mUserLru, so we need to ensure that the foreground user isn't displaced.
+            addUserToUserLru(mCurrentUserId);
+        }
+        if (userStartMode == USER_START_MODE_BACKGROUND && !userInfo.isProfile()) {
+            scheduleStopOfBackgroundUser(userId);
+        }
+        t.traceEnd();
+
+        // Make sure user is in the started state.  If it is currently
+        // stopping, we need to knock that off.
+        if (uss.state == UserState.STATE_STOPPING) {
+            t.traceBegin("updateStateStopping");
+            // If we are stopping, we haven't sent ACTION_SHUTDOWN,
+            // so we can just fairly silently bring the user back from
+            // the almost-dead.
+            uss.setState(uss.lastState);
+            mInjector.getUserManagerInternal().setUserState(userId, uss.state);
+            synchronized (mLock) {
+                updateStartedUserArrayLU();
+            }
+            needStart = true;
+            t.traceEnd();
+        } else if (uss.state == UserState.STATE_SHUTDOWN) {
+            t.traceBegin("updateStateShutdown");
+            // This means ACTION_SHUTDOWN has been sent, so we will
+            // need to treat this as a new boot of the user.
+            uss.setState(UserState.STATE_BOOTING);
+            mInjector.getUserManagerInternal().setUserState(userId, uss.state);
+            synchronized (mLock) {
+                updateStartedUserArrayLU();
+            }
+            needStart = true;
+            t.traceEnd();
+        }
+
+        if (uss.state == UserState.STATE_BOOTING) {
+            t.traceBegin("updateStateBooting");
+            // Give user manager a chance to propagate user restrictions
+            // to other services and prepare app storage
+            mInjector.getUserManager().onBeforeStartUser(userId);
+
+            // Booting up a new user, need to tell system services about it.
+            // Note that this is on the same handler as scheduling of broadcasts,
+            // which is important because it needs to go first.
+            mHandler.sendMessage(mHandler.obtainMessage(USER_START_MSG, userId, NO_ARG2));
+            t.traceEnd();
+        }
+
+        t.traceBegin("sendMessages");
+        if (foreground) {
+            mHandler.sendMessage(mHandler.obtainMessage(USER_CURRENT_MSG, userId, oldUserId));
+            mHandler.removeMessages(REPORT_USER_SWITCH_MSG);
+            mHandler.removeMessages(USER_SWITCH_TIMEOUT_MSG);
+            mHandler.sendMessage(mHandler.obtainMessage(REPORT_USER_SWITCH_MSG,
+                    oldUserId, userId, uss));
+            mHandler.sendMessageDelayed(mHandler.obtainMessage(USER_SWITCH_TIMEOUT_MSG,
+                    oldUserId, userId, uss), getUserSwitchTimeoutMs());
+        }
+
+        if (userInfo.preCreated) {
+            needStart = false;
+        }
+
+        // In most cases, broadcast for the system user starting/started is sent by
+        // ActivityManagerService#systemReady(). However on some HSUM devices (e.g. tablets)
+        // the user switches from the system user to a secondary user while running
+        // ActivityManagerService#systemReady(), thus broadcast is not sent for the system user.
+        // Therefore we send the broadcast for the system user here as well in HSUM.
+        // TODO(b/266158156): Improve/refactor the way broadcasts are sent for the system user
+        // in HSUM. Ideally it'd be best to have one single place that sends this notification.
+        final boolean isSystemUserInHeadlessMode = (userId == UserHandle.USER_SYSTEM)
+                && mInjector.isHeadlessSystemUserMode();
+        if (needStart || isSystemUserInHeadlessMode) {
+            sendUserStartedBroadcast(userId, callingUid, callingPid);
+        }
+        t.traceEnd();
+
+        if (foreground) {
+            t.traceBegin("moveUserToForeground");
+            moveUserToForeground(uss, userId);
+            t.traceEnd();
+        } else {
+            t.traceBegin("finishUserBoot");
+            finishUserBoot(uss);
+            t.traceEnd();
+        }
+
+        if (needStart || isSystemUserInHeadlessMode) {
+            t.traceBegin("sendRestartBroadcast");
+            sendUserStartingBroadcast(userId, callingUid, callingPid);
+            t.traceEnd();
+        }
+    }
+
     /**
      * Start user, if it's not already running, and bring it to foreground.
      */
diff --git a/services/core/java/com/android/server/am/flags.aconfig b/services/core/java/com/android/server/am/flags.aconfig
index 7873d34..adf0e64 100644
--- a/services/core/java/com/android/server/am/flags.aconfig
+++ b/services/core/java/com/android/server/am/flags.aconfig
@@ -218,3 +218,10 @@
     description: "Set reset_on_fork flag."
     bug: "370988407"
 }
+
+flag {
+    name: "push_global_state_to_oomadjuster"
+    namespace: "backstage_power"
+    description: "Migrate OomAdjuster pulled device state to a push model"
+    bug: "302575389"
+}
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index 596e375..e97629b 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -72,6 +72,7 @@
 import static android.content.pm.PermissionInfo.PROTECTION_FLAG_APPOP;
 import static android.permission.flags.Flags.deviceAwareAppOpNewSchemaEnabled;
 
+import static com.android.internal.util.FrameworkStatsLog.APP_OP_NOTE_OP_OR_CHECK_OP_BINDER_API_CALLED;
 import static com.android.internal.util.FrameworkStatsLog.APP_OP_NOTE_OP_OR_CHECK_OP_BINDER_API_CALLED__BINDER_API__CHECK_OPERATION;
 import static com.android.internal.util.FrameworkStatsLog.APP_OP_NOTE_OP_OR_CHECK_OP_BINDER_API_CALLED__BINDER_API__NOTE_OPERATION;
 import static com.android.internal.util.FrameworkStatsLog.APP_OP_NOTE_OP_OR_CHECK_OP_BINDER_API_CALLED__BINDER_API__NOTE_PROXY_OPERATION;
@@ -2833,10 +2834,10 @@
 
     @Override
     public int checkOperation(int code, int uid, String packageName) {
-        if (Flags.appopAccessTrackingLoggingEnabled()) {
+        if (Binder.getCallingPid() != Process.myPid()
+                && Flags.appopAccessTrackingLoggingEnabled()) {
             FrameworkStatsLog.write(
-                    FrameworkStatsLog.APP_OP_NOTE_OP_OR_CHECK_OP_BINDER_API_CALLED,
-                    uid, code,
+                    APP_OP_NOTE_OP_OR_CHECK_OP_BINDER_API_CALLED, uid, code,
                     APP_OP_NOTE_OP_OR_CHECK_OP_BINDER_API_CALLED__BINDER_API__CHECK_OPERATION,
                     false);
         }
@@ -2846,10 +2847,10 @@
 
     @Override
     public int checkOperationForDevice(int code, int uid, String packageName, int virtualDeviceId) {
-        if (Flags.appopAccessTrackingLoggingEnabled()) {
+        if (Binder.getCallingPid() != Process.myPid()
+                && Flags.appopAccessTrackingLoggingEnabled()) {
             FrameworkStatsLog.write(
-                    FrameworkStatsLog.APP_OP_NOTE_OP_OR_CHECK_OP_BINDER_API_CALLED,
-                    uid, code,
+                    APP_OP_NOTE_OP_OR_CHECK_OP_BINDER_API_CALLED, uid, code,
                     APP_OP_NOTE_OP_OR_CHECK_OP_BINDER_API_CALLED__BINDER_API__CHECK_OPERATION,
                     false);
         }
@@ -3033,14 +3034,13 @@
     public SyncNotedAppOp noteProxyOperationWithState(int code,
             AttributionSourceState attributionSourceState, boolean shouldCollectAsyncNotedOp,
             String message, boolean shouldCollectMessage, boolean skipProxyOperation) {
-        if (Flags.appopAccessTrackingLoggingEnabled()) {
+        if (Binder.getCallingPid() != Process.myPid()
+                && Flags.appopAccessTrackingLoggingEnabled()) {
             FrameworkStatsLog.write(
-                    FrameworkStatsLog.APP_OP_NOTE_OP_OR_CHECK_OP_BINDER_API_CALLED,
-                    attributionSourceState.uid, code,
+                    APP_OP_NOTE_OP_OR_CHECK_OP_BINDER_API_CALLED, attributionSourceState.uid, code,
                     APP_OP_NOTE_OP_OR_CHECK_OP_BINDER_API_CALLED__BINDER_API__NOTE_PROXY_OPERATION,
                     attributionSourceState.attributionTag != null);
         }
-
         AttributionSource attributionSource = new AttributionSource(attributionSourceState);
         return mCheckOpsDelegateDispatcher.noteProxyOperation(code, attributionSource,
                 shouldCollectAsyncNotedOp, message, shouldCollectMessage, skipProxyOperation);
@@ -3122,14 +3122,13 @@
     public SyncNotedAppOp noteOperation(int code, int uid, String packageName,
             String attributionTag, boolean shouldCollectAsyncNotedOp, String message,
             boolean shouldCollectMessage) {
-        if (Flags.appopAccessTrackingLoggingEnabled()) {
+        if (Binder.getCallingPid() != Process.myPid()
+                && Flags.appopAccessTrackingLoggingEnabled()) {
             FrameworkStatsLog.write(
-                    FrameworkStatsLog.APP_OP_NOTE_OP_OR_CHECK_OP_BINDER_API_CALLED,
-                    uid, code,
+                    APP_OP_NOTE_OP_OR_CHECK_OP_BINDER_API_CALLED, uid, code,
                     APP_OP_NOTE_OP_OR_CHECK_OP_BINDER_API_CALLED__BINDER_API__NOTE_OPERATION,
                     attributionTag != null);
         }
-
         return mCheckOpsDelegateDispatcher.noteOperation(code, uid, packageName,
                 attributionTag, Context.DEVICE_ID_DEFAULT, shouldCollectAsyncNotedOp, message,
                 shouldCollectMessage);
diff --git a/services/core/java/com/android/server/appop/AppOpsUidStateTrackerImpl.java b/services/core/java/com/android/server/appop/AppOpsUidStateTrackerImpl.java
index 03c8156..ed41f2e 100644
--- a/services/core/java/com/android/server/appop/AppOpsUidStateTrackerImpl.java
+++ b/services/core/java/com/android/server/appop/AppOpsUidStateTrackerImpl.java
@@ -36,6 +36,7 @@
 import static android.app.AppOpsManager.UID_STATE_MAX_LAST_NON_RESTRICTED;
 import static android.app.AppOpsManager.UID_STATE_NONEXISTENT;
 import static android.app.AppOpsManager.UID_STATE_TOP;
+import static android.permission.flags.Flags.delayUidStateChangesFromCapabilityUpdates;
 import static android.permission.flags.Flags.finishRunningOpsForKilledPackages;
 
 import static com.android.server.appop.AppOpsUidStateTracker.processStateToUidState;
@@ -236,20 +237,26 @@
             mPendingUidStates.put(uid, uidState);
             mPendingCapability.put(uid, capability);
 
+            boolean hasLostCapability = (prevCapability & ~capability) != 0;
+
             if (procState == PROCESS_STATE_NONEXISTENT) {
                 mPendingGone.put(uid, true);
                 commitUidPendingState(uid);
-            } else if (uidState < prevUidState
-                    || (uidState <= UID_STATE_MAX_LAST_NON_RESTRICTED
-                    && prevUidState > UID_STATE_MAX_LAST_NON_RESTRICTED)) {
+            } else if (uidState < prevUidState) {
                 // We are moving to a more important state, or the new state may be in the
                 // foreground and the old state is in the background, then always do it
                 // immediately.
                 commitUidPendingState(uid);
-            } else if (uidState == prevUidState && capability != prevCapability) {
+            } else if (delayUidStateChangesFromCapabilityUpdates()
+                    && uidState == prevUidState && !hasLostCapability) {
+                // No change on process state, but process capability hasn't decreased.
+                commitUidPendingState(uid);
+            } else if (!delayUidStateChangesFromCapabilityUpdates()
+                    && uidState == prevUidState && capability != prevCapability) {
                 // No change on process state, but process capability has changed.
                 commitUidPendingState(uid);
-            } else if (uidState <= UID_STATE_MAX_LAST_NON_RESTRICTED) {
+            } else if (uidState <= UID_STATE_MAX_LAST_NON_RESTRICTED
+                    && (!delayUidStateChangesFromCapabilityUpdates() || !hasLostCapability)) {
                 // We are moving to a less important state, but it doesn't cross the restriction
                 // threshold.
                 commitUidPendingState(uid);
diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
index 0475b94..60dbf3f 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
@@ -389,7 +389,8 @@
      */
     private boolean shouldStartScoForUid(int uid) {
         return !(UserHandle.isSameApp(uid, Process.BLUETOOTH_UID)
-                || UserHandle.isSameApp(uid, Process.PHONE_UID));
+                || UserHandle.isSameApp(uid, Process.PHONE_UID)
+                || UserHandle.isSameApp(uid, Process.SYSTEM_UID));
     }
 
     @GuardedBy("mDeviceStateLock")
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 1563a62..fdf7dec 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -286,7 +286,6 @@
 import java.util.Set;
 import java.util.TreeSet;
 import java.util.concurrent.CancellationException;
-import java.util.concurrent.ConcurrentLinkedQueue;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.Executor;
 import java.util.concurrent.Executors;
@@ -2748,6 +2747,11 @@
         }
     }
 
+    @Override
+    protected void onUnhandledException(int code, int flags, Exception e) {
+        Slog.wtf(TAG, "Uncaught exception in AudioService: " + code + ", " + flags, e);
+    }
+
     @Override // Binder call
     public void onShellCommand(FileDescriptor in, FileDescriptor out,
             FileDescriptor err, String[] args, ShellCallback callback,
@@ -8044,7 +8048,14 @@
         }
         synchronized (mAbsoluteVolumeDeviceInfoMapLock) {
             if (mAbsoluteVolumeDeviceInfoMap.containsKey(audioSystemDeviceOut)) {
-                return mAbsoluteVolumeDeviceInfoMap.get(audioSystemDeviceOut).mDeviceVolumeBehavior;
+                final AbsoluteVolumeDeviceInfo deviceInfo = mAbsoluteVolumeDeviceInfoMap.get(
+                        audioSystemDeviceOut);
+                if (deviceInfo != null) {
+                    return deviceInfo.mDeviceVolumeBehavior;
+                }
+
+                Log.e(TAG,
+                        "Null absolute volume device info stored for key " + audioSystemDeviceOut);
             }
         }
 
@@ -15038,6 +15049,11 @@
 
     private void addAudioSystemDeviceOutToAbsVolumeDevices(int audioSystemDeviceOut,
             AbsoluteVolumeDeviceInfo info) {
+        if (info == null) {
+            Log.e(TAG, "Cannot add null absolute volume info for audioSystemDeviceOut "
+                    + audioSystemDeviceOut);
+            return;
+        }
         if (DEBUG_VOL) {
             Log.d(TAG, "Adding DeviceType: 0x" + Integer.toHexString(audioSystemDeviceOut)
                     + " to mAbsoluteVolumeDeviceInfoMap with behavior "
diff --git a/services/core/java/com/android/server/audio/LoudnessCodecHelper.java b/services/core/java/com/android/server/audio/LoudnessCodecHelper.java
index 01f770b..9fa5da4 100644
--- a/services/core/java/com/android/server/audio/LoudnessCodecHelper.java
+++ b/services/core/java/com/android/server/audio/LoudnessCodecHelper.java
@@ -133,6 +133,9 @@
     private static final EventLogger sLogger = new EventLogger(
             AudioService.LOG_NB_EVENTS_LOUDNESS_CODEC, "Loudness updates");
 
+    private final Object mDispatcherLock = new Object();
+
+    @GuardedBy("mDispatcherLock")
     private final LoudnessRemoteCallbackList mLoudnessUpdateDispatchers =
             new LoudnessRemoteCallbackList(this);
 
@@ -339,12 +342,16 @@
     }
 
     void registerLoudnessCodecUpdatesDispatcher(ILoudnessCodecUpdatesDispatcher dispatcher) {
-        mLoudnessUpdateDispatchers.register(dispatcher, Binder.getCallingPid());
+        synchronized (mDispatcherLock) {
+            mLoudnessUpdateDispatchers.register(dispatcher, Binder.getCallingPid());
+        }
     }
 
     void unregisterLoudnessCodecUpdatesDispatcher(
             ILoudnessCodecUpdatesDispatcher dispatcher) {
-        mLoudnessUpdateDispatchers.unregister(dispatcher);
+        synchronized (mDispatcherLock) {
+            mLoudnessUpdateDispatchers.unregister(dispatcher);
+        }
     }
 
     void startLoudnessCodecUpdates(int sessionId) {
@@ -640,17 +647,20 @@
             Log.d(TAG,
                     "dispatchNewLoudnessParameters: sessionId " + sessionId + " bundle: " + bundle);
         }
-        final int nbDispatchers = mLoudnessUpdateDispatchers.beginBroadcast();
-        for (int i = 0; i < nbDispatchers; ++i) {
-            try {
-                mLoudnessUpdateDispatchers.getBroadcastItem(i)
-                        .dispatchLoudnessCodecParameterChange(sessionId, bundle);
-            } catch (RemoteException e) {
-                Log.e(TAG, "Error dispatching for sessionId " + sessionId + " bundle: " + bundle,
-                        e);
+        synchronized (mDispatcherLock) {
+            final int nbDispatchers = mLoudnessUpdateDispatchers.beginBroadcast();
+            for (int i = 0; i < nbDispatchers; ++i) {
+                try {
+                    mLoudnessUpdateDispatchers.getBroadcastItem(i)
+                            .dispatchLoudnessCodecParameterChange(sessionId, bundle);
+                } catch (RemoteException e) {
+                    Log.e(TAG,
+                            "Error dispatching for sessionId " + sessionId + " bundle: " + bundle,
+                            e);
+                }
             }
+            mLoudnessUpdateDispatchers.finishBroadcast();
         }
-        mLoudnessUpdateDispatchers.finishBroadcast();
     }
 
     @GuardedBy("mLock")
diff --git a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
index 88268cd..a734e73 100644
--- a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
+++ b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
@@ -253,7 +253,11 @@
                 updateAllowedCapturePolicy(apc, mAllowedCapturePolicies.get(uid));
             }
         }
-        sEventLogger.enqueue(new NewPlayerEvent(apc));
+        var packages = mContext.getPackageManager().getPackagesForUid(apc.getClientUid());
+        sEventLogger.enqueue(new NewPlayerEvent(
+                    apc,
+                    packages != null && packages.length > 0 ? packages[0] : null
+                ));
         synchronized(mPlayerLock) {
             mPlayers.put(newPiid, apc);
             maybeMutePlayerAwaitingConnection(apc);
@@ -1402,14 +1406,16 @@
         private final int mPlayerIId;
         private final int mPlayerType;
         private final int mClientUid;
+        private final String mClientPackageName;
         private final int mClientPid;
         private final AudioAttributes mPlayerAttr;
         private final int mSessionId;
 
-        NewPlayerEvent(AudioPlaybackConfiguration apc) {
+        NewPlayerEvent(AudioPlaybackConfiguration apc, String packageName) {
             mPlayerIId = apc.getPlayerInterfaceId();
             mPlayerType = apc.getPlayerType();
             mClientUid = apc.getClientUid();
+            mClientPackageName = packageName;
             mClientPid = apc.getClientPid();
             mPlayerAttr = apc.getAudioAttributes();
             mSessionId = apc.getSessionId();
@@ -1418,7 +1424,7 @@
         @Override
         public String eventToString() {
             return new String("new player piid:" + mPlayerIId + " uid/pid:" + mClientUid + "/"
-                    + mClientPid + " type:"
+                    + mClientPid  + " package:" + mClientPackageName + " type:"
                     + AudioPlaybackConfiguration.toLogFriendlyPlayerType(mPlayerType)
                     + " attr:" + mPlayerAttr
                     + " session:" + mSessionId);
diff --git a/services/core/java/com/android/server/compat/PlatformCompat.java b/services/core/java/com/android/server/compat/PlatformCompat.java
index a9fe8cb..8d64383 100644
--- a/services/core/java/com/android/server/compat/PlatformCompat.java
+++ b/services/core/java/com/android/server/compat/PlatformCompat.java
@@ -242,7 +242,8 @@
         boolean enabled = true;
         final int userId = UserHandle.getUserId(uid);
         for (String packageName : packages) {
-            final var appInfo = getApplicationInfo(packageName, userId);
+            final var appInfo =
+                fixTargetSdk(getApplicationInfo(packageName, userId), uid);
             enabled &= isChangeEnabledInternal(changeId, appInfo);
         }
         return enabled;
@@ -261,7 +262,8 @@
         boolean enabled = true;
         final int userId = UserHandle.getUserId(uid);
         for (String packageName : packages) {
-            final var appInfo = getApplicationInfo(packageName, userId);
+            final var appInfo =
+                fixTargetSdk(getApplicationInfo(packageName, userId), uid);
             enabled &= isChangeEnabledInternalNoLogging(changeId, appInfo);
         }
         return enabled;
@@ -504,6 +506,15 @@
                 packageName, 0, Process.myUid(), userId);
     }
 
+    private ApplicationInfo fixTargetSdk(ApplicationInfo appInfo, int uid) {
+        // b/282922910 - we don't want apps sharing system uid and targeting
+        // older target sdk to impact all system uid apps
+        if (Flags.systemUidTargetSystemSdk() && uid == Process.SYSTEM_UID) {
+            appInfo.targetSdkVersion = Build.VERSION.SDK_INT;
+        }
+        return appInfo;
+    }
+
     private void killPackage(String packageName) {
         int uid = LocalServices.getService(PackageManagerInternal.class).getPackageUid(packageName,
                 0, UserHandle.myUserId());
diff --git a/services/core/java/com/android/server/compat/platform_compat_flags.aconfig b/services/core/java/com/android/server/compat/platform_compat_flags.aconfig
new file mode 100644
index 0000000..fb32323
--- /dev/null
+++ b/services/core/java/com/android/server/compat/platform_compat_flags.aconfig
@@ -0,0 +1,10 @@
+package: "com.android.server.compat"
+container: "system"
+
+flag {
+    name: "system_uid_target_system_sdk"
+    namespace: "app_compat"
+    description: "Compat framework feature flag for forcing all system uid apps to target system sdk"
+    bug: "29702703"
+    is_fixed_read_only: true
+}
diff --git a/services/core/java/com/android/server/devicestate/DeviceStateManagerService.java b/services/core/java/com/android/server/devicestate/DeviceStateManagerService.java
index 1094bee..8b9c664 100644
--- a/services/core/java/com/android/server/devicestate/DeviceStateManagerService.java
+++ b/services/core/java/com/android/server/devicestate/DeviceStateManagerService.java
@@ -778,15 +778,16 @@
         processRecord.notifyRequestActiveAsync(request.getToken());
     }
 
-    private void registerProcess(int pid, IDeviceStateManagerCallback callback) {
+    @Nullable
+    private DeviceStateInfo registerProcess(int pid, IDeviceStateManagerCallback callback) {
         synchronized (mLock) {
             if (mProcessRecords.contains(pid)) {
                 throw new SecurityException("The calling process has already registered an"
                         + " IDeviceStateManagerCallback.");
             }
 
-            ProcessRecord record = new ProcessRecord(callback, pid, this::handleProcessDied,
-                    mHandler);
+            final ProcessRecord record =
+                    new ProcessRecord(callback, pid, this::handleProcessDied, mHandler);
             try {
                 callback.asBinder().linkToDeath(record, 0);
             } catch (RemoteException ex) {
@@ -794,15 +795,20 @@
             }
             mProcessRecords.put(pid, record);
 
-            // Callback clients should not be notified of invalid device states, so calls to
-            // #getDeviceStateInfoLocked should be gated on checks if a committed state is present
-            // before getting the device state info.
-            DeviceStateInfo currentInfo = mCommittedState.isPresent()
-                    ? getDeviceStateInfoLocked() : null;
-            if (currentInfo != null) {
-                // If there is not a committed state we'll wait to notify the process of the initial
-                // value.
-                record.notifyDeviceStateInfoAsync(currentInfo);
+            final DeviceStateInfo currentInfo =
+                    mCommittedState.isPresent() ? getDeviceStateInfoLocked() : null;
+            if (com.android.window.flags.Flags.wlinfoOncreate()) {
+                return currentInfo;
+            } else {
+                // Callback clients should not be notified of invalid device states, so calls to
+                // #getDeviceStateInfoLocked should be gated on checks if a committed state is
+                // present before getting the device state info.
+                if (currentInfo != null) {
+                    // If there is not a committed state we'll wait to notify the process of the
+                    // initial value.
+                    record.notifyDeviceStateInfoAsync(currentInfo);
+                }
+                return null;
             }
         }
     }
@@ -1286,8 +1292,9 @@
             }
         }
 
+        @Nullable
         @Override // Binder call
-        public void registerCallback(IDeviceStateManagerCallback callback) {
+        public DeviceStateInfo registerCallback(IDeviceStateManagerCallback callback) {
             if (callback == null) {
                 throw new IllegalArgumentException("Device state callback must not be null.");
             }
@@ -1295,7 +1302,7 @@
             final int callingPid = Binder.getCallingPid();
             final long token = Binder.clearCallingIdentity();
             try {
-                registerProcess(callingPid, callback);
+                return registerProcess(callingPid, callback);
             } finally {
                 Binder.restoreCallingIdentity(token);
             }
diff --git a/services/core/java/com/android/server/display/DisplayDeviceConfig.java b/services/core/java/com/android/server/display/DisplayDeviceConfig.java
index 8d96ba9..c4e1036 100644
--- a/services/core/java/com/android/server/display/DisplayDeviceConfig.java
+++ b/services/core/java/com/android/server/display/DisplayDeviceConfig.java
@@ -150,7 +150,7 @@
  *      <screenBrightnessDefault>0.65</screenBrightnessDefault>
  *      <powerThrottlingConfig>
  *        <brightnessLowestCapAllowed>0.1</brightnessLowestCapAllowed>
- *        <customAnimationRateSec>0.004</customAnimationRateSec>
+ *        <customAnimationRate>0.004</customAnimationRate>
  *        <pollingWindowMaxMillis>30000</pollingWindowMaxMillis>
  *        <pollingWindowMinMillis>10000</pollingWindowMinMillis>
  *          <powerThrottlingMap>
@@ -2193,11 +2193,11 @@
             return;
         }
         float lowestBrightnessCap = powerThrottlingCfg.getBrightnessLowestCapAllowed().floatValue();
-        float customAnimationRateSec = powerThrottlingCfg.getCustomAnimationRateSec().floatValue();
+        float customAnimationRate = powerThrottlingCfg.getCustomAnimationRate().floatValue();
         int pollingWindowMaxMillis = powerThrottlingCfg.getPollingWindowMaxMillis().intValue();
         int pollingWindowMinMillis = powerThrottlingCfg.getPollingWindowMinMillis().intValue();
         mPowerThrottlingConfigData = new PowerThrottlingConfigData(lowestBrightnessCap,
-                                                                   customAnimationRateSec,
+                                                                   customAnimationRate,
                                                                    pollingWindowMaxMillis,
                                                                    pollingWindowMinMillis);
     }
@@ -3012,16 +3012,16 @@
         /** Lowest brightness cap allowed for this device. */
         public final float brightnessLowestCapAllowed;
         /** Time take to animate brightness in seconds. */
-        public final float customAnimationRateSec;
+        public final float customAnimationRate;
         /** Time window for maximum polling power in milliseconds. */
         public final int pollingWindowMaxMillis;
         /** Time window for minimum polling power in milliseconds. */
         public final int pollingWindowMinMillis;
         public PowerThrottlingConfigData(float brightnessLowestCapAllowed,
-                float customAnimationRateSec, int pollingWindowMaxMillis,
+                float customAnimationRate, int pollingWindowMaxMillis,
                 int pollingWindowMinMillis) {
             this.brightnessLowestCapAllowed = brightnessLowestCapAllowed;
-            this.customAnimationRateSec = customAnimationRateSec;
+            this.customAnimationRate = customAnimationRate;
             this.pollingWindowMaxMillis = pollingWindowMaxMillis;
             this.pollingWindowMinMillis = pollingWindowMinMillis;
         }
@@ -3031,7 +3031,7 @@
             return "PowerThrottlingConfigData{"
                     + "brightnessLowestCapAllowed: "
                     + brightnessLowestCapAllowed
-                    + ", customAnimationRateSec: " + customAnimationRateSec
+                    + ", customAnimationRate: " + customAnimationRate
                     + ", pollingWindowMaxMillis: " + pollingWindowMaxMillis
                     + ", pollingWindowMinMillis: " + pollingWindowMinMillis
                     + "} ";
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index 3dc531e..3603cdb 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -1769,10 +1769,11 @@
             flags &= ~VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP;
         }
         // Put the display in the virtual device's display group only if it's not a mirror display,
-        // and if it doesn't need its own display group. So effectively, mirror displays go into the
-        // default display group.
+        // it is a trusted display, and it doesn't need its own display group. So effectively,
+        // mirror and untrusted displays go into the default display group.
         if ((flags & VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP) == 0
                 && (flags & VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR) == 0
+                && (flags & VIRTUAL_DISPLAY_FLAG_TRUSTED) == VIRTUAL_DISPLAY_FLAG_TRUSTED
                 && virtualDevice != null) {
             flags |= VIRTUAL_DISPLAY_FLAG_DEVICE_DISPLAY_GROUP;
         }
@@ -1848,9 +1849,7 @@
 
         if (callingUid != Process.SYSTEM_UID
                 && (flags & VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP) != 0) {
-            // The virtualDevice instance has been validated above using isValidVirtualDevice
-            if (virtualDevice == null
-                    && !checkCallingPermission(ADD_TRUSTED_DISPLAY, "createVirtualDisplay()")) {
+            if (!checkCallingPermission(ADD_TRUSTED_DISPLAY, "createVirtualDisplay()")) {
                 throw new SecurityException("Requires ADD_TRUSTED_DISPLAY permission to "
                         + "create a virtual display which is not in the default DisplayGroup.");
             }
@@ -1978,7 +1977,7 @@
                         // handles stopping the projection.
                         Slog.w(TAG, "Content Recording: failed to start mirroring - "
                                 + "releasing virtual display " + displayId);
-                        releaseVirtualDisplayInternal(callback.asBinder());
+                        releaseVirtualDisplayInternal(callback.asBinder(), callingUid);
                         return Display.INVALID_DISPLAY;
                     } else if (projection != null) {
                         // Indicate that this projection has been used to record, and can't be used
@@ -2067,7 +2066,7 @@
         // Something weird happened and the logical display was not created.
         Slog.w(TAG, "Rejecting request to create virtual display "
                 + "because the logical display was not created.");
-        mVirtualDisplayAdapter.releaseVirtualDisplayLocked(callback.asBinder());
+        mVirtualDisplayAdapter.releaseVirtualDisplayLocked(callback.asBinder(), callingUid);
         mDisplayDeviceRepo.onDisplayDeviceEvent(device,
                 DisplayAdapter.DISPLAY_DEVICE_EVENT_REMOVED);
         return -1;
@@ -2094,14 +2093,14 @@
         }
     }
 
-    private void releaseVirtualDisplayInternal(IBinder appToken) {
+    private void releaseVirtualDisplayInternal(IBinder appToken, int callingUid) {
         synchronized (mSyncRoot) {
             if (mVirtualDisplayAdapter == null) {
                 return;
             }
 
             DisplayDevice device =
-                    mVirtualDisplayAdapter.releaseVirtualDisplayLocked(appToken);
+                    mVirtualDisplayAdapter.releaseVirtualDisplayLocked(appToken, callingUid);
             Slog.d(TAG, "Virtual Display: Display Device released");
             if (device != null) {
                 // TODO: multi-display - handle virtual displays the same as other display adapters.
@@ -2302,6 +2301,14 @@
         updateLogicalDisplayState(display);
 
         mExternalDisplayPolicy.handleLogicalDisplayAddedLocked(display);
+
+        if (mFlags.isApplyDisplayChangedDuringDisplayAddedEnabled()) {
+            applyDisplayChangedLocked(display);
+        }
+
+        if (mDisplayTopologyCoordinator != null) {
+            mDisplayTopologyCoordinator.onDisplayAdded(display.getDisplayInfoLocked());
+        }
     }
 
     private void handleLogicalDisplayChangedLocked(@NonNull LogicalDisplay display) {
@@ -2389,6 +2396,9 @@
         } else {
             releaseDisplayAndEmitEvent(display, DisplayManagerGlobal.EVENT_DISPLAY_REMOVED);
         }
+        if (mDisplayTopologyCoordinator != null) {
+            mDisplayTopologyCoordinator.onDisplayRemoved(display.getDisplayIdLocked());
+        }
 
         Slog.i(TAG, "Logical display removed: " + display.getDisplayIdLocked());
     }
@@ -4614,9 +4624,10 @@
 
         @Override // Binder call
         public void releaseVirtualDisplay(IVirtualDisplayCallback callback) {
+            final int callingUid = Binder.getCallingUid();
             final long token = Binder.clearCallingIdentity();
             try {
-                releaseVirtualDisplayInternal(callback.asBinder());
+                releaseVirtualDisplayInternal(callback.asBinder(), callingUid);
             } finally {
                 Binder.restoreCallingIdentity(token);
             }
@@ -5660,6 +5671,11 @@
                 displayPowerController.stylusGestureStarted(eventTime);
             }
         }
+
+        @Override
+        public boolean isDisplayReadyForMirroring(int displayId) {
+            return mExternalDisplayPolicy.isDisplayReadyForMirroring(displayId);
+        }
     }
 
     class DesiredDisplayModeSpecsObserver
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index 8f07bb3..42a62f0 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -546,7 +546,8 @@
         mLastBrightnessEvent = new BrightnessEvent(mDisplayId);
         mTempBrightnessEvent = new BrightnessEvent(mDisplayId);
 
-        if (flags.isBatteryStatsEnabledForAllDisplays()) {
+        if (flags.isBatteryStatsEnabledForAllDisplays()
+                && isDisplaySupportedForBatteryStats(displayDeviceInfo)) {
             mBatteryStats = BatteryStatsService.getService();
         } else if (mDisplayId == Display.DEFAULT_DISPLAY) {
             mBatteryStats = BatteryStatsService.getService();
@@ -2772,6 +2773,16 @@
         }
     }
 
+    private static boolean isDisplaySupportedForBatteryStats(DisplayDeviceInfo displayDeviceInfo) {
+        switch (displayDeviceInfo.type) {
+            case Display.TYPE_INTERNAL:
+            case Display.TYPE_EXTERNAL:
+                return true;
+            default:
+                return false;
+        }
+    }
+
     private void dumpBrightnessEvents(PrintWriter pw) {
         int size = mBrightnessEventRingBuffer.size();
         if (size < 1) {
diff --git a/services/core/java/com/android/server/display/DisplayTopology.java b/services/core/java/com/android/server/display/DisplayTopology.java
index 90038a0..b01d617 100644
--- a/services/core/java/com/android/server/display/DisplayTopology.java
+++ b/services/core/java/com/android/server/display/DisplayTopology.java
@@ -20,12 +20,15 @@
 import android.util.IndentingPrintWriter;
 import android.util.Pair;
 import android.util.Slog;
+import android.view.Display;
 
 import com.android.internal.annotations.VisibleForTesting;
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
+import java.util.LinkedList;
 import java.util.List;
+import java.util.Queue;
 
 /**
  * Represents the relative placement of extended displays.
@@ -45,35 +48,50 @@
      * This is not necessarily the same as the default display.
      */
     @VisibleForTesting
-    int mPrimaryDisplayId;
+    int mPrimaryDisplayId = Display.INVALID_DISPLAY;
 
     /**
      * Add a display to the topology.
      * If this is the second display in the topology, it will be placed above the first display.
      * Subsequent displays will be places to the left or right of the second display.
-     * @param displayId The ID of the display
+     * @param displayId The logical display ID
      * @param width The width of the display
      * @param height The height of the display
      */
     void addDisplay(int displayId, double width, double height) {
-        if (mRoot == null) {
-            mRoot = new TreeNode(displayId, width, height, /* position= */ null, /* offset= */ 0);
-            mPrimaryDisplayId = displayId;
-            Slog.i(TAG, "First display added: " + mRoot);
-        } else if (mRoot.mChildren.isEmpty()) {
-            // This is the 2nd display. Align the middles of the top and bottom edges.
-            double offset = mRoot.mWidth / 2 - width / 2;
-            TreeNode display = new TreeNode(displayId, width, height,
-                    TreeNode.Position.POSITION_TOP, offset);
-            mRoot.mChildren.add(display);
-            Slog.i(TAG, "Second display added: " + display + ", parent ID: " + mRoot.mDisplayId);
+        addDisplay(displayId, width, height, /* shouldLog= */ true);
+    }
+
+    /**
+     * Remove a display from the topology.
+     * The default topology is created from the remaining displays, as if they were reconnected
+     * one by one.
+     * @param displayId The logical display ID
+     */
+    void removeDisplay(int displayId) {
+        if (!isDisplayPresent(displayId, mRoot)) {
+            return;
+        }
+        Queue<TreeNode> queue = new LinkedList<>();
+        queue.add(mRoot);
+        mRoot = null;
+        while (!queue.isEmpty()) {
+            TreeNode node = queue.poll();
+            if (node.mDisplayId != displayId) {
+                addDisplay(node.mDisplayId, node.mWidth, node.mHeight, /* shouldLog= */ false);
+            }
+            queue.addAll(node.mChildren);
+        }
+        if (mPrimaryDisplayId == displayId) {
+            if (mRoot != null) {
+                mPrimaryDisplayId = mRoot.mDisplayId;
+            } else {
+                mPrimaryDisplayId = Display.INVALID_DISPLAY;
+            }
+            Slog.i(TAG,  "Primary display with ID " + displayId
+                    + " removed, new primary display: " + mPrimaryDisplayId);
         } else {
-            TreeNode rightMostDisplay = findRightMostDisplay(mRoot, mRoot.mWidth).first;
-            TreeNode newDisplay = new TreeNode(displayId, width, height,
-                    TreeNode.Position.POSITION_RIGHT, /* offset= */ 0);
-            rightMostDisplay.mChildren.add(newDisplay);
-            Slog.i(TAG, "Display added: " + newDisplay + ", parent ID: "
-                    + rightMostDisplay.mDisplayId);
+            Slog.i(TAG, "Display with ID " + displayId + " removed");
         }
     }
 
@@ -97,6 +115,35 @@
         }
     }
 
+    private void addDisplay(int displayId, double width, double height, boolean shouldLog) {
+        if (mRoot == null) {
+            mRoot = new TreeNode(displayId, width, height, /* position= */ null, /* offset= */ 0);
+            mPrimaryDisplayId = displayId;
+            if (shouldLog) {
+                Slog.i(TAG, "First display added: " + mRoot);
+            }
+        } else if (mRoot.mChildren.isEmpty()) {
+            // This is the 2nd display. Align the middles of the top and bottom edges.
+            double offset = mRoot.mWidth / 2 - width / 2;
+            TreeNode display = new TreeNode(displayId, width, height,
+                    TreeNode.Position.POSITION_TOP, offset);
+            mRoot.mChildren.add(display);
+            if (shouldLog) {
+                Slog.i(TAG, "Second display added: " + display + ", parent ID: "
+                        + mRoot.mDisplayId);
+            }
+        } else {
+            TreeNode rightMostDisplay = findRightMostDisplay(mRoot, mRoot.mWidth).first;
+            TreeNode newDisplay = new TreeNode(displayId, width, height,
+                    TreeNode.Position.POSITION_RIGHT, /* offset= */ 0);
+            rightMostDisplay.mChildren.add(newDisplay);
+            if (shouldLog) {
+                Slog.i(TAG, "Display added: " + newDisplay + ", parent ID: "
+                        + rightMostDisplay.mDisplayId);
+            }
+        }
+    }
+
     /**
      * @param display The display from which the search should start.
      * @param xPos The x position of the right edge of that display.
@@ -126,6 +173,21 @@
         return result;
     }
 
+    private boolean isDisplayPresent(int displayId, TreeNode node) {
+        if (node == null) {
+            return false;
+        }
+        if (node.mDisplayId == displayId) {
+            return true;
+        }
+        for (TreeNode child : node.mChildren) {
+            if (isDisplayPresent(displayId, child)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
     @VisibleForTesting
     static class TreeNode {
 
diff --git a/services/core/java/com/android/server/display/DisplayTopologyCoordinator.java b/services/core/java/com/android/server/display/DisplayTopologyCoordinator.java
index cbd224c..46358dfd 100644
--- a/services/core/java/com/android/server/display/DisplayTopologyCoordinator.java
+++ b/services/core/java/com/android/server/display/DisplayTopologyCoordinator.java
@@ -66,6 +66,16 @@
     }
 
     /**
+     * Remove a display from the topology.
+     * @param displayId The logical display ID
+     */
+    void onDisplayRemoved(int displayId) {
+        synchronized (mLock) {
+            mTopology.removeDisplay(displayId);
+        }
+    }
+
+    /**
      * Print the object's state and debug information into the given stream.
      * @param pw The stream to dump information to.
      */
diff --git a/services/core/java/com/android/server/display/ExternalDisplayPolicy.java b/services/core/java/com/android/server/display/ExternalDisplayPolicy.java
index 28a0b28..f34d2cc 100644
--- a/services/core/java/com/android/server/display/ExternalDisplayPolicy.java
+++ b/services/core/java/com/android/server/display/ExternalDisplayPolicy.java
@@ -375,6 +375,54 @@
         }
     }
 
+    boolean isDisplayReadyForMirroring(int displayId) {
+        if (!mFlags.isWaitingConfirmationBeforeMirroringEnabled()) {
+            if (DEBUG) {
+                Slog.d(TAG, "isDisplayReadyForMirroring: mirroring CONFIRMED - "
+                        + " flag 'waiting for confirmation before mirroring' is disabled");
+            }
+            return true;
+        }
+
+        synchronized (mSyncRoot) {
+            if (!mIsBootCompleted) {
+                if (DEBUG) {
+                    Slog.d(TAG, "isDisplayReadyForMirroring: mirroring is not confirmed - "
+                            + "boot is in progress");
+                }
+                return false;
+            }
+
+            var logicalDisplay = mLogicalDisplayMapper.getDisplayLocked(displayId);
+            if (logicalDisplay == null) {
+                if (DEBUG) {
+                    Slog.d(TAG, "isDisplayReadyForMirroring: mirroring is not confirmed - "
+                            + "logicalDisplay is null");
+                }
+                return false;
+            }
+
+            if (!isExternalDisplayLocked(logicalDisplay)) {
+                if (DEBUG) {
+                    Slog.d(TAG, "isDisplayReadyForMirroring: mirroring is not confirmed - "
+                            + "logicalDisplay" + logicalDisplay.getDisplayIdLocked()
+                            + " type is " + logicalDisplay.getDisplayInfoLocked().type);
+                }
+                return false;
+            }
+
+            if (!logicalDisplay.isEnabledLocked()) {
+                if (DEBUG) {
+                    Slog.d(TAG, "isDisplayReadyForMirroring: mirroring is not confirmed - "
+                            + "logicalDisplay is disabled");
+                }
+                return false;
+            }
+        }
+
+        return true;
+    }
+
     private final class SkinThermalStatusObserver extends IThermalEventListener.Stub {
         @Override
         public void notifyThrottling(@NonNull final Temperature temp) {
diff --git a/services/core/java/com/android/server/display/LogicalDisplayMapper.java b/services/core/java/com/android/server/display/LogicalDisplayMapper.java
index 06a9103..09fa4e6 100644
--- a/services/core/java/com/android/server/display/LogicalDisplayMapper.java
+++ b/services/core/java/com/android/server/display/LogicalDisplayMapper.java
@@ -16,6 +16,7 @@
 
 package com.android.server.display;
 
+import static android.hardware.devicestate.DeviceState.PROPERTY_EMULATED_ONLY;
 import static android.hardware.devicestate.DeviceState.PROPERTY_POWER_CONFIGURATION_TRIGGER_SLEEP;
 import static android.hardware.devicestate.DeviceState.PROPERTY_POWER_CONFIGURATION_TRIGGER_WAKE;
 import static android.hardware.devicestate.DeviceStateManager.INVALID_DEVICE_STATE;
@@ -594,6 +595,13 @@
     boolean shouldDeviceBeWoken(DeviceState pendingState, DeviceState currentState,
             boolean isInteractive, boolean isBootCompleted) {
         if (mDeviceStateManagerFlags.deviceStatePropertyMigration()) {
+            if (currentState.hasProperties(PROPERTY_EMULATED_ONLY)
+                    && !pendingState.hasProperties(PROPERTY_EMULATED_ONLY)) {
+                // Do not wake the device, since this transition may occur due to the user pressing
+                // the power button to exit an emulated state.
+                return false;
+            }
+
             return pendingState.hasProperty(PROPERTY_POWER_CONFIGURATION_TRIGGER_WAKE)
                     && !currentState.equals(INVALID_DEVICE_STATE)
                     && !currentState.hasProperty(PROPERTY_POWER_CONFIGURATION_TRIGGER_WAKE)
diff --git a/services/core/java/com/android/server/display/VirtualDisplayAdapter.java b/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
index e77c5ec..4211453 100644
--- a/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
@@ -55,12 +55,14 @@
 import android.os.SystemProperties;
 import android.util.ArrayMap;
 import android.util.Slog;
+import android.util.SparseIntArray;
 import android.view.Display;
 import android.view.DisplayCutout;
 import android.view.DisplayShape;
 import android.view.Surface;
 import android.view.SurfaceControl;
 
+import com.android.internal.R;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.server.display.feature.DisplayManagerFlags;
 
@@ -85,6 +87,11 @@
     private static final AtomicInteger sNextUniqueIndex = new AtomicInteger(0);
 
     private final ArrayMap<IBinder, VirtualDisplayDevice> mVirtualDisplayDevices = new ArrayMap<>();
+
+    private final int mMaxDevices;
+    private final int mMaxDevicesPerPackage;
+    private final SparseIntArray mNoOfDevicesPerPackage = new SparseIntArray();
+
     private final Handler mHandler;
     private final SurfaceControlDisplayFactory mSurfaceControlDisplayFactory;
 
@@ -114,8 +121,31 @@
         super(syncRoot, context, handler, listener, TAG, featureFlags);
         mHandler = handler;
         mSurfaceControlDisplayFactory = surfaceControlDisplayFactory;
+
+        mMaxDevices = context.getResources().getInteger(R.integer.config_virtualDisplayLimit);
+        if (mMaxDevices < 1) {
+            throw new IllegalArgumentException("The limit of virtual displays must be >= 1");
+        }
+        mMaxDevicesPerPackage =
+                context.getResources().getInteger(R.integer.config_virtualDisplayLimitPerPackage);
+        if (mMaxDevicesPerPackage < 1) {
+            throw new IllegalArgumentException(
+                    "The limit of virtual displays per package must be >= 1");
+        }
     }
 
+    /**
+     * Create a virtual display
+     * @param callback The callback
+     * @param projection The media projection
+     * @param ownerUid The UID of the package creating a display
+     * @param ownerPackageName The name of the package creating a display
+     * @param uniqueId The unique ID of the display device
+     * @param surface The surface
+     * @param flags The flags
+     * @param virtualDisplayConfig The config
+     * @return The display device created
+     */
     public DisplayDevice createVirtualDisplayLocked(IVirtualDisplayCallback callback,
             IMediaProjection projection, int ownerUid, String ownerPackageName, String uniqueId,
             Surface surface, int flags, VirtualDisplayConfig virtualDisplayConfig) {
@@ -126,6 +156,22 @@
             return null;
         }
 
+        if (getFeatureFlags().isVirtualDisplayLimitEnabled()
+                && mVirtualDisplayDevices.size() >= mMaxDevices) {
+            Slog.w(TAG, "Rejecting request to create private virtual display because "
+                    + mMaxDevices + " devices already exist.");
+            return null;
+        }
+
+        int noOfDevices = mNoOfDevicesPerPackage.get(ownerUid, /* valueIfKeyNotFound= */ 0);
+        if (getFeatureFlags().isVirtualDisplayLimitEnabled()
+                && noOfDevices >= mMaxDevicesPerPackage) {
+            Slog.w(TAG, "Rejecting request to create private virtual display because "
+                    + mMaxDevicesPerPackage + " devices already exist for package "
+                    + ownerPackageName + ".");
+            return null;
+        }
+
         String name = virtualDisplayConfig.getName();
         boolean secure = (flags & VIRTUAL_DISPLAY_FLAG_SECURE) != 0;
 
@@ -140,6 +186,9 @@
                 projection, mediaProjectionCallback, uniqueId, virtualDisplayConfig);
 
         mVirtualDisplayDevices.put(appToken, device);
+        if (getFeatureFlags().isVirtualDisplayLimitEnabled()) {
+            mNoOfDevicesPerPackage.put(ownerUid, noOfDevices + 1);
+        }
 
         try {
             if (projection != null) {
@@ -150,7 +199,7 @@
             appToken.linkToDeath(device, 0);
         } catch (RemoteException ex) {
             Slog.e(TAG, "Virtual Display: error while setting up VirtualDisplayDevice", ex);
-            mVirtualDisplayDevices.remove(appToken);
+            removeVirtualDisplayDeviceLocked(appToken, ownerUid);
             device.destroyLocked(false);
             return null;
         }
@@ -194,8 +243,15 @@
         }
     }
 
-    public DisplayDevice releaseVirtualDisplayLocked(IBinder appToken) {
-        VirtualDisplayDevice device = mVirtualDisplayDevices.remove(appToken);
+    /**
+     * Release a virtual display that was previously created
+     * @param appToken The token to identify the display
+     * @param ownerUid The UID of the package, used to keep track of and limit the number of
+     *                 displays created per package
+     * @return The display device that has been removed
+     */
+    public DisplayDevice releaseVirtualDisplayLocked(IBinder appToken, int ownerUid) {
+        VirtualDisplayDevice device = removeVirtualDisplayDeviceLocked(appToken, ownerUid);
         if (device != null) {
             Slog.v(TAG, "Release VirtualDisplay " + device.mName);
             device.destroyLocked(true);
@@ -228,10 +284,6 @@
                 : ("," + uid + "," + config.getName() + "," + sNextUniqueIndex.getAndIncrement()));
     }
 
-    private void handleBinderDiedLocked(IBinder appToken) {
-        mVirtualDisplayDevices.remove(appToken);
-    }
-
     private void handleMediaProjectionStoppedLocked(IBinder appToken) {
         VirtualDisplayDevice device = mVirtualDisplayDevices.get(appToken);
         if (device != null) {
@@ -241,6 +293,18 @@
         }
     }
 
+    private VirtualDisplayDevice removeVirtualDisplayDeviceLocked(IBinder appToken, int ownerUid) {
+        int noOfDevices = mNoOfDevicesPerPackage.get(ownerUid, /* valueIfKeyNotFound= */ 0);
+        if (getFeatureFlags().isVirtualDisplayLimitEnabled()) {
+            if (noOfDevices <= 1) {
+                mNoOfDevicesPerPackage.delete(ownerUid);
+            } else {
+                mNoOfDevicesPerPackage.put(ownerUid, noOfDevices - 1);
+            }
+        }
+        return mVirtualDisplayDevices.remove(appToken);
+    }
+
     private final class VirtualDisplayDevice extends DisplayDevice implements DeathRecipient {
         private static final int PENDING_SURFACE_CHANGE = 0x01;
         private static final int PENDING_RESIZE = 0x02;
@@ -300,7 +364,7 @@
         @Override
         public void binderDied() {
             synchronized (getSyncRoot()) {
-                handleBinderDiedLocked(mAppToken);
+                removeVirtualDisplayDeviceLocked(mAppToken, mOwnerUid);
                 Slog.i(TAG, "Virtual display device released because application token died: "
                     + mOwnerPackageName);
                 destroyLocked(false);
diff --git a/services/core/java/com/android/server/display/brightness/clamper/BrightnessPowerClamper.java b/services/core/java/com/android/server/display/brightness/clamper/BrightnessPowerClamper.java
index 85e81f9..1a18b00 100644
--- a/services/core/java/com/android/server/display/brightness/clamper/BrightnessPowerClamper.java
+++ b/services/core/java/com/android/server/display/brightness/clamper/BrightnessPowerClamper.java
@@ -85,7 +85,7 @@
     private String mDataId = null;
     private float mCurrentBrightness = PowerManager.BRIGHTNESS_INVALID;
     private float mCustomAnimationRateSec = DisplayBrightnessState.CUSTOM_ANIMATION_RATE_NOT_SET;
-    private float mCustomAnimationRateSecDeviceConfig =
+    private float mCustomAnimationRateDeviceConfig =
                         DisplayBrightnessState.CUSTOM_ANIMATION_RATE_NOT_SET;
     private final BiFunction<String, String, ThrottlingLevel> mDataPointMapper = (key, value) -> {
         try {
@@ -117,7 +117,7 @@
         };
         mPowerThrottlingConfigData = powerData.getPowerThrottlingConfigData();
         if (mPowerThrottlingConfigData != null) {
-            mCustomAnimationRateSecDeviceConfig = mPowerThrottlingConfigData.customAnimationRateSec;
+            mCustomAnimationRateDeviceConfig = mPowerThrottlingConfigData.customAnimationRate;
         }
         mThermalLevelListener = new ThermalLevelListener(handler);
         mPmicMonitor =
@@ -228,10 +228,6 @@
         }
 
         mPowerThrottlingConfigData = data.getPowerThrottlingConfigData();
-        if (mPowerThrottlingConfigData == null) {
-            Slog.d(TAG,
-                    "Power throttling data is missing for configuration data.");
-        }
     }
 
     private void recalculateBrightnessCap() {
@@ -282,13 +278,13 @@
             mIsActive = isActive;
             Slog.i(TAG, "Power clamper changing current brightness cap mBrightnessCap: "
                     + mBrightnessCap + " to target brightness cap:" + targetBrightnessCap
-                    + " for current screen brightness: " + mCurrentBrightness);
-            mBrightnessCap = targetBrightnessCap;
-            Slog.i(TAG, "Power clamper changed state: thermalStatus:" + mCurrentThermalLevel
+                    + " for current screen brightness: " + mCurrentBrightness + "\n"
+                    + "Power clamper changed state: thermalStatus:" + mCurrentThermalLevel
                     + " mCurrentThermalLevelChanged:" + mCurrentThermalLevelChanged
                     + " mCurrentAvgPowerConsumed:" + mCurrentAvgPowerConsumed
-                    + " mCustomAnimationRateSec:" + mCustomAnimationRateSecDeviceConfig);
-            mCustomAnimationRateSec = mCustomAnimationRateSecDeviceConfig;
+                    + " mCustomAnimationRateSec:" + mCustomAnimationRateDeviceConfig);
+            mBrightnessCap = targetBrightnessCap;
+            mCustomAnimationRateSec = mCustomAnimationRateDeviceConfig;
             mChangeListener.onChanged();
         } else {
             mCustomAnimationRateSec = DisplayBrightnessState.CUSTOM_ANIMATION_RATE_NOT_SET;
@@ -344,7 +340,7 @@
                     + mPowerThrottlingConfigData.pollingWindowMinMillis + " msec.");
             return;
         }
-        mCustomAnimationRateSecDeviceConfig = mPowerThrottlingConfigData.customAnimationRateSec;
+        mCustomAnimationRateDeviceConfig = mPowerThrottlingConfigData.customAnimationRate;
         mThermalLevelListener.start();
     }
 
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 5284d1c..70bf566 100644
--- a/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java
+++ b/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java
@@ -199,6 +199,11 @@
             Flags.FLAG_IDLE_SCREEN_CONFIG_IN_SUBSCRIBING_LIGHT_SENSOR,
             Flags::idleScreenConfigInSubscribingLightSensor);
 
+    private final FlagState mVirtualDisplayLimit =
+            new FlagState(
+                    Flags.FLAG_VIRTUAL_DISPLAY_LIMIT,
+                    Flags::virtualDisplayLimit);
+
     private final FlagState mNormalBrightnessForDozeParameter = new FlagState(
             Flags.FLAG_NORMAL_BRIGHTNESS_FOR_DOZE_PARAMETER,
             Flags::normalBrightnessForDozeParameter
@@ -207,6 +212,20 @@
             Flags.FLAG_BLOCK_AUTOBRIGHTNESS_CHANGES_ON_STYLUS_USAGE,
             Flags::blockAutobrightnessChangesOnStylusUsage
     );
+    private final FlagState mIsUserRefreshRateForExternalDisplayEnabled = new FlagState(
+            Flags.FLAG_ENABLE_USER_REFRESH_RATE_FOR_EXTERNAL_DISPLAY,
+            Flags::enableUserRefreshRateForExternalDisplay
+    );
+
+    private final FlagState mEnableWaitingConfirmationBeforeMirroring = new FlagState(
+            Flags.FLAG_ENABLE_WAITING_CONFIRMATION_BEFORE_MIRRORING,
+            Flags::enableWaitingConfirmationBeforeMirroring
+    );
+
+    private final FlagState mEnableApplyDisplayChangedDuringDisplayAdded = new FlagState(
+            Flags.FLAG_ENABLE_APPLY_DISPLAY_CHANGED_DURING_DISPLAY_ADDED,
+            Flags::enableApplyDisplayChangedDuringDisplayAdded
+    );
 
     private final FlagState mEnableBatteryStatsForAllDisplays = new FlagState(
             Flags.FLAG_ENABLE_BATTERY_STATS_FOR_ALL_DISPLAYS,
@@ -416,6 +435,10 @@
         return mNewHdrBrightnessModifier.isEnabled();
     }
 
+    public boolean isVirtualDisplayLimitEnabled() {
+        return mVirtualDisplayLimit.isEnabled();
+    }
+
     /**
      * @return Whether the useDozeBrightness parameter should be used
      */
@@ -432,6 +455,14 @@
     }
 
     /**
+      * @return {@code true} if mirroring won't be enabled until boot completes and the user enables
+      * the display.
+      */
+    public boolean isWaitingConfirmationBeforeMirroringEnabled() {
+        return mEnableWaitingConfirmationBeforeMirroring.isEnabled();
+    }
+
+    /**
       * @return {@code true} if battery stats is enabled for all displays, not just the primary
       * display.
       */
@@ -440,6 +471,13 @@
     }
 
     /**
+      * @return {@code true} if need to apply display changes during display added event.
+      */
+    public boolean isApplyDisplayChangedDuringDisplayAddedEnabled() {
+        return mEnableApplyDisplayChangedDuringDisplayAdded.isEnabled();
+    }
+
+    /**
      * @return {@code true} if autobrightness is to be blocked when stylus is being used
      */
     public boolean isBlockAutobrightnessChangesOnStylusUsage() {
@@ -447,6 +485,14 @@
     }
 
     /**
+     * @return {@code true} if need to use user refresh rate settings for
+     * external displays.
+     */
+    public boolean isUserRefreshRateForExternalDisplayEnabled() {
+        return mIsUserRefreshRateForExternalDisplayEnabled.isEnabled();
+    }
+
+    /**
      * dumps all flagstates
      * @param pw printWriter
      */
@@ -487,10 +533,14 @@
         pw.println(" " + mOffloadDozeOverrideHoldsWakelock);
         pw.println(" " + mOffloadSessionCancelBlockScreenOn);
         pw.println(" " + mNewHdrBrightnessModifier);
+        pw.println(" " + mVirtualDisplayLimit);
         pw.println(" " + mNormalBrightnessForDozeParameter);
         pw.println(" " + mIdleScreenConfigInSubscribingLightSensor);
+        pw.println(" " + mEnableWaitingConfirmationBeforeMirroring);
         pw.println(" " + mEnableBatteryStatsForAllDisplays);
+        pw.println(" " + mEnableApplyDisplayChangedDuringDisplayAdded);
         pw.println(" " + mBlockAutobrightnessChangesOnStylusUsage);
+        pw.println(" " + mIsUserRefreshRateForExternalDisplayEnabled);
     }
 
     private static class FlagState {
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 252ed09..602c699 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
@@ -348,6 +348,14 @@
 }
 
 flag {
+    name: "virtual_display_limit"
+    namespace: "display_manager"
+    description: "Limit the number of virtual displays that can be created."
+    bug: "261791612"
+    is_fixed_read_only: true
+}
+
+flag {
     name: "idle_screen_config_in_subscribing_light_sensor"
     namespace: "display_manager"
     description: "Account for Idle screen refresh rate configs while subscribing to light sensor"
@@ -359,6 +367,17 @@
 }
 
 flag {
+    name: "enable_waiting_confirmation_before_mirroring"
+    namespace: "display_manager"
+    description: "Allow ContentRecorder checking whether user confirmed mirroring after boot"
+    bug: "361698995"
+    is_fixed_read_only: true
+    metadata {
+      purpose: PURPOSE_BUGFIX
+    }
+}
+
+flag {
     name: "enable_battery_stats_for_all_displays"
     namespace: "display_manager"
     description: "Flag to enable battery stats for all displays."
@@ -367,9 +386,31 @@
 }
 
 flag {
+    name: "enable_apply_display_changed_during_display_added"
+    namespace: "display_manager"
+    description: "Apply display changes after display added"
+    bug: "368131655"
+    is_fixed_read_only: true
+    metadata {
+      purpose: PURPOSE_BUGFIX
+    }
+}
+
+flag {
     name: "block_autobrightness_changes_on_stylus_usage"
     namespace: "display_manager"
     description: "Block the usage of ALS to control the display brightness when stylus is being used"
     bug: "352411468"
     is_fixed_read_only: true
 }
+
+flag {
+    name: "enable_user_refresh_rate_for_external_display"
+    namespace: "display_manager"
+    description: "Apply refresh rate from user preferred display mode to external displays"
+    bug: "370657357"
+    is_fixed_read_only: true
+    metadata {
+      purpose: PURPOSE_BUGFIX
+    }
+}
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 18e0d6e..ffa64bf 100644
--- a/services/core/java/com/android/server/display/mode/DisplayModeDirector.java
+++ b/services/core/java/com/android/server/display/mode/DisplayModeDirector.java
@@ -1194,6 +1194,13 @@
         @GuardedBy("mLock")
         private void updateRefreshRateSettingLocked(float minRefreshRate, float peakRefreshRate,
                 float defaultRefreshRate, int displayId) {
+            if (mDisplayObserver.isExternalDisplayLocked(displayId)) {
+                if (mLoggingEnabled) {
+                    Slog.d(TAG, "skip updateRefreshRateSettingLocked for external display "
+                            + displayId);
+                }
+                return;
+            }
             // TODO(b/156304339): The logic in here, aside from updating the refresh rate votes, is
             // used to predict if we're going to be doing frequent refresh rate switching, and if
             // so, enable the brightness observer. The logic here is more complicated and fragile
@@ -1243,6 +1250,8 @@
         }
 
         private void removeRefreshRateSetting(int displayId) {
+            mVotesStorage.updateVote(displayId, Vote.PRIORITY_USER_SETTING_PEAK_REFRESH_RATE,
+                    null);
             mVotesStorage.updateVote(displayId, Vote.PRIORITY_USER_SETTING_PEAK_RENDER_FRAME_RATE,
                     null);
             mVotesStorage.updateVote(displayId, Vote.PRIORITY_USER_SETTING_MIN_RENDER_FRAME_RATE,
@@ -1458,11 +1467,11 @@
         public void onDisplayAdded(int displayId) {
             updateDisplayDeviceConfig(displayId);
             DisplayInfo displayInfo = getDisplayInfo(displayId);
+            registerExternalDisplay(displayInfo);
             updateDisplayModes(displayId, displayInfo);
             updateLayoutLimitedFrameRate(displayId, displayInfo);
             updateUserSettingDisplayPreferredSize(displayInfo);
             updateDisplaysPeakRefreshRateAndResolution(displayInfo);
-            addDisplaysSynchronizedPeakRefreshRate(displayInfo);
         }
 
         @Override
@@ -1477,7 +1486,7 @@
             updateLayoutLimitedFrameRate(displayId, null);
             removeUserSettingDisplayPreferredSize(displayId);
             removeDisplaysPeakRefreshRateAndResolution(displayId);
-            removeDisplaysSynchronizedPeakRefreshRate(displayId);
+            unregisterExternalDisplay(displayId);
         }
 
         @Override
@@ -1489,6 +1498,30 @@
             updateUserSettingDisplayPreferredSize(displayInfo);
         }
 
+        private void registerExternalDisplay(DisplayInfo displayInfo) {
+            if (displayInfo == null || displayInfo.type != Display.TYPE_EXTERNAL) {
+                return;
+            }
+            synchronized (mLock) {
+                mExternalDisplaysConnected.add(displayInfo.displayId);
+                if (mExternalDisplaysConnected.size() == 1) {
+                    addDisplaysSynchronizedPeakRefreshRate();
+                }
+            }
+        }
+
+        private void unregisterExternalDisplay(int displayId) {
+            synchronized (mLock) {
+                if (!isExternalDisplayLocked(displayId)) {
+                    return;
+                }
+                mExternalDisplaysConnected.remove(displayId);
+                if (mExternalDisplaysConnected.isEmpty()) {
+                    removeDisplaysSynchronizedPeakRefreshRate();
+                }
+            }
+        }
+
         boolean isExternalDisplayLocked(int displayId) {
             return mExternalDisplaysConnected.contains(displayId);
         }
@@ -1534,10 +1567,24 @@
                 return;
             }
 
-            mVotesStorage.updateVote(info.displayId,
-                    Vote.PRIORITY_USER_SETTING_DISPLAY_PREFERRED_SIZE,
-                    Vote.forSize(/* width */ preferredMode.getPhysicalWidth(),
-                            /* height */ preferredMode.getPhysicalHeight()));
+            if (info.type == Display.TYPE_EXTERNAL
+                    && mDisplayManagerFlags.isUserRefreshRateForExternalDisplayEnabled()
+                    && !isRefreshRateSynchronizationEnabled()) {
+                mVotesStorage.updateVote(info.displayId,
+                        Vote.PRIORITY_USER_SETTING_DISPLAY_PREFERRED_SIZE,
+                        Vote.forSizeAndPhysicalRefreshRatesRange(
+                                /* minWidth */ preferredMode.getPhysicalWidth(),
+                                /* minHeight */ preferredMode.getPhysicalHeight(),
+                                /* width */ preferredMode.getPhysicalWidth(),
+                                /* height */ preferredMode.getPhysicalHeight(),
+                                /* minRefreshRate */ preferredMode.getRefreshRate(),
+                                /* maxRefreshRate */ preferredMode.getRefreshRate()));
+            } else {
+                mVotesStorage.updateVote(info.displayId,
+                        Vote.PRIORITY_USER_SETTING_DISPLAY_PREFERRED_SIZE,
+                        Vote.forSize(/* width */ preferredMode.getPhysicalWidth(),
+                                /* height */ preferredMode.getPhysicalHeight()));
+            }
         }
 
         @Nullable
@@ -1584,17 +1631,10 @@
          * Sets 60Hz target refresh rate as the vote with
          * {@link Vote#PRIORITY_SYNCHRONIZED_REFRESH_RATE} priority.
          */
-        private void addDisplaysSynchronizedPeakRefreshRate(@Nullable final DisplayInfo info) {
-            if (info == null || info.type != Display.TYPE_EXTERNAL
-                    || !isRefreshRateSynchronizationEnabled()) {
+        private void addDisplaysSynchronizedPeakRefreshRate() {
+            if (!isRefreshRateSynchronizationEnabled()) {
                 return;
             }
-            synchronized (mLock) {
-                mExternalDisplaysConnected.add(info.displayId);
-                if (mExternalDisplaysConnected.size() != 1) {
-                    return;
-                }
-            }
             // set minRefreshRate as the max refresh rate.
             mVotesStorage.updateGlobalVote(Vote.PRIORITY_SYNCHRONIZED_REFRESH_RATE,
                     Vote.forPhysicalRefreshRates(
@@ -1610,19 +1650,10 @@
                                     + SYNCHRONIZED_REFRESH_RATE_TOLERANCE));
         }
 
-        private void removeDisplaysSynchronizedPeakRefreshRate(final int displayId) {
+        private void removeDisplaysSynchronizedPeakRefreshRate() {
             if (!isRefreshRateSynchronizationEnabled()) {
                 return;
             }
-            synchronized (mLock) {
-                if (!isExternalDisplayLocked(displayId)) {
-                    return;
-                }
-                mExternalDisplaysConnected.remove(displayId);
-                if (!mExternalDisplaysConnected.isEmpty()) {
-                    return;
-                }
-            }
             mVotesStorage.updateGlobalVote(Vote.PRIORITY_SYNCHRONIZED_REFRESH_RATE, null);
             mVotesStorage.updateGlobalVote(Vote.PRIORITY_SYNCHRONIZED_RENDER_FRAME_RATE, null);
         }
diff --git a/services/core/java/com/android/server/display/mode/Vote.java b/services/core/java/com/android/server/display/mode/Vote.java
index 459f9a6..f5abb05 100644
--- a/services/core/java/com/android/server/display/mode/Vote.java
+++ b/services/core/java/com/android/server/display/mode/Vote.java
@@ -44,7 +44,7 @@
     // It votes [minRefreshRate, Float.POSITIVE_INFINITY]
     int PRIORITY_USER_SETTING_MIN_RENDER_FRAME_RATE = 3;
 
-    // User setting preferred display resolution.
+    // User setting preferred display resolution, for external displays also includes refresh rate.
     int PRIORITY_USER_SETTING_DISPLAY_PREFERRED_SIZE = 4;
 
     // APP_REQUEST_RENDER_FRAME_RATE_RANGE is used to for internal apps to limit the render
diff --git a/services/core/java/com/android/server/hdmi/Constants.java b/services/core/java/com/android/server/hdmi/Constants.java
index b78f8a7..0e7d2b6 100644
--- a/services/core/java/com/android/server/hdmi/Constants.java
+++ b/services/core/java/com/android/server/hdmi/Constants.java
@@ -509,6 +509,21 @@
     static final String PROPERTY_STRIP_AUDIO_TV_NO_SYSTEM_AUDIO =
         "persist.sys.hdmi.property_strip_audio_tv_no_system_audio";
 
+    /**
+     * Property that decides whether CEC should be disabled on standby when the low energy mode
+     * option is used.
+     */
+    static final String PROPERTY_WAS_CEC_DISABLED_ON_STANDBY_BY_LOW_ENERGY_MODE =
+            "persist.sys.hdmi.property_was_cec_disabled_on_standby_by_low_energy_mode";
+
+    /**
+     * Property that checks if CEC was disabled on standby by low energy mode. With the help of this
+     * property we avoid re-enabling CEC if the user explicitly disabled it, unrelated to the
+     * selected energy mode.
+     */
+    static final String PROPERTY_DISABLE_CEC_ON_STANDBY_IN_LOW_ENERGY_MODE =
+            "persist.sys.hdmi.property_disable_cec_on_standby_in_low_energy_mode";
+
     static final int RECORDING_TYPE_DIGITAL_RF = 1;
     static final int RECORDING_TYPE_ANALOGUE_RF = 2;
     static final int RECORDING_TYPE_EXTERNAL_PHYSICAL_ADDRESS = 3;
@@ -644,6 +659,11 @@
     })
     @interface FeatureFlag {}
 
+    /**
+     * Identifier key for Low energy mode.
+     */
+    static final String KEY_LOW_ENERGY_USE = "low_energy_use";
+
     private Constants() {
         /* cannot be instantiated */
     }
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index 8e41d18..81be0ba 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -22,6 +22,7 @@
 import static android.hardware.hdmi.HdmiControlManager.DEVICE_EVENT_REMOVE_DEVICE;
 import static android.hardware.hdmi.HdmiControlManager.EARC_FEATURE_DISABLED;
 import static android.hardware.hdmi.HdmiControlManager.EARC_FEATURE_ENABLED;
+import static android.hardware.hdmi.HdmiControlManager.HDMI_CEC_CONTROL_DISABLED;
 import static android.hardware.hdmi.HdmiControlManager.HDMI_CEC_CONTROL_ENABLED;
 import static android.hardware.hdmi.HdmiControlManager.POWER_CONTROL_MODE_NONE;
 import static android.hardware.hdmi.HdmiControlManager.SOUNDBAR_MODE_DISABLED;
@@ -478,7 +479,8 @@
     @Nullable
     private HdmiCecController mCecController;
 
-    private HdmiCecPowerStatusController mPowerStatusController;
+    @VisibleForTesting
+    protected HdmiCecPowerStatusController mPowerStatusController;
 
     @Nullable
     private HdmiEarcController mEarcController;
@@ -3814,7 +3816,32 @@
         mPowerStatusController.setPowerStatus(HdmiControlManager.POWER_STATUS_TRANSIENT_TO_ON,
                 false);
         if (mCecController != null) {
-            if (isCecControlEnabled()) {
+            if (isTvDevice() && getWasCecDisabledOnStandbyByLowEnergyMode()) {
+                Slog.w(TAG, "Re-enable CEC on wake-up since it was disabled due to low energy "
+                        + " mode.");
+                getHdmiCecConfig().setIntValue(HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED,
+                        HDMI_CEC_CONTROL_ENABLED);
+                setWasCecDisabledOnStandbyByLowEnergyMode(false);
+                int controlStateChangedReason = -1;
+                switch (wakeUpAction) {
+                    case WAKE_UP_SCREEN_ON:
+                        controlStateChangedReason =
+                                HdmiControlManager.CONTROL_STATE_CHANGED_REASON_WAKEUP;
+                        break;
+                    case WAKE_UP_BOOT_UP:
+                        controlStateChangedReason =
+                                HdmiControlManager.CONTROL_STATE_CHANGED_REASON_START;
+                        break;
+                    default:
+                        Slog.e(TAG, "wakeUpAction " + wakeUpAction + " not defined.");
+                        return;
+
+                }
+                // Since CEC is going to be initialized by the setting value update, we must invoke
+                // the vendor command listeners here with the reason TV woke up.
+                invokeVendorCommandListenersOnControlStateChanged(true,
+                        controlStateChangedReason);
+            } else if (isCecControlEnabled()) {
                 int startReason = -1;
                 switch (wakeUpAction) {
                     case WAKE_UP_SCREEN_ON:
@@ -3988,6 +4015,14 @@
                 if (isAudioSystemDevice() || !isPowerStandby()) {
                     return;
                 }
+                if (isTvDevice() && getDisableCecOnStandbyByLowEnergyMode()
+                        && mPowerManager.isLowPowerStandbyEnabled()) {
+                    Slog.w(TAG, "Disable CEC on standby due to low power energy mode.");
+                    setWasCecDisabledOnStandbyByLowEnergyMode(true);
+                    getHdmiCecConfig().setIntValue(
+                            HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED,
+                            HDMI_CEC_CONTROL_DISABLED);
+                }
                 mCecController.enableSystemCecControl(false);
                 mMhlController.setOption(OPTION_MHL_SERVICE_CONTROL, DISABLED);
             }
@@ -5148,4 +5183,34 @@
     protected boolean isHdmiControlEnhancedBehaviorFlagEnabled() {
         return hdmiControlEnhancedBehavior();
     }
+
+    /**
+     * Reads the property value that decides whether CEC should be disabled on standby when the low
+     * energy mode option is used.
+     */
+    @VisibleForTesting
+    protected boolean getDisableCecOnStandbyByLowEnergyMode() {
+        return SystemProperties.getBoolean(
+                Constants.PROPERTY_DISABLE_CEC_ON_STANDBY_IN_LOW_ENERGY_MODE, false);
+    }
+
+    /**
+     * Reads the property that checks if CEC was disabled on standby by low energy mode.
+     */
+    @VisibleForTesting
+    protected boolean getWasCecDisabledOnStandbyByLowEnergyMode() {
+        return SystemProperties.getBoolean(
+                Constants.PROPERTY_WAS_CEC_DISABLED_ON_STANDBY_BY_LOW_ENERGY_MODE, false);
+    }
+
+    /**
+     * Sets the truth value of the property that checks if CEC was disabled on standby by low energy
+     * mode.
+     */
+    @VisibleForTesting
+    protected void setWasCecDisabledOnStandbyByLowEnergyMode(boolean value) {
+        writeStringSystemProperty(
+                Constants.PROPERTY_WAS_CEC_DISABLED_ON_STANDBY_BY_LOW_ENERGY_MODE,
+                String.valueOf(value));
+    }
 }
diff --git a/services/core/java/com/android/server/hdmi/PowerManagerWrapper.java b/services/core/java/com/android/server/hdmi/PowerManagerWrapper.java
index 7530b3b..5292cbb 100644
--- a/services/core/java/com/android/server/hdmi/PowerManagerWrapper.java
+++ b/services/core/java/com/android/server/hdmi/PowerManagerWrapper.java
@@ -16,6 +16,8 @@
 
 package com.android.server.hdmi;
 
+import static com.android.server.hdmi.Constants.KEY_LOW_ENERGY_USE;
+
 import android.content.Context;
 import android.os.PowerManager;
 
@@ -47,6 +49,12 @@
         return new DefaultWakeLockWrapper(mPowerManager.newWakeLock(levelAndFlags, tag));
     }
 
+    boolean isLowPowerStandbyEnabled() {
+        PowerManager.LowPowerStandbyPolicy lowPowerStandbyPolicy
+                = mPowerManager.getLowPowerStandbyPolicy();
+        return lowPowerStandbyPolicy.getIdentifier().equals(KEY_LOW_ENERGY_USE);
+    }
+
     /**
      * "Default" wrapper for {@link PowerManager.WakeLock}, as opposed to a "Fake" wrapper for
      * testing - see {@link FakePowerManagerWrapper.FakeWakeLockWrapper}.
diff --git a/services/core/java/com/android/server/input/InputSettingsObserver.java b/services/core/java/com/android/server/input/InputSettingsObserver.java
index d70bd8b..d1a6d3b 100644
--- a/services/core/java/com/android/server/input/InputSettingsObserver.java
+++ b/services/core/java/com/android/server/input/InputSettingsObserver.java
@@ -63,6 +63,12 @@
         mObservers = Map.ofEntries(
                 Map.entry(Settings.System.getUriFor(Settings.System.POINTER_SPEED),
                         (reason) -> updateMousePointerSpeed()),
+                Map.entry(Settings.System.getUriFor(
+                        Settings.System.MOUSE_REVERSE_VERTICAL_SCROLLING),
+                        (reason) -> updateMouseReverseVerticalScrolling()),
+                Map.entry(Settings.System.getUriFor(
+                                Settings.System.MOUSE_SWAP_PRIMARY_BUTTON),
+                        (reason) -> updateMouseSwapPrimaryButton()),
                 Map.entry(Settings.System.getUriFor(Settings.System.TOUCHPAD_POINTER_SPEED),
                         (reason) -> updateTouchpadPointerSpeed()),
                 Map.entry(Settings.System.getUriFor(Settings.System.TOUCHPAD_NATURAL_SCROLLING),
@@ -163,6 +169,16 @@
         mNative.setPointerSpeed(constrainPointerSpeedValue(speed));
     }
 
+    private void updateMouseReverseVerticalScrolling() {
+        mNative.setMouseReverseVerticalScrollingEnabled(
+                InputSettings.isMouseReverseVerticalScrollingEnabled(mContext));
+    }
+
+    private void updateMouseSwapPrimaryButton() {
+        mNative.setMouseSwapPrimaryButtonEnabled(
+                InputSettings.isMouseSwapPrimaryButtonEnabled(mContext));
+    }
+
     private void updateTouchpadPointerSpeed() {
         mNative.setTouchpadPointerSpeed(
                 constrainPointerSpeedValue(InputSettings.getTouchpadPointerSpeed(mContext)));
diff --git a/services/core/java/com/android/server/input/NativeInputManagerService.java b/services/core/java/com/android/server/input/NativeInputManagerService.java
index 4404d63..21e8bcc 100644
--- a/services/core/java/com/android/server/input/NativeInputManagerService.java
+++ b/services/core/java/com/android/server/input/NativeInputManagerService.java
@@ -127,6 +127,10 @@
 
     void setMousePointerAccelerationEnabled(int displayId, boolean enabled);
 
+    void setMouseReverseVerticalScrollingEnabled(boolean enabled);
+
+    void setMouseSwapPrimaryButtonEnabled(boolean enabled);
+
     void setTouchpadPointerSpeed(int speed);
 
     void setTouchpadNaturalScrollingEnabled(boolean enabled);
@@ -388,6 +392,12 @@
         public native void setMousePointerAccelerationEnabled(int displayId, boolean enabled);
 
         @Override
+        public native void setMouseReverseVerticalScrollingEnabled(boolean enabled);
+
+        @Override
+        public native void setMouseSwapPrimaryButtonEnabled(boolean enabled);
+
+        @Override
         public native void setTouchpadPointerSpeed(int speed);
 
         @Override
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index f0fb33e..939aad4 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -84,6 +84,7 @@
 import android.content.pm.ServiceInfo;
 import android.content.pm.UserInfo;
 import android.content.res.Resources;
+import android.hardware.display.DisplayManagerInternal;
 import android.hardware.input.InputManager;
 import android.inputmethodservice.InputMethodService;
 import android.inputmethodservice.InputMethodService.BackDispositionMode;
@@ -119,6 +120,7 @@
 import android.util.Slog;
 import android.util.SparseArray;
 import android.util.proto.ProtoOutputStream;
+import android.view.Display;
 import android.view.InputChannel;
 import android.view.InputDevice;
 import android.view.MotionEvent;
@@ -185,7 +187,6 @@
 import com.android.server.companion.virtual.VirtualDeviceManagerInternal;
 import com.android.server.input.InputManagerInternal;
 import com.android.server.inputmethod.InputMethodManagerInternal.InputMethodListListener;
-import com.android.server.inputmethod.InputMethodMenuControllerNew.MenuItem;
 import com.android.server.inputmethod.InputMethodSubtypeSwitchingController.ImeSubtypeListItem;
 import com.android.server.pm.UserManagerInternal;
 import com.android.server.statusbar.StatusBarManagerInternal;
@@ -448,6 +449,8 @@
     private AudioManagerInternal mAudioManagerInternal = null;
     @Nullable
     private VirtualDeviceManagerInternal mVdmInternal = null;
+    @Nullable
+    private DisplayManagerInternal mDisplayManagerInternal = null;
 
     // Mapping from deviceId to the device-specific imeId for that device.
     @GuardedBy("ImfLock.class")
@@ -2165,7 +2168,18 @@
         final var bindingController = getInputMethodBindingController(userId);
         final int oldDeviceId = bindingController.getDeviceIdToShowIme();
         final int displayIdToShowIme = bindingController.getDisplayIdToShowIme();
-        final int newDeviceId = mVdmInternal.getDeviceIdForDisplayId(displayIdToShowIme);
+        int newDeviceId = mVdmInternal.getDeviceIdForDisplayId(displayIdToShowIme);
+        if (newDeviceId != DEVICE_ID_DEFAULT) {
+            // Only show custom IME on trusted displays.
+            if (mDisplayManagerInternal == null) {
+                mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class);
+            }
+            int displayFlags = mDisplayManagerInternal.getDisplayInfo(displayIdToShowIme).flags;
+            if ((displayFlags & Display.FLAG_TRUSTED) != Display.FLAG_TRUSTED) {
+                // If the display is not trusted, fallback to the default device IME.
+                newDeviceId = DEVICE_ID_DEFAULT;
+            }
+        }
         bindingController.setDeviceIdToShowIme(newDeviceId);
         if (newDeviceId == DEVICE_ID_DEFAULT) {
             if (oldDeviceId == DEVICE_ID_DEFAULT) {
@@ -4063,65 +4077,6 @@
         }
     }
 
-    /**
-     * Gets the list of Input Method Switcher Menu items and the index of the selected item.
-     *
-     * @param items                the list of input method and subtype items.
-     * @param selectedImeId        the ID of the selected input method.
-     * @param selectedSubtypeIndex the index of the selected subtype in the input method's array of
-     *                             subtypes, or {@link InputMethodUtils#NOT_A_SUBTYPE_INDEX} if no
-     *                             subtype is selected.
-     * @param userId               the ID of the user for which to get the menu items.
-     * @return the list of menu items, and the index of the selected item,
-     * or {@code -1} if no item is selected.
-     */
-    @GuardedBy("ImfLock.class")
-    @NonNull
-    private Pair<List<MenuItem>, Integer> getInputMethodPickerItems(
-            @NonNull List<ImeSubtypeListItem> items, @Nullable String selectedImeId,
-            int selectedSubtypeIndex, @UserIdInt int userId) {
-        final var bindingController = getInputMethodBindingController(userId);
-        final var settings = InputMethodSettingsRepository.get(userId);
-
-        if (selectedSubtypeIndex == NOT_A_SUBTYPE_INDEX) {
-            // TODO(b/351124299): Check if this fallback logic is still necessary.
-            final var curSubtype = bindingController.getCurrentInputMethodSubtype();
-            if (curSubtype != null) {
-                final var curMethodId = bindingController.getSelectedMethodId();
-                final var curImi = settings.getMethodMap().get(curMethodId);
-                selectedSubtypeIndex = SubtypeUtils.getSubtypeIndexFromHashCode(
-                        curImi, curSubtype.hashCode());
-            }
-        }
-
-        // No item is selected by default. When we have a list of explicitly enabled
-        // subtypes, the implicit subtype is no longer listed. If the implicit one
-        // is still selected, no items will be shown as selected.
-        int selectedIndex = -1;
-        String prevImeId = null;
-        final var menuItems = new ArrayList<MenuItem>();
-        for (int i = 0; i < items.size(); i++) {
-            final var item = items.get(i);
-            final var imeId = item.mImi.getId();
-            if (imeId.equals(selectedImeId)) {
-                final int subtypeIndex = item.mSubtypeIndex;
-                // Check if this is the selected IME-subtype pair.
-                if ((subtypeIndex == 0 && selectedSubtypeIndex == NOT_A_SUBTYPE_INDEX)
-                        || subtypeIndex == NOT_A_SUBTYPE_INDEX
-                        || subtypeIndex == selectedSubtypeIndex) {
-                    selectedIndex = i;
-                }
-            }
-            final boolean hasHeader = !imeId.equals(prevImeId);
-            final boolean hasDivider = hasHeader && prevImeId != null;
-            prevImeId = imeId;
-            menuItems.add(new MenuItem(item.mImeName, item.mSubtypeName, item.mImi,
-                    item.mSubtypeIndex, hasHeader, hasDivider));
-        }
-
-        return new Pair<>(menuItems, selectedIndex);
-    }
-
     @IInputMethodManagerImpl.PermissionVerified(allOf = {
             Manifest.permission.INTERACT_ACROSS_USERS_FULL,
             Manifest.permission.WRITE_SECURE_SETTINGS})
@@ -4958,18 +4913,21 @@
                         + " preferredInputMethodSubtypeIndex=" + lastInputMethodSubtypeIndex);
             }
 
-            final var itemsAndIndex = getInputMethodPickerItems(imList,
-                    lastInputMethodId, lastInputMethodSubtypeIndex, userId);
-            final var menuItems = itemsAndIndex.first;
-            final int selectedIndex = itemsAndIndex.second;
-
-            if (selectedIndex == -1) {
-                Slog.w(TAG, "Switching menu shown with no item selected"
-                        + ", IME id: " + lastInputMethodId
-                        + ", subtype index: " + lastInputMethodSubtypeIndex);
+            int selectedSubtypeIndex = lastInputMethodSubtypeIndex;
+            if (selectedSubtypeIndex == NOT_A_SUBTYPE_INDEX) {
+                // TODO(b/351124299): Check if this fallback logic is still necessary.
+                final var bindingController = getInputMethodBindingController(userId);
+                final var curSubtype = bindingController.getCurrentInputMethodSubtype();
+                if (curSubtype != null) {
+                    final var curMethodId = bindingController.getSelectedMethodId();
+                    final var curImi = settings.getMethodMap().get(curMethodId);
+                    selectedSubtypeIndex = SubtypeUtils.getSubtypeIndexFromHashCode(
+                            curImi, curSubtype.hashCode());
+                }
             }
 
-            mMenuControllerNew.show(menuItems, selectedIndex, displayId, userId);
+            mMenuControllerNew.show(imList, lastInputMethodId, selectedSubtypeIndex, displayId,
+                    userId);
         } else {
             mMenuController.showInputMethodMenuLocked(showAuxSubtypes, displayId,
                     lastInputMethodId, lastInputMethodSubtypeIndex, imList, userId);
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodMenuControllerNew.java b/services/core/java/com/android/server/inputmethod/InputMethodMenuControllerNew.java
index cf2cdc1..1d0e3c6 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodMenuControllerNew.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodMenuControllerNew.java
@@ -30,7 +30,6 @@
 import android.annotation.UserIdInt;
 import android.app.AlertDialog;
 import android.content.Context;
-import android.content.DialogInterface;
 import android.content.Intent;
 import android.os.UserHandle;
 import android.provider.Settings;
@@ -48,8 +47,11 @@
 import android.widget.ImageView;
 import android.widget.TextView;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.widget.RecyclerView;
+import com.android.server.inputmethod.InputMethodSubtypeSwitchingController.ImeSubtypeListItem;
 
+import java.util.ArrayList;
 import java.util.List;
 
 /**
@@ -80,18 +82,27 @@
     /**
      * Shows the Input Method Switcher Menu, with a list of IMEs and their subtypes.
      *
-     * @param items         the list of menu items.
-     * @param selectedIndex the index of the menu item that is selected.
-     *                      If no other IMEs are enabled, this index will be out of reach.
-     * @param displayId     the ID of the display where the menu was requested.
-     * @param userId        the ID of the user that requested the menu.
+     * @param items                the list of input method and subtype items.
+     * @param selectedImeId        the ID of the selected input method.
+     * @param selectedSubtypeIndex the index of the selected subtype in the input method's array of
+     *                             subtypes, or {@link InputMethodUtils#NOT_A_SUBTYPE_INDEX} if no
+     *                             subtype is selected.
+     * @param displayId            the ID of the display where the menu was requested.
+     * @param userId               the ID of the user that requested the menu.
      */
     @RequiresPermission(allOf = {INTERACT_ACROSS_USERS, HIDE_OVERLAY_WINDOWS})
-    void show(@NonNull List<MenuItem> items, int selectedIndex, int displayId,
-            @UserIdInt int userId) {
+    void show(@NonNull List<ImeSubtypeListItem> items, @Nullable String selectedImeId,
+            int selectedSubtypeIndex, int displayId, @UserIdInt int userId) {
         // Hide the menu in case it was already showing.
         hide(displayId, userId);
 
+        final var menuItems = getMenuItems(items);
+        final int selectedIndex = getSelectedIndex(menuItems, selectedImeId, selectedSubtypeIndex);
+        if (selectedIndex == -1) {
+            Slog.w(TAG, "Switching menu shown with no item selected, IME id: " + selectedImeId
+                    + ", subtype index: " + selectedSubtypeIndex);
+        }
+
         final Context dialogWindowContext = mDialogWindowContext.get(displayId);
         final var builder = new AlertDialog.Builder(dialogWindowContext,
                 com.android.internal.R.style.Theme_DeviceDefault_InputMethodSwitcherDialog);
@@ -104,52 +115,28 @@
                 dialogWindowContext.getText(com.android.internal.R.string.select_input_method));
         builder.setView(contentView);
 
-        final DialogInterface.OnClickListener onClickListener = (dialog, which) -> {
-            if (which != selectedIndex) {
-                final var item = items.get(which);
+        final OnClickListener onClickListener = (item, isSelected) -> {
+            if (!isSelected) {
                 InputMethodManagerInternal.get()
                         .switchToInputMethod(item.mImi.getId(), item.mSubtypeIndex, userId);
             }
             hide(displayId, userId);
         };
 
-        final var selectedImi = selectedIndex >= 0 ? items.get(selectedIndex).mImi : null;
-        final var languageSettingsIntent = selectedImi != null
-                ? selectedImi.createImeLanguageSettingsActivityIntent() : null;
-        final boolean isDeviceProvisioned = Settings.Global.getInt(
-                dialogWindowContext.getContentResolver(), Settings.Global.DEVICE_PROVISIONED,
-                0) != 0;
-        final boolean hasLanguageSettingsButton = languageSettingsIntent != null
-                && isDeviceProvisioned;
-        if (hasLanguageSettingsButton) {
-            final View buttonBar = contentView
-                    .requireViewById(com.android.internal.R.id.button_bar);
-            buttonBar.setVisibility(View.VISIBLE);
-
-            languageSettingsIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-            final Button languageSettingsButton = contentView
-                    .requireViewById(com.android.internal.R.id.button1);
-            languageSettingsButton.setVisibility(View.VISIBLE);
-            languageSettingsButton.setOnClickListener(v -> {
-                v.getContext().startActivityAsUser(languageSettingsIntent, UserHandle.of(userId));
-                hide(displayId, userId);
-            });
-        }
-
         // Create the current IME subtypes list.
         final RecyclerView recyclerView = contentView
                 .requireViewById(com.android.internal.R.id.list);
-        recyclerView.setAdapter(new Adapter(items, selectedIndex, inflater, onClickListener));
+        recyclerView.setAdapter(new Adapter(menuItems, selectedIndex, inflater, onClickListener));
         // Scroll to the currently selected IME. This must run after the recycler view is laid out.
         recyclerView.post(() -> recyclerView.scrollToPosition(selectedIndex));
-        // Indicate that the list can be scrolled.
-        recyclerView.setScrollIndicators(
-                hasLanguageSettingsButton ? View.SCROLL_INDICATOR_BOTTOM : 0);
         // Request focus to enable rotary scrolling on watches.
         recyclerView.requestFocus();
 
+        final var selectedItem = selectedIndex > -1 ? menuItems.get(selectedIndex) : null;
+        updateLanguageSettingsButton(selectedItem, contentView, displayId, userId);
+
         builder.setOnCancelListener(dialog -> hide(displayId, userId));
-        mMenuItems = items;
+        mMenuItems = menuItems;
         mDialog = builder.create();
         mDialog.setCanceledOnTouchOutside(true);
         final Window w = mDialog.getWindow();
@@ -208,98 +195,303 @@
     }
 
     /**
-     * Item to be shown in the Input Method Switcher Menu, containing an input method and
-     * optionally an input method subtype.
+     * Creates the list of menu items from the given list of input methods and subtypes. This
+     * handles adding headers and dividers between groups of items from different input methods
+     * as follows:
+     *
+     * <li>If there is only one group, no divider or header will be added.</li>
+     * <li>A divider is added before each group, except the first one.</li>
+     * <li>A header is added before each group (after the divider, if it exists) if the group has
+     * at least two items, or a single item with a subtype name.</li>
+     *
+     * @param items the list of input method and subtype items.
      */
-    static class MenuItem {
+    @VisibleForTesting
+    @NonNull
+    static List<MenuItem> getMenuItems(@NonNull List<ImeSubtypeListItem> items) {
+        final var menuItems = new ArrayList<MenuItem>();
+        if (items.isEmpty()) {
+            return menuItems;
+        }
+
+        final var itemsArray = (ArrayList<ImeSubtypeListItem>) items;
+        final int numItems = itemsArray.size();
+        // Initialize to the last IME id to avoid headers if there is only a single IME.
+        String prevImeId = itemsArray.getLast().mImi.getId();
+        boolean firstGroup = true;
+        for (int i = 0; i < numItems; i++) {
+            final var item = itemsArray.get(i);
+
+            final var imeId = item.mImi.getId();
+            final boolean groupChange = !imeId.equals(prevImeId);
+            if (groupChange) {
+                if (!firstGroup) {
+                    menuItems.add(DividerItem.getInstance());
+                }
+                // Add a header if we have at least two items, or a single item with a subtype name.
+                final var nextItemId = i + 1 < numItems ? itemsArray.get(i + 1).mImi.getId() : null;
+                final boolean addHeader = item.mSubtypeName != null || imeId.equals(nextItemId);
+                if (addHeader) {
+                    menuItems.add(new HeaderItem(item.mImeName));
+                }
+                firstGroup = false;
+                prevImeId = imeId;
+            }
+
+            menuItems.add(new SubtypeItem(item.mImeName, item.mSubtypeName, item.mImi,
+                    item.mSubtypeIndex));
+        }
+
+        return menuItems;
+    }
+
+    /**
+     * Gets the index of the selected item.
+     *
+     * @param items                the list of menu items.
+     * @param selectedImeId        the ID of the selected input method.
+     * @param selectedSubtypeIndex the index of the selected subtype in the input method's array of
+     *                             subtypes, or {@link InputMethodUtils#NOT_A_SUBTYPE_INDEX} if no
+     *                             subtype is selected.
+     * @return the index of the selected item, or {@code -1} if no item is selected.
+     */
+    @VisibleForTesting
+    @IntRange(from = -1)
+    static int getSelectedIndex(@NonNull List<MenuItem> items, @Nullable String selectedImeId,
+            int selectedSubtypeIndex) {
+        for (int i = 0; i < items.size(); i++) {
+            final var item = items.get(i);
+            if (item instanceof SubtypeItem subtypeItem) {
+                final var imeId = subtypeItem.mImi.getId();
+                final int subtypeIndex = subtypeItem.mSubtypeIndex;
+                if (imeId.equals(selectedImeId)
+                        && ((subtypeIndex == 0 && selectedSubtypeIndex == NOT_A_SUBTYPE_INDEX)
+                            || subtypeIndex == NOT_A_SUBTYPE_INDEX
+                            || subtypeIndex == selectedSubtypeIndex)) {
+                    return i;
+                }
+            }
+        }
+        // Either there is no selected IME, or the selected subtype is enabled but not in the list.
+        // This can happen if an implicit subtype is selected, but we got a list of explicit
+        // subtypes. In this case, the implicit subtype will no longer be included in the list.
+        return -1;
+    }
+
+    /**
+     * Updates the visibility of the Language Settings button to visible if the currently selected
+     * item specifies a (language) settings activity and the device is provisioned. Otherwise,
+     * the button won't be shown.
+     *
+     * @param selectedItem the currently selected item, or {@code null} if no item is selected.
+     * @param view         the menu dialog view.
+     * @param displayId    the ID of the display where the menu was requested.
+     * @param userId       the ID of the user that requested the menu.
+     */
+    @RequiresPermission(allOf = {INTERACT_ACROSS_USERS})
+    private void updateLanguageSettingsButton(@Nullable MenuItem selectedItem, @NonNull View view,
+            int displayId, @UserIdInt int userId) {
+        final var settingsIntent = (selectedItem instanceof SubtypeItem selectedSubtypeItem)
+                ? selectedSubtypeItem.mImi.createImeLanguageSettingsActivityIntent() : null;
+        final boolean isDeviceProvisioned = Settings.Global.getInt(
+                view.getContext().getContentResolver(), Settings.Global.DEVICE_PROVISIONED,
+                0) != 0;
+        final boolean hasButton = settingsIntent != null && isDeviceProvisioned;
+        final View buttonBar = view.requireViewById(com.android.internal.R.id.button_bar);
+        final Button button = view.requireViewById(com.android.internal.R.id.button1);
+        final RecyclerView recyclerView = view.requireViewById(com.android.internal.R.id.list);
+        if (hasButton) {
+            settingsIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+            buttonBar.setVisibility(View.VISIBLE);
+            button.setOnClickListener(v -> {
+                v.getContext().startActivityAsUser(settingsIntent, UserHandle.of(userId));
+                hide(displayId, userId);
+            });
+            // Indicate that the list can be scrolled.
+            recyclerView.setScrollIndicators(View.SCROLL_INDICATOR_BOTTOM);
+        } else {
+            buttonBar.setVisibility(View.GONE);
+            button.setOnClickListener(null);
+            // Remove scroll indicator as there is nothing drawn below the list.
+            recyclerView.setScrollIndicators(0 /* indicators */);
+        }
+    }
+
+    /**
+     * Interface definition for callbacks to be invoked when a {@link SubtypeItem} is clicked.
+     */
+    private interface OnClickListener {
+
+        /**
+         * Called when an item is clicked.
+         *
+         * @param item       The item that was clicked.
+         * @param isSelected Whether the item is the currently selected one.
+         */
+        void onClick(@NonNull SubtypeItem item, boolean isSelected);
+    }
+
+    /** Item to be displayed in the menu. */
+    sealed interface MenuItem {}
+
+    /** Subtype item containing an input method and optionally an input method subtype. */
+    static final class SubtypeItem implements MenuItem {
 
         /** The name of the input method. */
         @NonNull
-        private final CharSequence mImeName;
+        final CharSequence mImeName;
 
         /**
          * The name of the input method subtype, or {@code null} if this item doesn't have a
          * subtype.
          */
         @Nullable
-        private final CharSequence mSubtypeName;
+        final CharSequence mSubtypeName;
 
         /** The info of the input method. */
         @NonNull
-        private final InputMethodInfo mImi;
+        final InputMethodInfo mImi;
 
         /**
          * The index of the subtype in the input method's array of subtypes,
          * or {@link InputMethodUtils#NOT_A_SUBTYPE_INDEX} if this item doesn't have a subtype.
          */
         @IntRange(from = NOT_A_SUBTYPE_INDEX)
-        private final int mSubtypeIndex;
+        final int mSubtypeIndex;
 
-        /** Whether this item has a group header (only the first item of each input method). */
-        private final boolean mHasHeader;
-
-        /**
-         * Whether this item should has a group divider (same as {@link #mHasHeader},
-         * excluding the first IME).
-         */
-        private final boolean mHasDivider;
-
-        MenuItem(@NonNull CharSequence imeName, @Nullable CharSequence subtypeName,
+        SubtypeItem(@NonNull CharSequence imeName, @Nullable CharSequence subtypeName,
                 @NonNull InputMethodInfo imi,
-                @IntRange(from = NOT_A_SUBTYPE_INDEX) int subtypeIndex, boolean hasHeader,
-                boolean hasDivider) {
+                @IntRange(from = NOT_A_SUBTYPE_INDEX) int subtypeIndex) {
             mImeName = imeName;
             mSubtypeName = subtypeName;
             mImi = imi;
             mSubtypeIndex = subtypeIndex;
-            mHasHeader = hasHeader;
-            mHasDivider = hasDivider;
         }
 
         @Override
         public String toString() {
-            return "MenuItem{"
+            return "SubtypeItem{"
                     + "mImeName=" + mImeName
                     + " mSubtypeName=" + mSubtypeName
                     + " mSubtypeIndex=" + mSubtypeIndex
-                    + " mHasHeader=" + mHasHeader
-                    + " mHasDivider=" + mHasDivider
                     + "}";
         }
     }
 
-    private static class Adapter extends RecyclerView.Adapter<Adapter.ViewHolder> {
+    /** Header item displayed before a group of {@link SubtypeItem} of the same input method. */
+    static final class HeaderItem implements MenuItem {
+
+        /** The header title. */
+        @NonNull
+        final CharSequence mTitle;
+
+        HeaderItem(@NonNull CharSequence title) {
+            mTitle = title;
+        }
+
+        @Override
+        public String toString() {
+            return "HeaderItem{"
+                    + "mTitle=" + mTitle
+                    + "}";
+        }
+    }
+
+    /** Divider item displayed before a {@link HeaderItem}. */
+    static final class DividerItem implements MenuItem {
+
+        private static DividerItem sInstance;
+
+        /** Gets a singleton instance of DividerItem. */
+        @NonNull
+        static DividerItem getInstance() {
+            if (sInstance == null) {
+                sInstance = new DividerItem();
+            }
+            return sInstance;
+        }
+
+        @Override
+        public String toString() {
+            return "DividerItem{}";
+        }
+    }
+
+    private static final class Adapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
+
+        /** View type for unknown item. */
+        private static final int TYPE_UNKNOWN = -1;
+
+        /** View type for {@link SubtypeItem}. */
+        private static final int TYPE_SUBTYPE = 0;
+
+        /** View type for {@link HeaderItem}. */
+        private static final int TYPE_HEADER = 1;
+
+        /** View type for {@link DividerItem}. */
+        private static final int TYPE_DIVIDER = 2;
 
         /** The list of items to show. */
         @NonNull
         private final List<MenuItem> mItems;
         /** The index of the selected item. */
+        @IntRange(from = -1)
         private final int mSelectedIndex;
         @NonNull
         private final LayoutInflater mInflater;
+        /** The listener used to handle clicks on {@link SubtypeViewHolder} items. */
         @NonNull
-        private final DialogInterface.OnClickListener mOnClickListener;
+        private final OnClickListener mListener;
 
-        Adapter(@NonNull List<MenuItem> items, int selectedIndex,
+        Adapter(@NonNull List<MenuItem> items, @IntRange(from = -1) int selectedIndex,
                 @NonNull LayoutInflater inflater,
-                @NonNull DialogInterface.OnClickListener onClickListener) {
+                @NonNull OnClickListener listener) {
             mItems = items;
             mSelectedIndex = selectedIndex;
             mInflater = inflater;
-            mOnClickListener = onClickListener;
+            mListener = listener;
         }
 
         @Override
-        public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
-            final View view = mInflater.inflate(
-                    com.android.internal.R.layout.input_method_switch_item_new, parent, false);
-
-            return new ViewHolder(view, mOnClickListener);
+        public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+            switch (viewType) {
+                case TYPE_SUBTYPE -> {
+                    final View view = mInflater.inflate(
+                            com.android.internal.R.layout.input_method_switch_item_new, parent,
+                            false);
+                    return new SubtypeViewHolder(view, mListener);
+                }
+                case TYPE_HEADER -> {
+                    final View view = mInflater.inflate(
+                            com.android.internal.R.layout.input_method_switch_item_header, parent,
+                            false);
+                    return new HeaderViewHolder(view);
+                }
+                case TYPE_DIVIDER -> {
+                    final View view = mInflater.inflate(
+                            com.android.internal.R.layout.input_method_switch_item_divider, parent,
+                            false);
+                    return new DividerViewHolder(view);
+                }
+                default -> throw new IllegalArgumentException("Unknown viewType: " + viewType);
+            }
         }
 
         @Override
-        public void onBindViewHolder(ViewHolder holder, int position) {
-            holder.bind(mItems.get(position), position == mSelectedIndex /* isSelected */);
+        public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
+            final var item = mItems.get(position);
+            if (holder instanceof SubtypeViewHolder subtypeHolder
+                    && item instanceof SubtypeItem subtypeItem) {
+                subtypeHolder.bind(subtypeItem, position == mSelectedIndex /* isSelected */);
+            } else if (holder instanceof HeaderViewHolder headerHolder
+                    && item instanceof HeaderItem headerItem) {
+                headerHolder.bind(headerItem);
+            } else if (holder instanceof DividerViewHolder && item instanceof DividerItem) {
+                // Nothing to bind for dividers.
+                return;
+            } else {
+                Slog.w(TAG, "Holder type: " + holder + " doesn't match item type: " + item);
+            }
         }
 
         @Override
@@ -307,7 +499,21 @@
             return mItems.size();
         }
 
-        private static class ViewHolder extends RecyclerView.ViewHolder {
+        @Override
+        public int getItemViewType(int position) {
+            final var item = mItems.get(position);
+            if (item instanceof SubtypeItem) {
+                return TYPE_SUBTYPE;
+            } else if (item instanceof HeaderItem) {
+                return TYPE_HEADER;
+            } else if (item instanceof DividerItem) {
+                return TYPE_DIVIDER;
+            } else {
+                return TYPE_UNKNOWN;
+            }
+        }
+
+        private static final class SubtypeViewHolder extends RecyclerView.ViewHolder {
 
             /** The container of the item. */
             @NonNull
@@ -318,46 +524,74 @@
             /** Indicator for the selected status of the item. */
             @NonNull
             private final ImageView mCheckmark;
-            /** The group header optionally drawn above the item. */
-            @NonNull
-            private final TextView mHeader;
-            /** The group divider optionally drawn above the item. */
-            @NonNull
-            private final View mDivider;
 
-            private ViewHolder(@NonNull View itemView,
-                    @NonNull DialogInterface.OnClickListener onClickListener) {
+            /** The bound item data, or {@code null} if no item was bound yet. */
+            @Nullable
+            private SubtypeItem mItem;
+            /** Whether this item is the currently selected one. */
+            private boolean mIsSelected;
+
+            SubtypeViewHolder(@NonNull View itemView, @NonNull OnClickListener listener) {
                 super(itemView);
 
-                mContainer = itemView.requireViewById(com.android.internal.R.id.list_item);
+                mContainer = itemView;
                 mName = itemView.requireViewById(com.android.internal.R.id.text);
                 mCheckmark = itemView.requireViewById(com.android.internal.R.id.image);
-                mHeader = itemView.requireViewById(com.android.internal.R.id.header_text);
-                mDivider = itemView.requireViewById(com.android.internal.R.id.divider);
 
-                mContainer.setOnClickListener((v) ->
-                        onClickListener.onClick(null /* dialog */, getAdapterPosition()));
+                mContainer.setOnClickListener((v) -> {
+                    if (mItem != null) {
+                        listener.onClick(mItem, mIsSelected);
+                    }
+                });
             }
 
             /**
              * Binds the given item to the current view.
              *
              * @param item       the item to bind.
-             * @param isSelected whether this is selected.
+             * @param isSelected whether the item is selected.
              */
-            private void bind(@NonNull MenuItem item, boolean isSelected) {
+            void bind(@NonNull SubtypeItem item, boolean isSelected) {
+                mItem = item;
+                mIsSelected = isSelected;
                 // Use the IME name for subtypes with an empty subtype name.
                 final var name = TextUtils.isEmpty(item.mSubtypeName)
                         ? item.mImeName : item.mSubtypeName;
                 mContainer.setActivated(isSelected);
                 // Activated is the correct state, but we also set selected for accessibility info.
                 mContainer.setSelected(isSelected);
+                // Trigger the ellipsize marquee behaviour by selecting the name.
                 mName.setSelected(isSelected);
                 mName.setText(name);
                 mCheckmark.setVisibility(isSelected ? View.VISIBLE : View.GONE);
-                mHeader.setText(item.mImeName);
-                mHeader.setVisibility(item.mHasHeader ? View.VISIBLE : View.GONE);
-                mDivider.setVisibility(item.mHasDivider ? View.VISIBLE : View.GONE);
+            }
+        }
+
+        private static final class HeaderViewHolder extends RecyclerView.ViewHolder {
+
+            /** The title view, only visible if the bound item has a title. */
+            private final TextView mTitle;
+
+            HeaderViewHolder(@NonNull View itemView) {
+                super(itemView);
+
+                mTitle = itemView.requireViewById(com.android.internal.R.id.header_text);
+            }
+
+            /**
+             * Binds the given item to the current view.
+             *
+             * @param item the item to bind.
+             */
+            void bind(@NonNull HeaderItem item) {
+                mTitle.setText(item.mTitle);
+            }
+        }
+
+        private static final class DividerViewHolder extends RecyclerView.ViewHolder {
+
+            DividerViewHolder(@NonNull View itemView) {
+                super(itemView);
             }
         }
     }
diff --git a/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java b/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java
index 5514ec7..dc2c957 100644
--- a/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java
+++ b/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java
@@ -62,7 +62,6 @@
 import com.android.internal.pm.parsing.PackageParser2;
 import com.android.internal.pm.pkg.parsing.ParsingPackageUtils;
 import com.android.internal.util.ArrayUtils;
-import com.android.internal.util.FrameworkStatsLog;
 import com.android.server.LocalServices;
 import com.android.server.integrity.engine.RuleEvaluationEngine;
 import com.android.server.integrity.model.IntegrityCheckResult;
@@ -214,12 +213,6 @@
                                         version, ruleProvider));
                     }
 
-                    FrameworkStatsLog.write(
-                            FrameworkStatsLog.INTEGRITY_RULES_PUSHED,
-                            success,
-                            ruleProvider,
-                            version);
-
                     Intent intent = new Intent();
                     intent.putExtra(EXTRA_STATUS, success ? STATUS_SUCCESS : STATUS_FAILURE);
                     try {
@@ -346,15 +339,6 @@
                                 packageName, result.getEffect(), result.getMatchedRules()));
             }
 
-            FrameworkStatsLog.write(
-                    FrameworkStatsLog.INTEGRITY_CHECK_RESULT_REPORTED,
-                    packageName,
-                    appCertificates.toString(),
-                    appInstallMetadata.getVersionCode(),
-                    installerPackageName,
-                    result.getLoggingResponse(),
-                    result.isCausedByAppCertRule(),
-                    result.isCausedByInstallerRule());
             mPackageManagerInternal.setIntegrityVerificationResult(
                     verificationId,
                     result.getEffect() == IntegrityCheckResult.Effect.ALLOW
diff --git a/services/core/java/com/android/server/integrity/engine/RuleEvaluationEngine.java b/services/core/java/com/android/server/integrity/engine/RuleEvaluationEngine.java
index 61da45d..e8c828b 100644
--- a/services/core/java/com/android/server/integrity/engine/RuleEvaluationEngine.java
+++ b/services/core/java/com/android/server/integrity/engine/RuleEvaluationEngine.java
@@ -66,7 +66,7 @@
     public IntegrityCheckResult evaluate(
             AppInstallMetadata appInstallMetadata) {
         List<Rule> rules = loadRules(appInstallMetadata);
-        return RuleEvaluator.evaluateRules(rules, appInstallMetadata);
+        return IntegrityCheckResult.allow();
     }
 
     private List<Rule> loadRules(AppInstallMetadata appInstallMetadata) {
diff --git a/services/core/java/com/android/server/integrity/engine/RuleEvaluator.java b/services/core/java/com/android/server/integrity/engine/RuleEvaluator.java
deleted file mode 100644
index 9d94304..0000000
--- a/services/core/java/com/android/server/integrity/engine/RuleEvaluator.java
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.integrity.engine;
-
-import static android.content.integrity.Rule.DENY;
-import static android.content.integrity.Rule.FORCE_ALLOW;
-
-import android.annotation.NonNull;
-import android.content.integrity.AppInstallMetadata;
-import android.content.integrity.Rule;
-
-import com.android.server.integrity.model.IntegrityCheckResult;
-
-import java.util.List;
-import java.util.stream.Collectors;
-
-/**
- * A helper class for evaluating rules against app install metadata to find if there are matching
- * rules.
- */
-final class RuleEvaluator {
-
-    /**
-     * Match the list of rules against an app install metadata.
-     *
-     * <p>Rules must be in disjunctive normal form (DNF). A rule should contain AND'ed formulas
-     * only. All rules are OR'ed together by default.
-     *
-     * @param rules The list of rules to evaluate.
-     * @param appInstallMetadata Metadata of the app to be installed, and to evaluate the rules
-     *     against.
-     * @return result of the integrity check
-     */
-    @NonNull
-    static IntegrityCheckResult evaluateRules(
-            List<Rule> rules, AppInstallMetadata appInstallMetadata) {
-
-        // Identify the rules that match the {@code appInstallMetadata}.
-        List<Rule> matchedRules =
-                rules.stream()
-                        .filter(rule -> rule.getFormula().matches(appInstallMetadata))
-                        .collect(Collectors.toList());
-
-        // Identify the matched power allow rules and terminate early if we have any.
-        List<Rule> matchedPowerAllowRules =
-                matchedRules.stream()
-                        .filter(rule -> rule.getEffect() == FORCE_ALLOW)
-                        .collect(Collectors.toList());
-
-        if (!matchedPowerAllowRules.isEmpty()) {
-            return IntegrityCheckResult.allow(matchedPowerAllowRules);
-        }
-
-        // Identify the matched deny rules.
-        List<Rule> matchedDenyRules =
-                matchedRules.stream()
-                        .filter(rule -> rule.getEffect() == DENY)
-                        .collect(Collectors.toList());
-
-        if (!matchedDenyRules.isEmpty()) {
-            return IntegrityCheckResult.deny(matchedDenyRules);
-        }
-
-        // When no rules are denied, return default allow result.
-        return IntegrityCheckResult.allow();
-    }
-}
diff --git a/services/core/java/com/android/server/integrity/model/IntegrityCheckResult.java b/services/core/java/com/android/server/integrity/model/IntegrityCheckResult.java
index 1fa0670..b0647fc 100644
--- a/services/core/java/com/android/server/integrity/model/IntegrityCheckResult.java
+++ b/services/core/java/com/android/server/integrity/model/IntegrityCheckResult.java
@@ -19,8 +19,6 @@
 import android.annotation.Nullable;
 import android.content.integrity.Rule;
 
-import com.android.internal.util.FrameworkStatsLog;
-
 import java.util.Collections;
 import java.util.List;
 
@@ -82,21 +80,6 @@
         return new IntegrityCheckResult(Effect.DENY, ruleList);
     }
 
-    /**
-     * Returns the in value of the integrity check result for logging purposes.
-     */
-    public int getLoggingResponse() {
-        if (getEffect() == Effect.DENY) {
-            return FrameworkStatsLog.INTEGRITY_CHECK_RESULT_REPORTED__RESPONSE__REJECTED;
-        } else if (getEffect() == Effect.ALLOW && getMatchedRules().isEmpty()) {
-            return FrameworkStatsLog.INTEGRITY_CHECK_RESULT_REPORTED__RESPONSE__ALLOWED;
-        } else if (getEffect() == Effect.ALLOW && !getMatchedRules().isEmpty()) {
-            return FrameworkStatsLog.INTEGRITY_CHECK_RESULT_REPORTED__RESPONSE__FORCE_ALLOWED;
-        } else {
-            throw new IllegalStateException("IntegrityCheckResult is not valid.");
-        }
-    }
-
     /** Returns true when the {@code mEffect} is caused by an app certificate mismatch. */
     public boolean isCausedByAppCertRule() {
         return mRuleList.stream().anyMatch(rule -> rule.getFormula().isAppCertificateFormula());
diff --git a/services/core/java/com/android/server/location/contexthub/ContextHubService.java b/services/core/java/com/android/server/location/contexthub/ContextHubService.java
index 3f4a9bb..ed69f7a 100644
--- a/services/core/java/com/android/server/location/contexthub/ContextHubService.java
+++ b/services/core/java/com/android/server/location/contexthub/ContextHubService.java
@@ -444,8 +444,17 @@
         mSupportedContextHubPerms = hubInfo.second;
         mContextHubInfoList = new ArrayList<>(mContextHubIdToInfoMap.values());
         mClientManager = new ContextHubClientManager(mContext, mContextHubWrapper);
-        mTransactionManager = new ContextHubTransactionManager(
-                mContextHubWrapper, mClientManager, mNanoAppStateManager);
+
+        if (Flags.reduceLockingContextHubTransactionManager()) {
+            mTransactionManager =
+                    new ContextHubTransactionManager(
+                            mContextHubWrapper, mClientManager, mNanoAppStateManager);
+        } else {
+            mTransactionManager =
+                    new ContextHubTransactionManagerOld(
+                            mContextHubWrapper, mClientManager, mNanoAppStateManager);
+        }
+
         mSensorPrivacyManagerInternal =
                 LocalServices.getService(SensorPrivacyManagerInternal.class);
         return true;
diff --git a/services/core/java/com/android/server/location/contexthub/ContextHubTransactionManager.java b/services/core/java/com/android/server/location/contexthub/ContextHubTransactionManager.java
index 2a0b1af..da31bf2 100644
--- a/services/core/java/com/android/server/location/contexthub/ContextHubTransactionManager.java
+++ b/services/core/java/com/android/server/location/contexthub/ContextHubTransactionManager.java
@@ -26,6 +26,8 @@
 import android.os.SystemClock;
 import android.util.Log;
 
+import com.android.internal.annotations.GuardedBy;
+
 import java.time.Duration;
 import java.util.ArrayDeque;
 import java.util.Collections;
@@ -43,8 +45,8 @@
 
 /**
  * Manages transactions at the Context Hub Service.
- * <p>
- * This class maintains a queue of transaction requests made to the ContextHubService by clients,
+ *
+ * <p>This class maintains a queue of transaction requests made to the ContextHubService by clients,
  * and executes them through the Context Hub. At any point in time, either the transaction queue is
  * empty, or there is a pending transaction that is waiting for an asynchronous response from the
  * hub. This class also handles synchronous errors and timeouts of each transaction.
@@ -52,66 +54,80 @@
  * @hide
  */
 /* package */ class ContextHubTransactionManager {
-    private static final String TAG = "ContextHubTransactionManager";
+    protected static final String TAG = "ContextHubTransactionManager";
 
     public static final Duration RELIABLE_MESSAGE_TIMEOUT = Duration.ofSeconds(1);
 
     public static final Duration RELIABLE_MESSAGE_DUPLICATE_DETECTION_TIMEOUT =
             RELIABLE_MESSAGE_TIMEOUT.multipliedBy(3);
 
-    private static final int MAX_PENDING_REQUESTS = 10000;
+    // TODO: b/362299144: When cleaning up the flag
+    // reduce_locking_context_hub_transaction_manager, change these to private
+    protected static final int MAX_PENDING_REQUESTS = 10000;
 
-    private static final int RELIABLE_MESSAGE_MAX_NUM_RETRY = 3;
+    protected static final int RELIABLE_MESSAGE_MAX_NUM_RETRY = 3;
 
-    private static final Duration RELIABLE_MESSAGE_RETRY_WAIT_TIME = Duration.ofMillis(250);
+    protected static final Duration RELIABLE_MESSAGE_RETRY_WAIT_TIME = Duration.ofMillis(250);
 
-    private static final Duration RELIABLE_MESSAGE_MIN_WAIT_TIME = Duration.ofNanos(1000);
+    protected static final Duration RELIABLE_MESSAGE_MIN_WAIT_TIME = Duration.ofNanos(1000);
 
-    private final IContextHubWrapper mContextHubProxy;
+    protected final IContextHubWrapper mContextHubProxy;
 
-    private final ContextHubClientManager mClientManager;
+    protected final ContextHubClientManager mClientManager;
 
-    private final NanoAppStateManager mNanoAppStateManager;
+    protected final NanoAppStateManager mNanoAppStateManager;
 
-    private final ArrayDeque<ContextHubServiceTransaction> mTransactionQueue = new ArrayDeque<>();
+    @GuardedBy("mTransactionLock")
+    protected final ArrayDeque<ContextHubServiceTransaction> mTransactionQueue = new ArrayDeque<>();
 
-    private final Map<Integer, ContextHubServiceTransaction> mReliableMessageTransactionMap =
+    @GuardedBy("mReliableMessageLock")
+    protected final Map<Integer, ContextHubServiceTransaction> mReliableMessageTransactionMap =
             new HashMap<>();
 
     /** A set of host endpoint IDs that have an active pending transaction. */
-    private final Set<Short> mReliableMessageHostEndpointIdActiveSet = new HashSet<>();
+    @GuardedBy("mReliableMessageLock")
+    protected final Set<Short> mReliableMessageHostEndpointIdActiveSet = new HashSet<>();
 
-    private final AtomicInteger mNextAvailableId = new AtomicInteger();
+    protected final AtomicInteger mNextAvailableId = new AtomicInteger();
 
     /**
-     * The next available message sequence number. We choose a random
-     * number to start with to avoid collisions and limit the bound to
-     * half of the max value to avoid overflow.
+     * The next available message sequence number. We choose a random number to start with to avoid
+     * collisions and limit the bound to half of the max value to avoid overflow.
      */
-    private final AtomicInteger mNextAvailableMessageSequenceNumber =
+    protected final AtomicInteger mNextAvailableMessageSequenceNumber =
             new AtomicInteger(new Random().nextInt(Integer.MAX_VALUE / 2));
 
     /*
-     * An executor and the future object for scheduling timeout timers and
+     * An executor and the future objects for scheduling timeout timers and
      * for scheduling the processing of reliable message transactions.
      */
-    private final ScheduledThreadPoolExecutor mExecutor = new ScheduledThreadPoolExecutor(1);
-    private ScheduledFuture<?> mTimeoutFuture = null;
-    private ScheduledFuture<?> mReliableMessageTransactionFuture = null;
+    protected final ScheduledThreadPoolExecutor mExecutor = new ScheduledThreadPoolExecutor(2);
+
+    @GuardedBy("mTransactionLock")
+    protected ScheduledFuture<?> mTimeoutFuture = null;
+
+    @GuardedBy("mReliableMessageLock")
+    protected ScheduledFuture<?> mReliableMessageTransactionFuture = null;
 
     /*
      * The list of previous transaction records.
      */
-    private static final int NUM_TRANSACTION_RECORDS = 20;
-    private final ConcurrentLinkedEvictingDeque<TransactionRecord> mTransactionRecordDeque =
+    protected static final int NUM_TRANSACTION_RECORDS = 20;
+    protected final ConcurrentLinkedEvictingDeque<TransactionRecord> mTransactionRecordDeque =
             new ConcurrentLinkedEvictingDeque<>(NUM_TRANSACTION_RECORDS);
 
-    /**
-     * A container class to store a record of transactions.
+    /*
+     * Locks for synchronization of normal transactions separately from reliable message
+     * transactions.
      */
-    private class TransactionRecord {
-        private final String mTransaction;
-        private final long mTimestamp;
+    protected final Object mTransactionLock = new Object();
+    protected final Object mReliableMessageLock = new Object();
+    protected final Object mTransactionRecordLock = new Object();
+
+    /** A container class to store a record of transactions. */
+    protected static class TransactionRecord {
+        protected final String mTransaction;
+        protected final long mTimestamp;
 
         TransactionRecord(String transaction) {
             mTransaction = transaction;
@@ -126,8 +142,18 @@
         }
     }
 
+    /** Used when finishing a transaction. */
+    interface TransactionAcceptConditions {
+        /**
+         * Returns whether to accept the found transaction when receiving a response from the
+         * Context Hub.
+         */
+        boolean acceptTransaction(ContextHubServiceTransaction transaction);
+    }
+
     /* package */ ContextHubTransactionManager(
-            IContextHubWrapper contextHubProxy, ContextHubClientManager clientManager,
+            IContextHubWrapper contextHubProxy,
+            ContextHubClientManager clientManager,
             NanoAppStateManager nanoAppStateManager) {
         mContextHubProxy = contextHubProxy;
         mClientManager = clientManager;
@@ -409,34 +435,47 @@
 
     /**
      * Adds a new transaction to the queue.
-     * <p>
-     * If there was no pending transaction at the time, the transaction that was added will be
+     *
+     * <p>If there was no pending transaction at the time, the transaction that was added will be
      * started in this method. If there were too many transactions in the queue, an exception will
      * be thrown.
      *
      * @param transaction the transaction to add
-     * @throws IllegalStateException if the queue is full
      */
     /* package */
-    synchronized void addTransaction(
-            ContextHubServiceTransaction transaction) throws IllegalStateException {
+    void addTransaction(ContextHubServiceTransaction transaction) {
         if (transaction == null) {
             return;
         }
 
-        if (mTransactionQueue.size() >= MAX_PENDING_REQUESTS
-                || mReliableMessageTransactionMap.size() >= MAX_PENDING_REQUESTS) {
-            throw new IllegalStateException("Transaction queue is full (capacity = "
-                    + MAX_PENDING_REQUESTS + ")");
+        synchronized (mTransactionRecordLock) {
+            mTransactionRecordDeque.add(new TransactionRecord(transaction.toString()));
         }
 
-        mTransactionRecordDeque.add(new TransactionRecord(transaction.toString()));
         if (Flags.reliableMessageRetrySupportService()
                 && transaction.getTransactionType()
                         == ContextHubTransaction.TYPE_RELIABLE_MESSAGE) {
-            mReliableMessageTransactionMap.put(transaction.getMessageSequenceNumber(), transaction);
+            synchronized (mReliableMessageLock) {
+                if (mReliableMessageTransactionMap.size() >= MAX_PENDING_REQUESTS) {
+                    throw new IllegalStateException(
+                            "Reliable message transaction queue is full "
+                                    + "(capacity = "
+                                    + MAX_PENDING_REQUESTS
+                                    + ")");
+                }
+                mReliableMessageTransactionMap.put(
+                        transaction.getMessageSequenceNumber(), transaction);
+            }
             mExecutor.execute(() -> processMessageTransactions());
-        } else {
+            return;
+        }
+
+        synchronized (mTransactionLock) {
+            if (mTransactionQueue.size() >= MAX_PENDING_REQUESTS) {
+                throw new IllegalStateException(
+                        "Transaction queue is full (capacity = " + MAX_PENDING_REQUESTS + ")");
+            }
+
             mTransactionQueue.add(transaction);
             if (mTransactionQueue.size() == 1) {
                 startNextTransaction();
@@ -448,62 +487,85 @@
      * Handles a transaction response from a Context Hub.
      *
      * @param transactionId the transaction ID of the response
-     * @param success       true if the transaction succeeded
+     * @param success true if the transaction succeeded
      */
     /* package */
-    synchronized void onTransactionResponse(int transactionId, boolean success) {
-        ContextHubServiceTransaction transaction = mTransactionQueue.peek();
+    void onTransactionResponse(int transactionId, boolean success) {
+        TransactionAcceptConditions conditions =
+                transaction -> transaction.getTransactionId() == transactionId;
+        ContextHubServiceTransaction transaction = getTransactionAndHandleNext(conditions);
         if (transaction == null) {
-            Log.w(TAG, "Received unexpected transaction response (no transaction pending)");
-            return;
-        }
-        if (transaction.getTransactionId() != transactionId) {
             Log.w(TAG, "Received unexpected transaction response (expected ID = "
-                    + transaction.getTransactionId() + ", received ID = " + transactionId + ")");
+                    + transactionId
+                    + ", received ID = "
+                    + transaction.getTransactionId()
+                    + ")");
             return;
         }
 
-        transaction.onTransactionComplete(success ? ContextHubTransaction.RESULT_SUCCESS :
-                        ContextHubTransaction.RESULT_FAILED_AT_HUB);
-        removeTransactionAndStartNext();
+        synchronized (transaction) {
+            transaction.onTransactionComplete(
+                    success
+                            ? ContextHubTransaction.RESULT_SUCCESS
+                            : ContextHubTransaction.RESULT_FAILED_AT_HUB);
+            transaction.setComplete();
+        }
     }
 
+    /**
+     * Handles a message delivery response from a Context Hub.
+     *
+     * @param messageSequenceNumber the message sequence number of the response
+     * @param success true if the message was delivered successfully
+     */
     /* package */
-    synchronized void onMessageDeliveryResponse(int messageSequenceNumber, boolean success) {
+    void onMessageDeliveryResponse(int messageSequenceNumber, boolean success) {
         if (!Flags.reliableMessageRetrySupportService()) {
-            ContextHubServiceTransaction transaction = mTransactionQueue.peek();
+            TransactionAcceptConditions conditions =
+                    transaction -> transaction.getTransactionType()
+                            == ContextHubTransaction.TYPE_RELIABLE_MESSAGE
+                    && transaction.getMessageSequenceNumber()
+                            == messageSequenceNumber;
+            ContextHubServiceTransaction transaction = getTransactionAndHandleNext(conditions);
             if (transaction == null) {
-                Log.w(TAG, "Received unexpected transaction response (no transaction pending)");
+                Log.w(TAG, "Received unexpected message delivery response (expected"
+                        + " message sequence number = "
+                        + messageSequenceNumber
+                        + ", received messageSequenceNumber = "
+                        + messageSequenceNumber
+                        + ")");
                 return;
             }
 
-            int transactionMessageSequenceNumber = transaction.getMessageSequenceNumber();
-            if (transaction.getTransactionType() != ContextHubTransaction.TYPE_RELIABLE_MESSAGE
-                    || transactionMessageSequenceNumber != messageSequenceNumber) {
-                Log.w(TAG, "Received unexpected message transaction response (expected message "
-                        + "sequence number = "
-                        + transaction.getMessageSequenceNumber()
-                        + ", received messageSequenceNumber = " + messageSequenceNumber + ")");
+            synchronized (transaction) {
+                transaction.onTransactionComplete(
+                        success
+                                ? ContextHubTransaction.RESULT_SUCCESS
+                                : ContextHubTransaction.RESULT_FAILED_AT_HUB);
+                transaction.setComplete();
+            }
+            return;
+        }
+
+        ContextHubServiceTransaction transaction = null;
+        synchronized (mReliableMessageLock) {
+            transaction = mReliableMessageTransactionMap.get(messageSequenceNumber);
+            if (transaction == null) {
+                Log.w(
+                        TAG,
+                        "Could not find reliable message transaction with "
+                                + "message sequence number = "
+                                + messageSequenceNumber);
                 return;
             }
 
-            transaction.onTransactionComplete(success ? ContextHubTransaction.RESULT_SUCCESS :
-                            ContextHubTransaction.RESULT_FAILED_AT_HUB);
-            removeTransactionAndStartNext();
-            return;
+            removeMessageTransaction(transaction);
         }
 
-        ContextHubServiceTransaction transaction =
-                mReliableMessageTransactionMap.get(messageSequenceNumber);
-        if (transaction == null) {
-            Log.w(TAG, "Could not find reliable message transaction with "
-                    + "message sequence number = "
-                    + messageSequenceNumber);
-            return;
-        }
-
-        completeMessageTransaction(transaction,
-                success ? ContextHubTransaction.RESULT_SUCCESS
+        completeMessageTransaction(
+                transaction,
+                success
+                        ? ContextHubTransaction.RESULT_SUCCESS
                         : ContextHubTransaction.RESULT_FAILED_AT_HUB);
         mExecutor.execute(() -> processMessageTransactions());
     }
@@ -514,77 +576,116 @@
      * @param nanoAppStateList the list of nanoapps included in the response
      */
     /* package */
-    synchronized void onQueryResponse(List<NanoAppState> nanoAppStateList) {
-        ContextHubServiceTransaction transaction = mTransactionQueue.peek();
+    void onQueryResponse(List<NanoAppState> nanoAppStateList) {
+        TransactionAcceptConditions conditions = transaction ->
+                transaction.getTransactionType() == ContextHubTransaction.TYPE_QUERY_NANOAPPS;
+        ContextHubServiceTransaction transaction = getTransactionAndHandleNext(conditions);
         if (transaction == null) {
-            Log.w(TAG, "Received unexpected query response (no transaction pending)");
-            return;
-        }
-        if (transaction.getTransactionType() != ContextHubTransaction.TYPE_QUERY_NANOAPPS) {
             Log.w(TAG, "Received unexpected query response (expected " + transaction + ")");
             return;
         }
 
-        transaction.onQueryResponse(ContextHubTransaction.RESULT_SUCCESS, nanoAppStateList);
-        removeTransactionAndStartNext();
+        synchronized (transaction) {
+            transaction.onQueryResponse(ContextHubTransaction.RESULT_SUCCESS, nanoAppStateList);
+            transaction.setComplete();
+        }
     }
 
-    /**
-     * Handles a hub reset event by stopping a pending transaction and starting the next.
-     */
+    /** Handles a hub reset event by stopping a pending transaction and starting the next. */
     /* package */
-    synchronized void onHubReset() {
+    void onHubReset() {
         if (Flags.reliableMessageRetrySupportService()) {
-            Iterator<Map.Entry<Integer, ContextHubServiceTransaction>> iter =
-                    mReliableMessageTransactionMap.entrySet().iterator();
-            while (iter.hasNext()) {
-                completeMessageTransaction(iter.next().getValue(),
-                        ContextHubTransaction.RESULT_FAILED_AT_HUB, iter);
+            synchronized (mReliableMessageLock) {
+                Iterator<Map.Entry<Integer, ContextHubServiceTransaction>> iter =
+                        mReliableMessageTransactionMap.entrySet().iterator();
+                while (iter.hasNext()) {
+                    removeAndCompleteMessageTransaction(
+                            iter.next().getValue(),
+                            ContextHubTransaction.RESULT_FAILED_AT_HUB,
+                            iter);
+                }
             }
         }
 
-        ContextHubServiceTransaction transaction = mTransactionQueue.peek();
-        if (transaction == null) {
-            return;
-        }
+        synchronized (mTransactionLock) {
+            ContextHubServiceTransaction transaction = mTransactionQueue.peek();
+            if (transaction == null) {
+                return;
+            }
 
-        removeTransactionAndStartNext();
+            removeTransactionAndStartNext();
+        }
+    }
+
+    /**
+     * This function also starts the next transaction and removes the active transaction from the
+     * queue. The caller should complete the transaction.
+     *
+     * <p>Returns the active transaction if the transaction queue is not empty, the transaction is
+     * not null, and the transaction matches the conditions.
+     */
+    private ContextHubServiceTransaction getTransactionAndHandleNext(
+            TransactionAcceptConditions conditions) {
+        ContextHubServiceTransaction transaction = null;
+        synchronized (mTransactionLock) {
+            transaction = mTransactionQueue.peek();
+            if (transaction == null
+                    || (conditions != null && !conditions.acceptTransaction(transaction))) {
+                return null;
+            }
+
+            cancelTimeoutFuture();
+            mTransactionQueue.remove();
+            if (!mTransactionQueue.isEmpty()) {
+                startNextTransaction();
+            }
+        }
+        return transaction;
     }
 
     /**
      * Pops the front transaction from the queue and starts the next pending transaction request.
-     * <p>
-     * Removing elements from the transaction queue must only be done through this method. When a
+     *
+     * <p>Removing elements from the transaction queue must only be done through this method. When a
      * pending transaction is removed, the timeout timer is cancelled and the transaction is marked
      * complete.
-     * <p>
-     * It is assumed that the transaction queue is non-empty when this method is invoked, and that
-     * the caller has obtained a lock on this ContextHubTransactionManager object.
+     *
+     * <p>It is assumed that the transaction queue is non-empty when this method is invoked, and
+     * that the caller has obtained mTransactionLock.
      */
+    @GuardedBy("mTransactionLock")
     private void removeTransactionAndStartNext() {
-        if (mTimeoutFuture != null) {
-            mTimeoutFuture.cancel(/* mayInterruptIfRunning= */ false);
-            mTimeoutFuture = null;
-        }
+        cancelTimeoutFuture();
 
         ContextHubServiceTransaction transaction = mTransactionQueue.remove();
-        transaction.setComplete();
+        synchronized (transaction) {
+            transaction.setComplete();
+        }
 
         if (!mTransactionQueue.isEmpty()) {
             startNextTransaction();
         }
     }
 
+    /** Cancels the timeout future. */
+    @GuardedBy("mTransactionLock")
+    private void cancelTimeoutFuture() {
+        if (mTimeoutFuture != null) {
+            mTimeoutFuture.cancel(/* mayInterruptIfRunning= */ false);
+            mTimeoutFuture = null;
+        }
+    }
+
     /**
      * Starts the next pending transaction request.
-     * <p>
-     * Starting new transactions must only be done through this method. This method continues to
+     *
+     * <p>Starting new transactions must only be done through this method. This method continues to
      * process the transaction queue as long as there are pending requests, and no transaction is
      * pending.
-     * <p>
-     * It is assumed that the caller has obtained a lock on this ContextHubTransactionManager
-     * object.
+     *
+     * <p>It is assumed that the caller has obtained a lock on mTransactionLock.
      */
+    @GuardedBy("mTransactionLock")
     private void startNextTransaction() {
         int result = ContextHubTransaction.RESULT_FAILED_UNKNOWN;
         while (result != ContextHubTransaction.RESULT_SUCCESS && !mTransactionQueue.isEmpty()) {
@@ -592,28 +693,36 @@
             result = transaction.onTransact();
 
             if (result == ContextHubTransaction.RESULT_SUCCESS) {
-                Runnable onTimeoutFunc = () -> {
-                    synchronized (this) {
-                        if (!transaction.isComplete()) {
-                            Log.d(TAG, transaction + " timed out");
-                            transaction.onTransactionComplete(
-                                    ContextHubTransaction.RESULT_FAILED_TIMEOUT);
+                Runnable onTimeoutFunc =
+                        () -> {
+                            synchronized (transaction) {
+                                if (!transaction.isComplete()) {
+                                    Log.d(TAG, transaction + " timed out");
+                                    transaction.onTransactionComplete(
+                                            ContextHubTransaction.RESULT_FAILED_TIMEOUT);
+                                    transaction.setComplete();
+                                }
+                            }
 
-                            removeTransactionAndStartNext();
-                        }
-                    }
-                };
+                            synchronized (mTransactionLock) {
+                                removeTransactionAndStartNext();
+                            }
+                        };
 
                 long timeoutMs = transaction.getTimeout(TimeUnit.MILLISECONDS);
                 try {
-                    mTimeoutFuture = mExecutor.schedule(
-                            onTimeoutFunc, timeoutMs, TimeUnit.MILLISECONDS);
+                    mTimeoutFuture =
+                            mExecutor.schedule(onTimeoutFunc, timeoutMs, TimeUnit.MILLISECONDS);
                 } catch (Exception e) {
                     Log.e(TAG, "Error when schedule a timer", e);
                 }
             } else {
-                transaction.onTransactionComplete(
-                        ContextHubServiceUtil.toTransactionResult(result));
+                synchronized (transaction) {
+                    transaction.onTransactionComplete(
+                            ContextHubServiceUtil.toTransactionResult(result));
+                    transaction.setComplete();
+                }
+
                 mTransactionQueue.remove();
             }
         }
@@ -621,81 +730,97 @@
 
     /**
      * Processes message transactions, starting and completing them as needed.
-     * <p>
-     * This function is called when adding a message transaction or when a timer
-     * expires for an existing message transaction's retry or timeout. The
-     * internal processing loop will iterate at most twice as if one iteration
-     * completes a transaction, the next iteration can only start new transactions.
-     * If the first iteration does not complete any transaction, the loop will
-     * only iterate once.
+     *
+     * <p>This function is called when adding a message transaction or when a timer expires for an
+     * existing message transaction's retry or timeout. The internal processing loop will iterate at
+     * most twice as if one iteration completes a transaction, the next iteration can only start new
+     * transactions. If the first iteration does not complete any transaction, the loop will only
+     * iterate once.
+     *
      * <p>
      */
-    private synchronized void processMessageTransactions() {
-        if (!Flags.reliableMessageRetrySupportService()) {
-            return;
-        }
+    private void processMessageTransactions() {
+        synchronized (mReliableMessageLock) {
+            if (!Flags.reliableMessageRetrySupportService()) {
+                return;
+            }
 
-        if (mReliableMessageTransactionFuture != null) {
-            mReliableMessageTransactionFuture.cancel(/* mayInterruptIfRunning= */ false);
-            mReliableMessageTransactionFuture = null;
-        }
+            if (mReliableMessageTransactionFuture != null) {
+                mReliableMessageTransactionFuture.cancel(/* mayInterruptIfRunning= */ false);
+                mReliableMessageTransactionFuture = null;
+            }
 
-        long now = SystemClock.elapsedRealtimeNanos();
-        long nextExecutionTime = Long.MAX_VALUE;
-        boolean continueProcessing;
-        do {
-            continueProcessing = false;
-            Iterator<Map.Entry<Integer, ContextHubServiceTransaction>> iter =
-                    mReliableMessageTransactionMap.entrySet().iterator();
-            while (iter.hasNext()) {
-                ContextHubServiceTransaction transaction = iter.next().getValue();
-                short hostEndpointId = transaction.getHostEndpointId();
-                int numCompletedStartCalls = transaction.getNumCompletedStartCalls();
-                if (numCompletedStartCalls == 0
-                        && mReliableMessageHostEndpointIdActiveSet.contains(hostEndpointId)) {
-                    continue;
-                }
-
-                long nextRetryTime = transaction.getNextRetryTime();
-                long timeoutTime = transaction.getTimeoutTime();
-                boolean transactionTimedOut = timeoutTime <= now;
-                boolean transactionHitMaxRetries = nextRetryTime <= now
-                        && numCompletedStartCalls > RELIABLE_MESSAGE_MAX_NUM_RETRY;
-                if (transactionTimedOut || transactionHitMaxRetries) {
-                    completeMessageTransaction(transaction,
-                            ContextHubTransaction.RESULT_FAILED_TIMEOUT, iter);
-                    continueProcessing = true;
-                } else {
-                    if (nextRetryTime <= now || numCompletedStartCalls <= 0) {
-                        startMessageTransaction(transaction, now);
+            long now = SystemClock.elapsedRealtimeNanos();
+            long nextExecutionTime = Long.MAX_VALUE;
+            boolean continueProcessing;
+            do {
+                continueProcessing = false;
+                Iterator<Map.Entry<Integer, ContextHubServiceTransaction>> iter =
+                        mReliableMessageTransactionMap.entrySet().iterator();
+                while (iter.hasNext()) {
+                    ContextHubServiceTransaction transaction = iter.next().getValue();
+                    short hostEndpointId = transaction.getHostEndpointId();
+                    int numCompletedStartCalls = transaction.getNumCompletedStartCalls();
+                    if (numCompletedStartCalls == 0
+                            && mReliableMessageHostEndpointIdActiveSet.contains(hostEndpointId)) {
+                        continue;
                     }
 
-                    nextExecutionTime = Math.min(nextExecutionTime,
-                            transaction.getNextRetryTime());
-                    nextExecutionTime = Math.min(nextExecutionTime,
-                            transaction.getTimeoutTime());
-                }
-            }
-        } while (continueProcessing);
+                    long nextRetryTime = transaction.getNextRetryTime();
+                    long timeoutTime = transaction.getTimeoutTime();
+                    boolean transactionTimedOut = timeoutTime <= now;
+                    boolean transactionHitMaxRetries =
+                            nextRetryTime <= now
+                                    && numCompletedStartCalls > RELIABLE_MESSAGE_MAX_NUM_RETRY;
+                    if (transactionTimedOut || transactionHitMaxRetries) {
+                        removeAndCompleteMessageTransaction(
+                                transaction, ContextHubTransaction.RESULT_FAILED_TIMEOUT, iter);
+                        continueProcessing = true;
+                    } else {
+                        if (nextRetryTime <= now || numCompletedStartCalls <= 0) {
+                            startMessageTransaction(transaction, now);
+                        }
 
-        if (nextExecutionTime < Long.MAX_VALUE) {
-            mReliableMessageTransactionFuture = mExecutor.schedule(
-                    () -> processMessageTransactions(),
-                    Math.max(nextExecutionTime - SystemClock.elapsedRealtimeNanos(),
-                            RELIABLE_MESSAGE_MIN_WAIT_TIME.toNanos()),
-                    TimeUnit.NANOSECONDS);
+                        nextExecutionTime =
+                                Math.min(nextExecutionTime, transaction.getNextRetryTime());
+                        nextExecutionTime =
+                                Math.min(nextExecutionTime, transaction.getTimeoutTime());
+                    }
+                }
+            } while (continueProcessing);
+
+            if (nextExecutionTime < Long.MAX_VALUE) {
+                mReliableMessageTransactionFuture =
+                        mExecutor.schedule(
+                                () -> processMessageTransactions(),
+                                Math.max(
+                                        nextExecutionTime - SystemClock.elapsedRealtimeNanos(),
+                                        RELIABLE_MESSAGE_MIN_WAIT_TIME.toNanos()),
+                                TimeUnit.NANOSECONDS);
+            }
         }
     }
 
     /**
-     * Completes a message transaction and removes it from the reliable message map.
+     * Completes a message transaction.
      *
      * @param transaction The transaction to complete.
      * @param result The result code.
      */
-    private void completeMessageTransaction(ContextHubServiceTransaction transaction,
-            @ContextHubTransaction.Result int result) {
-        completeMessageTransaction(transaction, result, /* iter= */ null);
+    private void completeMessageTransaction(
+            ContextHubServiceTransaction transaction, @ContextHubTransaction.Result int result) {
+        synchronized (transaction) {
+            transaction.onTransactionComplete(result);
+            transaction.setComplete();
+        }
+
+        Log.d(
+                TAG,
+                "Successfully completed reliable message transaction with "
+                        + "message sequence number = "
+                        + transaction.getMessageSequenceNumber()
+                        + " and result = "
+                        + result);
     }
 
     /**
@@ -705,25 +830,41 @@
      * @param result The result code.
      * @param iter The iterator for the reliable message map - used to remove the message directly.
      */
-    private void completeMessageTransaction(ContextHubServiceTransaction transaction,
+    @GuardedBy("mReliableMessageLock")
+    private void removeAndCompleteMessageTransaction(
+            ContextHubServiceTransaction transaction,
             @ContextHubTransaction.Result int result,
             Iterator<Map.Entry<Integer, ContextHubServiceTransaction>> iter) {
-        transaction.onTransactionComplete(result);
+        removeMessageTransaction(transaction, iter);
+        completeMessageTransaction(transaction, result);
+    }
 
+    /**
+     * Removes a message transaction from the reliable message map.
+     *
+     * @param transaction The transaction to remove.
+     */
+    @GuardedBy("mReliableMessageLock")
+    private void removeMessageTransaction(ContextHubServiceTransaction transaction) {
+        removeMessageTransaction(transaction, /* iter= */ null);
+    }
+
+    /**
+     * Removes a message transaction from the reliable message map.
+     *
+     * @param transaction The transaction to remove.
+     * @param iter The iterator for the reliable message map - used to remove the message directly.
+     */
+    @GuardedBy("mReliableMessageLock")
+    private void removeMessageTransaction(
+            ContextHubServiceTransaction transaction,
+            Iterator<Map.Entry<Integer, ContextHubServiceTransaction>> iter) {
         if (iter == null) {
             mReliableMessageTransactionMap.remove(transaction.getMessageSequenceNumber());
         } else {
             iter.remove();
         }
         mReliableMessageHostEndpointIdActiveSet.remove(transaction.getHostEndpointId());
-
-    Log.d(
-        TAG,
-        "Successfully completed reliable message transaction with "
-            + "message sequence number = "
-            + transaction.getMessageSequenceNumber()
-            + " and result = "
-            + result);
     }
 
     /**
@@ -732,24 +873,25 @@
      * @param transaction The transaction to start.
      * @param now The now time.
      */
+    @GuardedBy("mReliableMessageLock")
     private void startMessageTransaction(ContextHubServiceTransaction transaction, long now) {
         int numCompletedStartCalls = transaction.getNumCompletedStartCalls();
         @ContextHubTransaction.Result int result = transaction.onTransact();
         if (result == ContextHubTransaction.RESULT_SUCCESS) {
-      Log.d(
-          TAG,
-          "Successfully "
-              + (numCompletedStartCalls == 0 ? "started" : "retried")
-              + " reliable message transaction with message sequence number = "
-              + transaction.getMessageSequenceNumber());
+            Log.d(
+                    TAG,
+                    "Successfully "
+                            + (numCompletedStartCalls == 0 ? "started" : "retried")
+                            + " reliable message transaction with message sequence number = "
+                            + transaction.getMessageSequenceNumber());
         } else {
-      Log.w(
-          TAG,
-          "Could not start reliable message transaction with "
-              + "message sequence number = "
-              + transaction.getMessageSequenceNumber()
-              + ", result = "
-              + result);
+            Log.w(
+                    TAG,
+                    "Could not start reliable message transaction with "
+                            + "message sequence number = "
+                            + transaction.getMessageSequenceNumber()
+                            + ", result = "
+                            + result);
         }
 
         transaction.setNextRetryTime(now + RELIABLE_MESSAGE_RETRY_WAIT_TIME.toNanos());
@@ -788,17 +930,19 @@
     public String toString() {
         StringBuilder sb = new StringBuilder();
         int i = 0;
-        synchronized (this) {
-            for (ContextHubServiceTransaction transaction: mTransactionQueue) {
+        synchronized (mTransactionLock) {
+            for (ContextHubServiceTransaction transaction : mTransactionQueue) {
                 sb.append(i);
                 sb.append(": ");
                 sb.append(transaction.toString());
                 sb.append("\n");
                 ++i;
             }
+        }
 
-            if (Flags.reliableMessageRetrySupportService()) {
-                for (ContextHubServiceTransaction transaction:
+        if (Flags.reliableMessageRetrySupportService()) {
+            synchronized (mReliableMessageLock) {
+                for (ContextHubServiceTransaction transaction :
                         mReliableMessageTransactionMap.values()) {
                     sb.append(i);
                     sb.append(": ");
@@ -807,7 +951,9 @@
                     ++i;
                 }
             }
+        }
 
+        synchronized (mTransactionRecordLock) {
             sb.append("Transaction History:\n");
             Iterator<TransactionRecord> iterator = mTransactionRecordDeque.descendingIterator();
             while (iterator.hasNext()) {
@@ -815,6 +961,7 @@
                 sb.append("\n");
             }
         }
+
         return sb.toString();
     }
 }
diff --git a/services/core/java/com/android/server/location/contexthub/ContextHubTransactionManagerOld.java b/services/core/java/com/android/server/location/contexthub/ContextHubTransactionManagerOld.java
new file mode 100644
index 0000000..a67fa30
--- /dev/null
+++ b/services/core/java/com/android/server/location/contexthub/ContextHubTransactionManagerOld.java
@@ -0,0 +1,475 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.location.contexthub;
+
+import android.chre.flags.Flags;
+import android.hardware.location.ContextHubTransaction;
+import android.hardware.location.IContextHubTransactionCallback;
+import android.hardware.location.NanoAppBinary;
+import android.hardware.location.NanoAppMessage;
+import android.hardware.location.NanoAppState;
+import android.os.RemoteException;
+import android.os.SystemClock;
+import android.util.Log;
+
+import java.time.Duration;
+import java.util.ArrayDeque;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Random;
+import java.util.Set;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.ScheduledThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * Manages transactions at the Context Hub Service.
+ *
+ * <p>This class maintains a queue of transaction requests made to the ContextHubService by clients,
+ * and executes them through the Context Hub. At any point in time, either the transaction queue is
+ * empty, or there is a pending transaction that is waiting for an asynchronous response from the
+ * hub. This class also handles synchronous errors and timeouts of each transaction.
+ *
+ * <p>This is the old version of ContextHubTransactionManager that uses global synchronization
+ * instead of individual locks. This will be deleted when the
+ * reduce_locking_context_hub_transaction_manager flag is cleaned up.
+ *
+ * @hide
+ */
+/* package */ class ContextHubTransactionManagerOld extends ContextHubTransactionManager {
+    /* package */ ContextHubTransactionManagerOld(
+            IContextHubWrapper contextHubProxy,
+            ContextHubClientManager clientManager,
+            NanoAppStateManager nanoAppStateManager) {
+        super(contextHubProxy, clientManager, nanoAppStateManager);
+    }
+
+    /**
+     * Adds a new transaction to the queue.
+     *
+     * <p>If there was no pending transaction at the time, the transaction that was added will be
+     * started in this method. If there were too many transactions in the queue, an exception will
+     * be thrown.
+     *
+     * @param transaction the transaction to add
+     * @throws IllegalStateException if the queue is full
+     */
+    /* package */
+    @Override
+    synchronized void addTransaction(ContextHubServiceTransaction transaction)
+            throws IllegalStateException {
+        if (transaction == null) {
+            return;
+        }
+
+        if (mTransactionQueue.size() >= MAX_PENDING_REQUESTS
+                || mReliableMessageTransactionMap.size() >= MAX_PENDING_REQUESTS) {
+            throw new IllegalStateException(
+                    "Transaction queue is full (capacity = " + MAX_PENDING_REQUESTS + ")");
+        }
+
+        mTransactionRecordDeque.add(new TransactionRecord(transaction.toString()));
+        if (Flags.reliableMessageRetrySupportService()
+                && transaction.getTransactionType()
+                        == ContextHubTransaction.TYPE_RELIABLE_MESSAGE) {
+            mReliableMessageTransactionMap.put(transaction.getMessageSequenceNumber(), transaction);
+            mExecutor.execute(() -> processMessageTransactions());
+        } else {
+            mTransactionQueue.add(transaction);
+            if (mTransactionQueue.size() == 1) {
+                startNextTransaction();
+            }
+        }
+    }
+
+    /**
+     * Handles a transaction response from a Context Hub.
+     *
+     * @param transactionId the transaction ID of the response
+     * @param success true if the transaction succeeded
+     */
+    /* package */
+    @Override
+    synchronized void onTransactionResponse(int transactionId, boolean success) {
+        ContextHubServiceTransaction transaction = mTransactionQueue.peek();
+        if (transaction == null) {
+            Log.w(TAG, "Received unexpected transaction response (no transaction pending)");
+            return;
+        }
+        if (transaction.getTransactionId() != transactionId) {
+            Log.w(
+                    TAG,
+                    "Received unexpected transaction response (expected ID = "
+                            + transaction.getTransactionId()
+                            + ", received ID = "
+                            + transactionId
+                            + ")");
+            return;
+        }
+
+        transaction.onTransactionComplete(
+                success
+                        ? ContextHubTransaction.RESULT_SUCCESS
+                        : ContextHubTransaction.RESULT_FAILED_AT_HUB);
+        removeTransactionAndStartNext();
+    }
+
+    /* package */
+    @Override
+    synchronized void onMessageDeliveryResponse(int messageSequenceNumber, boolean success) {
+        if (!Flags.reliableMessageRetrySupportService()) {
+            ContextHubServiceTransaction transaction = mTransactionQueue.peek();
+            if (transaction == null) {
+                Log.w(TAG, "Received unexpected transaction response (no transaction pending)");
+                return;
+            }
+
+            int transactionMessageSequenceNumber = transaction.getMessageSequenceNumber();
+            if (transaction.getTransactionType() != ContextHubTransaction.TYPE_RELIABLE_MESSAGE
+                    || transactionMessageSequenceNumber != messageSequenceNumber) {
+                Log.w(
+                        TAG,
+                        "Received unexpected message transaction response (expected message "
+                                + "sequence number = "
+                                + transaction.getMessageSequenceNumber()
+                                + ", received messageSequenceNumber = "
+                                + messageSequenceNumber
+                                + ")");
+                return;
+            }
+
+            transaction.onTransactionComplete(
+                    success
+                            ? ContextHubTransaction.RESULT_SUCCESS
+                            : ContextHubTransaction.RESULT_FAILED_AT_HUB);
+            removeTransactionAndStartNext();
+            return;
+        }
+
+        ContextHubServiceTransaction transaction =
+                mReliableMessageTransactionMap.get(messageSequenceNumber);
+        if (transaction == null) {
+            Log.w(
+                    TAG,
+                    "Could not find reliable message transaction with "
+                            + "message sequence number = "
+                            + messageSequenceNumber);
+            return;
+        }
+
+        completeMessageTransaction(
+                transaction,
+                success
+                        ? ContextHubTransaction.RESULT_SUCCESS
+                        : ContextHubTransaction.RESULT_FAILED_AT_HUB);
+        mExecutor.execute(() -> processMessageTransactions());
+    }
+
+    /**
+     * Handles a query response from a Context Hub.
+     *
+     * @param nanoAppStateList the list of nanoapps included in the response
+     */
+    /* package */
+    @Override
+    synchronized void onQueryResponse(List<NanoAppState> nanoAppStateList) {
+        ContextHubServiceTransaction transaction = mTransactionQueue.peek();
+        if (transaction == null) {
+            Log.w(TAG, "Received unexpected query response (no transaction pending)");
+            return;
+        }
+        if (transaction.getTransactionType() != ContextHubTransaction.TYPE_QUERY_NANOAPPS) {
+            Log.w(TAG, "Received unexpected query response (expected " + transaction + ")");
+            return;
+        }
+
+        transaction.onQueryResponse(ContextHubTransaction.RESULT_SUCCESS, nanoAppStateList);
+        removeTransactionAndStartNext();
+    }
+
+    /** Handles a hub reset event by stopping a pending transaction and starting the next. */
+    /* package */
+    @Override
+    synchronized void onHubReset() {
+        if (Flags.reliableMessageRetrySupportService()) {
+            Iterator<Map.Entry<Integer, ContextHubServiceTransaction>> iter =
+                    mReliableMessageTransactionMap.entrySet().iterator();
+            while (iter.hasNext()) {
+                completeMessageTransaction(
+                        iter.next().getValue(), ContextHubTransaction.RESULT_FAILED_AT_HUB, iter);
+            }
+        }
+
+        ContextHubServiceTransaction transaction = mTransactionQueue.peek();
+        if (transaction == null) {
+            return;
+        }
+
+        removeTransactionAndStartNext();
+    }
+
+    /**
+     * Pops the front transaction from the queue and starts the next pending transaction request.
+     *
+     * <p>Removing elements from the transaction queue must only be done through this method. When a
+     * pending transaction is removed, the timeout timer is cancelled and the transaction is marked
+     * complete.
+     *
+     * <p>It is assumed that the transaction queue is non-empty when this method is invoked, and
+     * that the caller has obtained a lock on this ContextHubTransactionManager object.
+     */
+    private void removeTransactionAndStartNext() {
+        if (mTimeoutFuture != null) {
+            mTimeoutFuture.cancel(/* mayInterruptIfRunning= */ false);
+            mTimeoutFuture = null;
+        }
+
+        ContextHubServiceTransaction transaction = mTransactionQueue.remove();
+        transaction.setComplete();
+
+        if (!mTransactionQueue.isEmpty()) {
+            startNextTransaction();
+        }
+    }
+
+    /**
+     * Starts the next pending transaction request.
+     *
+     * <p>Starting new transactions must only be done through this method. This method continues to
+     * process the transaction queue as long as there are pending requests, and no transaction is
+     * pending.
+     *
+     * <p>It is assumed that the caller has obtained a lock on this ContextHubTransactionManager
+     * object.
+     */
+    private void startNextTransaction() {
+        int result = ContextHubTransaction.RESULT_FAILED_UNKNOWN;
+        while (result != ContextHubTransaction.RESULT_SUCCESS && !mTransactionQueue.isEmpty()) {
+            ContextHubServiceTransaction transaction = mTransactionQueue.peek();
+            result = transaction.onTransact();
+
+            if (result == ContextHubTransaction.RESULT_SUCCESS) {
+                Runnable onTimeoutFunc =
+                        () -> {
+                            synchronized (this) {
+                                if (!transaction.isComplete()) {
+                                    Log.d(TAG, transaction + " timed out");
+                                    transaction.onTransactionComplete(
+                                            ContextHubTransaction.RESULT_FAILED_TIMEOUT);
+
+                                    removeTransactionAndStartNext();
+                                }
+                            }
+                        };
+
+                long timeoutMs = transaction.getTimeout(TimeUnit.MILLISECONDS);
+                try {
+                    mTimeoutFuture =
+                            mExecutor.schedule(onTimeoutFunc, timeoutMs, TimeUnit.MILLISECONDS);
+                } catch (Exception e) {
+                    Log.e(TAG, "Error when schedule a timer", e);
+                }
+            } else {
+                transaction.onTransactionComplete(
+                        ContextHubServiceUtil.toTransactionResult(result));
+                mTransactionQueue.remove();
+            }
+        }
+    }
+
+    /**
+     * Processes message transactions, starting and completing them as needed.
+     *
+     * <p>This function is called when adding a message transaction or when a timer expires for an
+     * existing message transaction's retry or timeout. The internal processing loop will iterate at
+     * most twice as if one iteration completes a transaction, the next iteration can only start new
+     * transactions. If the first iteration does not complete any transaction, the loop will only
+     * iterate once.
+     *
+     * <p>
+     */
+    private synchronized void processMessageTransactions() {
+        if (!Flags.reliableMessageRetrySupportService()) {
+            return;
+        }
+
+        if (mReliableMessageTransactionFuture != null) {
+            mReliableMessageTransactionFuture.cancel(/* mayInterruptIfRunning= */ false);
+            mReliableMessageTransactionFuture = null;
+        }
+
+        long now = SystemClock.elapsedRealtimeNanos();
+        long nextExecutionTime = Long.MAX_VALUE;
+        boolean continueProcessing;
+        do {
+            continueProcessing = false;
+            Iterator<Map.Entry<Integer, ContextHubServiceTransaction>> iter =
+                    mReliableMessageTransactionMap.entrySet().iterator();
+            while (iter.hasNext()) {
+                ContextHubServiceTransaction transaction = iter.next().getValue();
+                short hostEndpointId = transaction.getHostEndpointId();
+                int numCompletedStartCalls = transaction.getNumCompletedStartCalls();
+                if (numCompletedStartCalls == 0
+                        && mReliableMessageHostEndpointIdActiveSet.contains(hostEndpointId)) {
+                    continue;
+                }
+
+                long nextRetryTime = transaction.getNextRetryTime();
+                long timeoutTime = transaction.getTimeoutTime();
+                boolean transactionTimedOut = timeoutTime <= now;
+                boolean transactionHitMaxRetries =
+                        nextRetryTime <= now
+                                && numCompletedStartCalls > RELIABLE_MESSAGE_MAX_NUM_RETRY;
+                if (transactionTimedOut || transactionHitMaxRetries) {
+                    completeMessageTransaction(
+                            transaction, ContextHubTransaction.RESULT_FAILED_TIMEOUT, iter);
+                    continueProcessing = true;
+                } else {
+                    if (nextRetryTime <= now || numCompletedStartCalls <= 0) {
+                        startMessageTransaction(transaction, now);
+                    }
+
+                    nextExecutionTime = Math.min(nextExecutionTime, transaction.getNextRetryTime());
+                    nextExecutionTime = Math.min(nextExecutionTime, transaction.getTimeoutTime());
+                }
+            }
+        } while (continueProcessing);
+
+        if (nextExecutionTime < Long.MAX_VALUE) {
+            mReliableMessageTransactionFuture =
+                    mExecutor.schedule(
+                            () -> processMessageTransactions(),
+                            Math.max(
+                                    nextExecutionTime - SystemClock.elapsedRealtimeNanos(),
+                                    RELIABLE_MESSAGE_MIN_WAIT_TIME.toNanos()),
+                            TimeUnit.NANOSECONDS);
+        }
+    }
+
+    /**
+     * Completes a message transaction and removes it from the reliable message map.
+     *
+     * @param transaction The transaction to complete.
+     * @param result The result code.
+     */
+    private void completeMessageTransaction(
+            ContextHubServiceTransaction transaction, @ContextHubTransaction.Result int result) {
+        completeMessageTransaction(transaction, result, /* iter= */ null);
+    }
+
+    /**
+     * Completes a message transaction and removes it from the reliable message map using iter.
+     *
+     * @param transaction The transaction to complete.
+     * @param result The result code.
+     * @param iter The iterator for the reliable message map - used to remove the message directly.
+     */
+    private void completeMessageTransaction(
+            ContextHubServiceTransaction transaction,
+            @ContextHubTransaction.Result int result,
+            Iterator<Map.Entry<Integer, ContextHubServiceTransaction>> iter) {
+        transaction.onTransactionComplete(result);
+
+        if (iter == null) {
+            mReliableMessageTransactionMap.remove(transaction.getMessageSequenceNumber());
+        } else {
+            iter.remove();
+        }
+        mReliableMessageHostEndpointIdActiveSet.remove(transaction.getHostEndpointId());
+
+        Log.d(
+                TAG,
+                "Successfully completed reliable message transaction with "
+                        + "message sequence number = "
+                        + transaction.getMessageSequenceNumber()
+                        + " and result = "
+                        + result);
+    }
+
+    /**
+     * Starts a message transaction.
+     *
+     * @param transaction The transaction to start.
+     * @param now The now time.
+     */
+    private void startMessageTransaction(ContextHubServiceTransaction transaction, long now) {
+        int numCompletedStartCalls = transaction.getNumCompletedStartCalls();
+        @ContextHubTransaction.Result int result = transaction.onTransact();
+        if (result == ContextHubTransaction.RESULT_SUCCESS) {
+            Log.d(
+                    TAG,
+                    "Successfully "
+                            + (numCompletedStartCalls == 0 ? "started" : "retried")
+                            + " reliable message transaction with message sequence number = "
+                            + transaction.getMessageSequenceNumber());
+        } else {
+            Log.w(
+                    TAG,
+                    "Could not start reliable message transaction with "
+                            + "message sequence number = "
+                            + transaction.getMessageSequenceNumber()
+                            + ", result = "
+                            + result);
+        }
+
+        transaction.setNextRetryTime(now + RELIABLE_MESSAGE_RETRY_WAIT_TIME.toNanos());
+        if (transaction.getTimeoutTime() == Long.MAX_VALUE) { // first time starting transaction
+            transaction.setTimeoutTime(now + RELIABLE_MESSAGE_TIMEOUT.toNanos());
+        }
+        transaction.setNumCompletedStartCalls(numCompletedStartCalls + 1);
+        mReliableMessageHostEndpointIdActiveSet.add(transaction.getHostEndpointId());
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+        int i = 0;
+        synchronized (this) {
+            for (ContextHubServiceTransaction transaction : mTransactionQueue) {
+                sb.append(i);
+                sb.append(": ");
+                sb.append(transaction.toString());
+                sb.append("\n");
+                ++i;
+            }
+
+            if (Flags.reliableMessageRetrySupportService()) {
+                for (ContextHubServiceTransaction transaction :
+                        mReliableMessageTransactionMap.values()) {
+                    sb.append(i);
+                    sb.append(": ");
+                    sb.append(transaction.toString());
+                    sb.append("\n");
+                    ++i;
+                }
+            }
+
+            sb.append("Transaction History:\n");
+            Iterator<TransactionRecord> iterator = mTransactionRecordDeque.descendingIterator();
+            while (iterator.hasNext()) {
+                sb.append(iterator.next());
+                sb.append("\n");
+            }
+        }
+        return sb.toString();
+    }
+}
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverySnapshotStorage.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverySnapshotStorage.java
index c02b103..404c841 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverySnapshotStorage.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverySnapshotStorage.java
@@ -19,7 +19,6 @@
 import android.annotation.Nullable;
 import android.os.Environment;
 import android.security.keystore.recovery.KeyChainSnapshot;
-import android.util.Log;
 import android.util.SparseArray;
 
 import com.android.internal.annotations.GuardedBy;
@@ -29,9 +28,11 @@
 import com.android.server.locksettings.recoverablekeystore.serialization
         .KeyChainSnapshotParserException;
 import com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSerializer;
+import com.android.server.utils.Slogf;
 
 import java.io.File;
 import java.io.FileInputStream;
+import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.security.cert.CertificateEncodingException;
@@ -81,12 +82,14 @@
     public synchronized void put(int uid, KeyChainSnapshot snapshot) {
         mSnapshotByUid.put(uid, snapshot);
 
-        try {
-            writeToDisk(uid, snapshot);
+        File snapshotFile = getSnapshotFile(uid);
+        try (FileOutputStream fileOutputStream = new FileOutputStream(snapshotFile)) {
+            KeyChainSnapshotSerializer.serialize(snapshot, fileOutputStream);
         } catch (IOException | CertificateEncodingException e) {
-            Log.e(TAG,
-                    String.format(Locale.US, "Error persisting snapshot for %d to disk", uid),
-                    e);
+            // If we fail to write the latest snapshot, we should delete any older snapshot that
+            // happens to be around. Otherwise snapshot syncs might end up going 'back in time'.
+            snapshotFile.delete();
+            Slogf.e(TAG, e, "Error persisting snapshot for %d to disk", uid);
         }
     }
 
@@ -100,10 +103,17 @@
             return snapshot;
         }
 
-        try {
-            return readFromDisk(uid);
+        File snapshotFile = getSnapshotFile(uid);
+        try (FileInputStream fileInputStream = new FileInputStream(snapshotFile)) {
+            return KeyChainSnapshotDeserializer.deserialize(fileInputStream);
+        } catch (FileNotFoundException e) {
+            Slogf.i(TAG, "Snapshot for uid %d not found", uid);
+            return null;
         } catch (IOException | KeyChainSnapshotParserException e) {
-            Log.e(TAG, String.format(Locale.US, "Error reading snapshot for %d from disk", uid), e);
+            // If we fail to read the latest snapshot, we should delete it in case it is in some way
+            // corrupted. We can regenerate snapshots anyway.
+            snapshotFile.delete();
+            Slogf.e(TAG, e, "Error reading snapshot for %d from disk", uid);
             return null;
         }
     }
@@ -116,50 +126,6 @@
         getSnapshotFile(uid).delete();
     }
 
-    /**
-     * Writes the snapshot for recovery agent {@code uid} to disk.
-     *
-     * @throws IOException if an IO error occurs writing to disk.
-     */
-    private void writeToDisk(int uid, KeyChainSnapshot snapshot)
-            throws IOException, CertificateEncodingException {
-        File snapshotFile = getSnapshotFile(uid);
-
-        try (
-            FileOutputStream fileOutputStream = new FileOutputStream(snapshotFile)
-        ) {
-            KeyChainSnapshotSerializer.serialize(snapshot, fileOutputStream);
-        } catch (IOException | CertificateEncodingException e) {
-            // If we fail to write the latest snapshot, we should delete any older snapshot that
-            // happens to be around. Otherwise snapshot syncs might end up going 'back in time'.
-            snapshotFile.delete();
-            throw e;
-        }
-    }
-
-    /**
-     * Reads the last snapshot for recovery agent {@code uid} from disk.
-     *
-     * @return The snapshot, or null if none existed.
-     * @throws IOException if an IO error occurs reading from disk.
-     */
-    @Nullable
-    private KeyChainSnapshot readFromDisk(int uid)
-            throws IOException, KeyChainSnapshotParserException {
-        File snapshotFile = getSnapshotFile(uid);
-
-        try (
-            FileInputStream fileInputStream = new FileInputStream(snapshotFile)
-        ) {
-            return KeyChainSnapshotDeserializer.deserialize(fileInputStream);
-        } catch (IOException | KeyChainSnapshotParserException e) {
-            // If we fail to read the latest snapshot, we should delete it in case it is in some way
-            // corrupted. We can regenerate snapshots anyway.
-            snapshotFile.delete();
-            throw e;
-        }
-    }
-
     private File getSnapshotFile(int uid) {
         File folder = getStorageFolder();
         String fileName = getSnapshotFileName(uid);
diff --git a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
index 8b06dad..d1d5d48 100644
--- a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
+++ b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
@@ -1112,19 +1112,12 @@
                 continue;
             }
 
-            Log.w(
-                    TAG,
-                    TextUtils.formatSimple(
-                            "Revoking access to manager record id: %d, package: %s, userId:"
-                                    + " %d",
-                            manager.mManagerId, manager.mOwnerPackageName, userRecord.mUserId));
-
+            Slog.w(TAG, "Revoking access for " + manager.getDebugString());
             unregisterManagerLocked(manager.mManager, /* died */ false);
-
             try {
                 manager.mManager.invalidateInstance();
             } catch (RemoteException ex) {
-                Slog.w(TAG, "Failed to notify manager= " + manager + " of permission revocation.");
+                manager.logRemoteException("invalidateInstance", ex);
             }
         }
     }
@@ -2428,10 +2421,7 @@
             try {
                 mManager.notifyRequestFailed(requestId, reason);
             } catch (RemoteException ex) {
-                Slog.w(
-                        TAG,
-                        "Failed to notify manager of the request failure. Manager probably died.",
-                        ex);
+                logRemoteException("notifyRequestFailed", ex);
             }
         }
 
@@ -2444,7 +2434,7 @@
             try {
                 mManager.notifyRoutesUpdated(routes);
             } catch (RemoteException ex) {
-                Slog.w(TAG, "Failed to notify routes. Manager probably died.", ex);
+                logRemoteException("notifyRoutesUpdated", ex);
             }
         }
 
@@ -2457,10 +2447,7 @@
             try {
                 mManager.notifySessionUpdated(sessionInfo);
             } catch (RemoteException ex) {
-                Slog.w(
-                        TAG,
-                        "notifySessionUpdatedToManagers: Failed to notify. Manager probably died.",
-                        ex);
+                logRemoteException("notifySessionUpdated", ex);
             }
         }
 
@@ -2473,13 +2460,18 @@
             try {
                 mManager.notifySessionReleased(sessionInfo);
             } catch (RemoteException ex) {
-                Slog.w(
-                        TAG,
-                        "notifySessionReleasedToManagers: Failed to notify. Manager probably died.",
-                        ex);
+                logRemoteException("notifySessionReleased", ex);
             }
         }
 
+        private void logRemoteException(String operation, RemoteException exception) {
+            String message =
+                    TextUtils.formatSimple(
+                            "%s failed for %s due to %s",
+                            operation, getDebugString(), exception.toString());
+            Slog.w(TAG, message);
+        }
+
         private void updateScanningState(@ScanningState int scanningState) {
             if (mScanningState == scanningState) {
                 return;
@@ -2492,9 +2484,16 @@
                             UserHandler::updateDiscoveryPreferenceOnHandler, mUserRecord.mHandler));
         }
 
-        @Override
-        public String toString() {
-            return "Manager " + mOwnerPackageName + " (pid " + mOwnerPid + ")";
+        /** Returns a human readable representation of this manager record for logging purposes. */
+        public String getDebugString() {
+            return TextUtils.formatSimple(
+                    "Manager %s (id=%d,pid=%d,userId=%d,uid=%d,targetPkg=%s)",
+                    mOwnerPackageName,
+                    mManagerId,
+                    mOwnerPid,
+                    mUserRecord.mUserId,
+                    mOwnerUid,
+                    mTargetPackageName);
         }
     }
 
diff --git a/services/core/java/com/android/server/notification/ManagedServices.java b/services/core/java/com/android/server/notification/ManagedServices.java
index 03fc60c..93482e7 100644
--- a/services/core/java/com/android/server/notification/ManagedServices.java
+++ b/services/core/java/com/android/server/notification/ManagedServices.java
@@ -712,13 +712,21 @@
                         }
                     }
                     readExtraAttributes(tag, parser, resolvedUserId);
-                    if (allowedManagedServicePackages == null || allowedManagedServicePackages.test(
-                            getPackageName(approved), resolvedUserId, getRequiredPermission())
-                            || approved.isEmpty()) {
-                        if (mUm.getUserInfo(resolvedUserId) != null) {
-                            addApprovedList(approved, resolvedUserId, isPrimary, userSetComponent);
-                        }
+                    if (isUserChanged != null && approved.isEmpty()) {
+                        // NAS
+                        denyPregrantedAppUserSet(resolvedUserId, isPrimary);
                         mUseXml = true;
+                    } else {
+                        if (allowedManagedServicePackages == null
+                                || allowedManagedServicePackages.test(
+                                getPackageName(approved), resolvedUserId, getRequiredPermission())
+                                || approved.isEmpty()) {
+                            if (mUm.getUserInfo(resolvedUserId) != null) {
+                                addApprovedList(approved, resolvedUserId, isPrimary,
+                                        userSetComponent);
+                            }
+                            mUseXml = true;
+                        }
                     }
                 } else {
                     readExtraTag(tag, parser);
@@ -826,6 +834,17 @@
         }
     }
 
+    protected void denyPregrantedAppUserSet(int userId, boolean isPrimary) {
+        synchronized (mApproved) {
+            ArrayMap<Boolean, ArraySet<String>> approvedByType = mApproved.get(userId);
+            if (approvedByType == null) {
+                approvedByType = new ArrayMap<>();
+                mApproved.put(userId, approvedByType);
+            }
+            approvedByType.put(isPrimary, new ArraySet<>());
+        }
+    }
+
     protected boolean isComponentEnabledForPackage(String pkg) {
         synchronized (mMutex) {
             return mEnabledServicesPackageNames.contains(pkg);
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 6c2d4f7..88334eb 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -12577,18 +12577,31 @@
 
                         // Checks if this is a request to notify system UI about a notification that
                         // has been lifetime extended.
-                        // (We only need to check old for the flag, because in both cancellation and
-                        // update cases, old should have the flag, whereas in update cases the
-                        // new will NOT have the flag.)
-                        // If it is such a request, and this is system UI, we send the post request
-                        // only to System UI, and break as we don't need to continue checking other
-                        // Managed Services.
-                        if (info.isSystemUi() && old != null && old.getNotification() != null
+                        // We check both old and new for the flag, to avoid catching updates
+                        // (where new will not have the flag).
+                        // If it is such a request, and this is the system UI listener, we send
+                        // the post request. If it's any other listener, we skip it.
+                        if (old != null && old.getNotification() != null
                                 && (old.getNotification().flags
+                                & FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY) > 0
+                                && sbn != null && sbn.getNotification() != null
+                                && (sbn.getNotification().flags
                                 & FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY) > 0) {
-                            final NotificationRankingUpdate update = makeRankingUpdateLocked(info);
-                            listenerCalls.add(() -> notifyPosted(info, sbnToPost, update));
-                            break;
+                            if (info.isSystemUi()) {
+                                final NotificationRankingUpdate update =
+                                        makeRankingUpdateLocked(info);
+                                listenerCalls.add(() -> notifyPosted(info, sbnToPost, update));
+                                break;
+                            } else {
+                                // Skipping because this is the direct-reply "update" and we only
+                                // need to send it to sysui, so we immediately continue, before it
+                                // can get sent to other listeners below.
+                                if (DBG) {
+                                    Slog.d(TAG, "prepareNotifyPostedLocked: direct reply update, "
+                                            + "skipping post to " + info.toString());
+                                }
+                                continue;
+                            }
                         }
                     }
 
diff --git a/services/core/java/com/android/server/notification/PreferencesHelper.java b/services/core/java/com/android/server/notification/PreferencesHelper.java
index 9e70f81..3349b13 100644
--- a/services/core/java/com/android/server/notification/PreferencesHelper.java
+++ b/services/core/java/com/android/server/notification/PreferencesHelper.java
@@ -1986,6 +1986,7 @@
      * bypassing DND. It should be called whenever a channel is created, updated, or deleted, or
      * when the current user (or its profiles) change.
      */
+    // TODO: b/368247671 - remove fromSystemOrSystemUi argument when modes_ui is inlined.
     private void updateCurrentUserHasChannelsBypassingDnd(int callingUid,
             boolean fromSystemOrSystemUi) {
         ArraySet<Pair<String, Integer>> candidatePkgs = new ArraySet<>();
@@ -2016,7 +2017,12 @@
         boolean haveBypassingApps = candidatePkgs.size() > 0;
         if (mCurrentUserHasChannelsBypassingDnd != haveBypassingApps) {
             mCurrentUserHasChannelsBypassingDnd = haveBypassingApps;
-            updateZenPolicy(mCurrentUserHasChannelsBypassingDnd, callingUid, fromSystemOrSystemUi);
+            if (android.app.Flags.modesUi()) {
+                mZenModeHelper.updateHasPriorityChannels(mCurrentUserHasChannelsBypassingDnd);
+            } else {
+                updateZenPolicy(mCurrentUserHasChannelsBypassingDnd, callingUid,
+                        fromSystemOrSystemUi);
+            }
         }
     }
 
@@ -2034,6 +2040,9 @@
         return true;
     }
 
+    // TODO: b/368247671 - delete this method when modes_ui is inlined, as
+    //                     updateCurrentUserHasChannelsBypassingDnd was the only caller and
+    //                     PreferencesHelper should otherwise not need to modify actual policy
     public void updateZenPolicy(boolean areChannelsBypassingDnd, int callingUid,
             boolean fromSystemOrSystemUi) {
         NotificationManager.Policy policy = mZenModeHelper.getNotificationPolicy();
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index ea211a9..5547bd3 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -1567,6 +1567,28 @@
         return azr;
     }
 
+    // Update only the hasPriorityChannels state (aka areChannelsBypassingDnd) without modifying
+    // any of the rest of the existing policy. This allows components that only want to modify
+    // this bit (PreferencesHelper) to not have to adjust the rest of the policy.
+    protected void updateHasPriorityChannels(boolean hasPriorityChannels) {
+        if (!Flags.modesUi()) {
+            Log.wtf(TAG, "updateHasPriorityChannels called without modes_ui");
+        }
+        synchronized (mConfigLock) {
+            // If it already matches, do nothing
+            if (mConfig.areChannelsBypassingDnd == hasPriorityChannels) {
+                return;
+            }
+
+            ZenModeConfig newConfig = mConfig.copy();
+            newConfig.areChannelsBypassingDnd = hasPriorityChannels;
+            // The updated calculation of whether there are priority channels is always done by
+            // the system, even if the event causing the calculation had a different origin.
+            setConfigLocked(newConfig, null, ORIGIN_SYSTEM, "updateHasPriorityChannels",
+                    Process.SYSTEM_UID);
+        }
+    }
+
     @SuppressLint("MissingPermission")
     void scheduleActivationBroadcast(String pkg, @UserIdInt int userId, String ruleId,
             boolean activated) {
diff --git a/services/core/java/com/android/server/notification/flags.aconfig b/services/core/java/com/android/server/notification/flags.aconfig
index 0b34177..a24c743 100644
--- a/services/core/java/com/android/server/notification/flags.aconfig
+++ b/services/core/java/com/android/server/notification/flags.aconfig
@@ -180,3 +180,10 @@
     purpose: PURPOSE_BUGFIX
   }
 }
+
+flag {
+  name: "notification_vibration_in_sound_uri_for_channel"
+  namespace: "systemui"
+  description: "Enables sound uri with vibration source in notification channel"
+  bug: "351975435"
+}
diff --git a/services/core/java/com/android/server/ondeviceintelligence/OnDeviceIntelligenceManagerService.java b/services/core/java/com/android/server/ondeviceintelligence/OnDeviceIntelligenceManagerService.java
index 03a34f2..b0d69e6 100644
--- a/services/core/java/com/android/server/ondeviceintelligence/OnDeviceIntelligenceManagerService.java
+++ b/services/core/java/com/android/server/ondeviceintelligence/OnDeviceIntelligenceManagerService.java
@@ -19,6 +19,8 @@
 import static android.service.ondeviceintelligence.OnDeviceSandboxedInferenceService.DEVICE_CONFIG_UPDATE_BUNDLE_KEY;
 import static android.service.ondeviceintelligence.OnDeviceSandboxedInferenceService.MODEL_LOADED_BUNDLE_KEY;
 import static android.service.ondeviceintelligence.OnDeviceSandboxedInferenceService.MODEL_UNLOADED_BUNDLE_KEY;
+import static android.service.ondeviceintelligence.OnDeviceSandboxedInferenceService.MODEL_LOADED_BROADCAST_INTENT;
+import static android.service.ondeviceintelligence.OnDeviceSandboxedInferenceService.MODEL_UNLOADED_BROADCAST_INTENT;
 import static android.service.ondeviceintelligence.OnDeviceSandboxedInferenceService.REGISTER_MODEL_UPDATE_CALLBACK_BUNDLE_KEY;
 
 import static com.android.server.ondeviceintelligence.BundleUtil.sanitizeInferenceParams;
@@ -154,7 +156,7 @@
     @GuardedBy("mLock")
     private String[] mTemporaryBroadcastKeys;
     @GuardedBy("mLock")
-    private String mBroadcastPackageName;
+    private String mBroadcastPackageName = SYSTEM_PACKAGE;
     @GuardedBy("mLock")
     private String mTemporaryConfigNamespace;
 
@@ -921,10 +923,7 @@
             }
         }
 
-        return new String[]{mContext.getResources().getString(
-                R.string.config_onDeviceIntelligenceModelLoadedBroadcastKey),
-                mContext.getResources().getString(
-                        R.string.config_onDeviceIntelligenceModelUnloadedBroadcastKey)};
+        return new String[]{ MODEL_LOADED_BROADCAST_INTENT, MODEL_UNLOADED_BROADCAST_INTENT };
     }
 
     @RequiresPermission(Manifest.permission.USE_ON_DEVICE_INTELLIGENCE)
diff --git a/services/core/java/com/android/server/os/NativeTombstoneManager.java b/services/core/java/com/android/server/os/NativeTombstoneManager.java
index 3bcaf58..f23d782 100644
--- a/services/core/java/com/android/server/os/NativeTombstoneManager.java
+++ b/services/core/java/com/android/server/os/NativeTombstoneManager.java
@@ -96,12 +96,15 @@
         mHandler = thread.getThreadHandler();
 
         mWatcher = new TombstoneWatcher();
-        mWatcher.startWatching();
     }
 
     void onSystemReady() {
         registerForUserRemoval();
         registerForPackageRemoval();
+        // TombstoneWatcher depends on DropboxManagerService.
+        // DropboxManagerService started before systemReady.
+        // So it is good to call startWatching here.
+        mWatcher.startWatching();
 
         BootReceiver.initDropboxRateLimiter();
 
diff --git a/services/core/java/com/android/server/pm/ApexManager.java b/services/core/java/com/android/server/pm/ApexManager.java
index 5d71439e..458b46d 100644
--- a/services/core/java/com/android/server/pm/ApexManager.java
+++ b/services/core/java/com/android/server/pm/ApexManager.java
@@ -592,7 +592,7 @@
                 return apexSessionInfo;
             } catch (RemoteException re) {
                 Slog.e(TAG, "Unable to contact apexservice", re);
-                throw new RuntimeException(re);
+                return null;
             }
         }
 
@@ -607,7 +607,7 @@
                 return result;
             } catch (RemoteException re) {
                 Slog.e(TAG, "Unable to contact apexservice", re);
-                throw new RuntimeException(re);
+                return new SparseArray<>(0);
             }
         }
 
@@ -619,7 +619,9 @@
                 return apexInfoList;
             } catch (RemoteException re) {
                 Slog.e(TAG, "Unable to contact apexservice", re);
-                throw new RuntimeException(re);
+                throw new PackageManagerException(
+                        PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE,
+                        "apexd verification failed : " + re.getMessage());
             } catch (Exception e) {
                 throw new PackageManagerException(
                         PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE,
@@ -633,7 +635,7 @@
                 return waitForApexService().getStagedApexInfos(params);
             } catch (RemoteException re) {
                 Slog.w(TAG, "Unable to contact apexservice" + re.getMessage());
-                throw new RuntimeException(re);
+                return new ApexInfo[0];
             } catch (Exception e) {
                 Slog.w(TAG, "Failed to collect staged apex infos" + e.getMessage());
                 return new ApexInfo[0];
@@ -646,7 +648,9 @@
                 waitForApexService().markStagedSessionReady(sessionId);
             } catch (RemoteException re) {
                 Slog.e(TAG, "Unable to contact apexservice", re);
-                throw new RuntimeException(re);
+                throw new PackageManagerException(
+                        PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE,
+                        "Failed to mark apexd session as ready : " + re.getMessage());
             } catch (Exception e) {
                 throw new PackageManagerException(
                         PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE,
diff --git a/services/core/java/com/android/server/pm/ComputerEngine.java b/services/core/java/com/android/server/pm/ComputerEngine.java
index 4665a72..be7631d 100644
--- a/services/core/java/com/android/server/pm/ComputerEngine.java
+++ b/services/core/java/com/android/server/pm/ComputerEngine.java
@@ -2768,7 +2768,8 @@
             enforceCrossUserPermission(Binder.getCallingUid(), userId, false, false,
                     !isRecentsAccessingChildProfiles(Binder.getCallingUid(), userId),
                     "MATCH_ANY_USER flag requires INTERACT_ACROSS_USERS permission");
-        } else if ((flags & PackageManager.MATCH_UNINSTALLED_PACKAGES) != 0
+        } else if (!Flags.removeCrossUserPermissionHack()
+                && (flags & PackageManager.MATCH_UNINSTALLED_PACKAGES) != 0
                 && isCallerSystemUser
                 && mUserManager.hasProfile(UserHandle.USER_SYSTEM)) {
             // If the caller wants all packages and has a profile associated with it,
@@ -5144,10 +5145,28 @@
         }
 
         updateOwnerPackageName = installSource.mUpdateOwnerPackageName;
+
+        if (DEBUG_INSTALL) {
+            Log.d(TAG, "ComputerEngine getInstallSourceInfo updateOwnerPackageName = "
+                    + updateOwnerPackageName + ", callingUid = " + callingUid + ", packageName = "
+                    + packageName + ", userId = " + userId);
+        }
+
         if (updateOwnerPackageName != null) {
             final PackageStateInternal ps = mSettings.getPackage(updateOwnerPackageName);
             final boolean isCallerSystemOrUpdateOwner = callingUid == Process.SYSTEM_UID
                             || isCallerSameApp(updateOwnerPackageName, callingUid);
+
+            if (DEBUG_INSTALL) {
+                Log.d(TAG, "ComputerEngine getInstallSourceInfo ps = "
+                        + ps + ", isCallerSystemOrUpdateOwner =" + isCallerSystemOrUpdateOwner
+                        + ", isCallerSameApp = "
+                        + isCallerSameApp(updateOwnerPackageName, callingUid) + ", filter = "
+                        + shouldFilterApplicationIncludingUninstalled(ps, callingUid, userId)
+                        + ", FromManagedUserOrProfile = "
+                        + isCallerFromManagedUserOrProfile(userId));
+            }
+
             // Except for package visibility filtering, we also hide update owner if the installer
             // is in the managed user or profile. As we don't enforce the update ownership for the
             // managed user and profile, knowing there's an update owner is meaningless in that
@@ -5159,6 +5178,11 @@
             }
         }
 
+        if (DEBUG_INSTALL) {
+            Log.d(TAG, "ComputerEngine getInstallSourceInfo updateOwnerPackageName = "
+                    + updateOwnerPackageName);
+        }
+
         if (installSource.mIsInitiatingPackageUninstalled) {
             // We can't check visibility in the usual way, since the initiating package is no
             // longer present. So we apply simpler rules to whether to expose the info:
diff --git a/services/core/java/com/android/server/pm/InstallRequest.java b/services/core/java/com/android/server/pm/InstallRequest.java
index 1f79ac0..089bbb7 100644
--- a/services/core/java/com/android/server/pm/InstallRequest.java
+++ b/services/core/java/com/android/server/pm/InstallRequest.java
@@ -16,7 +16,6 @@
 
 package com.android.server.pm;
 
-import static android.content.pm.Flags.improveInstallFreeze;
 import static android.content.pm.PackageInstaller.SessionParams.USER_ACTION_UNSPECIFIED;
 import static android.content.pm.PackageManager.INSTALL_REASON_UNKNOWN;
 import static android.content.pm.PackageManager.INSTALL_SCENARIO_DEFAULT;
@@ -1050,13 +1049,13 @@
     }
 
     public void onFreezeStarted() {
-        if (mPackageMetrics != null && improveInstallFreeze()) {
+        if (mPackageMetrics != null) {
             mPackageMetrics.onStepStarted(PackageMetrics.STEP_FREEZE_INSTALL);
         }
     }
 
     public void onFreezeCompleted() {
-        if (mPackageMetrics != null && improveInstallFreeze()) {
+        if (mPackageMetrics != null) {
             mPackageMetrics.onStepFinished(PackageMetrics.STEP_FREEZE_INSTALL);
         }
     }
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index c581622..9e0ba84 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -109,6 +109,7 @@
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.PackageInfoFlags;
 import android.content.pm.PackageManagerInternal;
+import android.content.pm.SharedLibraryInfo;
 import android.content.pm.SigningDetails;
 import android.content.pm.SigningInfo;
 import android.content.pm.dex.DexMetadataHelper;
@@ -2840,19 +2841,38 @@
             // since installation is in progress.
             activate();
         }
+        try {
+            List<PackageInstallerSession> children = getChildSessions();
+            if (isMultiPackage()) {
+                for (PackageInstallerSession child : children) {
+                    child.prepareInheritedFiles();
+                    child.parseApk();
+                }
+            } else {
+                prepareInheritedFiles();
+                parseApk();
+            }
+        }  catch (PackageManagerException e) {
+            final String completeMsg = ExceptionUtils.getCompleteMessage(e);
+            final String errorMsg = PackageManager.installStatusToString(e.error, completeMsg);
+            setSessionFailed(e.error, errorMsg);
+            onSessionVerificationFailure(e.error, errorMsg);
+        }
         if (Flags.verificationService()) {
             final Supplier<Computer> snapshotSupplier = mPm::snapshotComputer;
             if (mVerifierController.isVerifierInstalled(snapshotSupplier, userId)) {
-                // TODO: extract shared library declarations
                 final SigningInfo signingInfo;
+                final List<SharedLibraryInfo> declaredLibraries;
                 synchronized (mLock) {
                     signingInfo = new SigningInfo(mSigningDetails);
+                    declaredLibraries =
+                            mPackageLite == null ? null : mPackageLite.getDeclaredLibraries();
                 }
                 // Send the request to the verifier and wait for its response before the rest of
                 // the installation can proceed.
                 if (!mVerifierController.startVerificationSession(snapshotSupplier, userId,
-                        sessionId, params.appPackageName, Uri.fromFile(stageDir), signingInfo,
-                        /* declaredLibraries= */null, /* extensionParams= */ null,
+                        sessionId, getPackageName(), Uri.fromFile(stageDir), signingInfo,
+                        declaredLibraries, /* extensionParams= */ null,
                         new VerifierCallback(), /* retry= */ false)) {
                     // A verifier is installed but cannot be connected. Installation disallowed.
                     onSessionVerificationFailure(INSTALL_FAILED_INTERNAL_ERROR,
@@ -2887,12 +2907,10 @@
             List<PackageInstallerSession> children = getChildSessions();
             if (isMultiPackage()) {
                 for (PackageInstallerSession child : children) {
-                    child.prepareInheritedFiles();
-                    child.parseApkAndExtractNativeLibraries();
+                    child.extractNativeLibraries();
                 }
             } else {
-                prepareInheritedFiles();
-                parseApkAndExtractNativeLibraries();
+                extractNativeLibraries();
             }
             verifyNonStaged();
         } catch (PackageManagerException e) {
@@ -3069,7 +3087,7 @@
         mStageDirInUse = true;
     }
 
-    private void parseApkAndExtractNativeLibraries() throws PackageManagerException {
+    private void parseApk() throws PackageManagerException {
         synchronized (mLock) {
             if (mStageDirInUse) {
                 throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
@@ -3102,12 +3120,16 @@
                 // stage dir here.
                 // Besides, PackageLite may be null for staged sessions that don't complete
                 // pre-reboot verification.
-                result = getOrParsePackageLiteLocked(stageDir, /* flags */ 0);
+                mPackageLite = getOrParsePackageLiteLocked(stageDir, /* flags */ 0);
             } else {
-                result = getOrParsePackageLiteLocked(mResolvedBaseFile, /* flags */ 0);
+                mPackageLite = getOrParsePackageLiteLocked(mResolvedBaseFile, /* flags */ 0);
             }
-            if (result != null) {
-                mPackageLite = result;
+        }
+    }
+
+    private void extractNativeLibraries() throws PackageManagerException {
+        synchronized (mLock) {
+            if (mPackageLite != null) {
                 if (!isApexSession()) {
                     synchronized (mProgressLock) {
                         mInternalProgress = 0.5f;
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 611e0d8..4557769 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -204,7 +204,6 @@
 import com.android.server.LocalManagerRegistry;
 import com.android.server.LocalServices;
 import com.android.server.LockGuard;
-import com.android.server.PackageWatchdog;
 import com.android.server.ServiceThread;
 import com.android.server.SystemConfig;
 import com.android.server.ThreadPriorityBooster;
@@ -214,6 +213,7 @@
 import com.android.server.art.model.DeleteResult;
 import com.android.server.compat.CompatChange;
 import com.android.server.compat.PlatformCompat;
+import com.android.server.crashrecovery.CrashRecoveryAdaptor;
 import com.android.server.pm.Installer.InstallerException;
 import com.android.server.pm.Settings.VersionInfo;
 import com.android.server.pm.dex.ArtManagerService;
@@ -3048,7 +3048,7 @@
         mDexManager.writePackageDexUsageNow();
         mDynamicCodeLogger.writeNow();
         if (!refactorCrashrecovery()) {
-            PackageWatchdog.getInstance(mContext).writeNow();
+            CrashRecoveryAdaptor.packageWatchdogWriteNow(mContext);
         }
 
         synchronized (mLock) {
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 8bab9de..daf413b 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -1101,23 +1101,14 @@
         if (android.multiuser.Flags.cachesNotInvalidatedAtStartReadOnly()) {
             UserManager.invalidateIsUserUnlockedCache();
             UserManager.invalidateQuietModeEnabledCache();
-            UserManager.invalidateUserSerialNumberCache();
+            if (android.multiuser.Flags.cacheUserPropertiesCorrectlyReadOnly()) {
+                UserManager.invalidateStaticUserProperties();
+                UserManager.invalidateUserPropertiesCache();
+            }
+            UserManager.invalidateCacheOnUserListChange();
         }
     }
 
-    private boolean doesDeviceHardwareSupportPrivateSpace() {
-        return !mPm.hasSystemFeature(FEATURE_EMBEDDED, 0)
-                && !mPm.hasSystemFeature(FEATURE_WATCH, 0)
-                && !mPm.hasSystemFeature(FEATURE_LEANBACK, 0)
-                && !mPm.hasSystemFeature(FEATURE_AUTOMOTIVE, 0);
-    }
-
-    private static boolean isAutoLockForPrivateSpaceEnabled() {
-        return android.os.Flags.allowPrivateProfile()
-                && Flags.supportAutolockForPrivateSpace()
-                && android.multiuser.Flags.enablePrivateSpaceFeatures();
-    }
-
     void systemReady() {
         mAppOpsService = IAppOpsService.Stub.asInterface(
                 ServiceManager.getService(Context.APP_OPS_SERVICE));
@@ -1162,6 +1153,19 @@
         }
     }
 
+    private boolean doesDeviceHardwareSupportPrivateSpace() {
+        return !mPm.hasSystemFeature(FEATURE_EMBEDDED, 0)
+                && !mPm.hasSystemFeature(FEATURE_WATCH, 0)
+                && !mPm.hasSystemFeature(FEATURE_LEANBACK, 0)
+                && !mPm.hasSystemFeature(FEATURE_AUTOMOTIVE, 0);
+    }
+
+    private static boolean isAutoLockForPrivateSpaceEnabled() {
+        return android.os.Flags.allowPrivateProfile()
+                && Flags.supportAutolockForPrivateSpace()
+                && android.multiuser.Flags.enablePrivateSpaceFeatures();
+    }
+
     private boolean isAutoLockingPrivateSpaceOnRestartsEnabled() {
         return android.os.Flags.allowPrivateProfile()
                 && android.multiuser.Flags.enablePrivateSpaceAutolockOnRestarts()
@@ -4448,7 +4452,7 @@
 
                             if (userData != null) {
                                 synchronized (mUsersLock) {
-                                    mUsers.put(userData.info.id, userData);
+                                    addUserDataLU(userData);
                                     if (mNextSerialNumber < 0
                                             || mNextSerialNumber <= userData.info.id) {
                                         mNextSerialNumber = userData.info.id + 1;
@@ -5724,7 +5728,7 @@
                     userData.info = userInfo;
                     userData.userProperties = new UserProperties(
                             userTypeDetails.getDefaultUserPropertiesReference());
-                    mUsers.put(userId, userData);
+                    addUserDataLU(userData);
                 }
                 writeUserLP(userData);
                 writeUserListLP();
@@ -6138,7 +6142,7 @@
         final UserData userData = new UserData();
         userData.info = userInfo;
         synchronized (mUsersLock) {
-            mUsers.put(userInfo.id, userData);
+            addUserDataLU(userData);
         }
         updateUserIds();
         return userData;
@@ -6148,8 +6152,7 @@
     @VisibleForTesting
     void removeUserInfo(@UserIdInt int userId) {
         synchronized (mUsersLock) {
-            UserManager.invalidateUserSerialNumberCache();
-            mUsers.remove(userId);
+            removeUserDataLU(userId);
         }
     }
 
@@ -6579,8 +6582,7 @@
 
         // Remove this user from the list
         synchronized (mUsersLock) {
-            UserManager.invalidateUserSerialNumberCache();
-            mUsers.remove(userId);
+            removeUserDataLU(userId);
             mIsUserManaged.delete(userId);
         }
         synchronized (mUserStates) {
@@ -6969,6 +6971,26 @@
     }
 
     /**
+     * Adding user data to mUsers list in one place to invalidate related caches.
+     */
+    @GuardedBy("mUsersLock")
+    private void addUserDataLU(UserData userData) {
+        if (android.multiuser.Flags.invalidateCacheOnUsersChangedReadOnly()) {
+            UserManager.invalidateCacheOnUserListChange();
+        }
+        mUsers.put(userData.info.id, userData);
+    }
+
+    /**
+     * Removing user data to mUsers list in one place to invalidate related caches.
+     */
+    @GuardedBy("mUsersLock")
+    private void removeUserDataLU(@UserIdInt int userId) {
+        UserManager.invalidateCacheOnUserListChange();
+        mUsers.remove(userId);
+    }
+
+    /**
      * Caches the list of user ids in an array, adjusting the array size when necessary.
      */
     private void updateUserIds() {
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index e47b4c2..ad5c840 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -731,7 +731,10 @@
                     KeyEvent.KEYCODE_ASSIST,
                     KeyEvent.KEYCODE_VOICE_ASSIST,
                     KeyEvent.KEYCODE_MUTE,
-                    KeyEvent.KEYCODE_VOLUME_MUTE
+                    KeyEvent.KEYCODE_VOLUME_MUTE,
+                    KeyEvent.KEYCODE_RECENT_APPS,
+                    KeyEvent.KEYCODE_APP_SWITCH,
+                    KeyEvent.KEYCODE_NOTIFICATION
             ));
 
     private static final int MSG_DISPATCH_MEDIA_KEY_WITH_WAKE_LOCK = 3;
@@ -2082,12 +2085,21 @@
             }
             switch (mDoubleTapOnHomeBehavior) {
                 case DOUBLE_TAP_HOME_RECENT_SYSTEM_UI:
+                    if (!isKeyEventForCurrentUser(
+                            event.getDisplayId(), event.getKeyCode(), "toggleRecentApps")) {
+                        break;
+                    }
                     notifyKeyGestureCompleted(event,
                             KeyGestureEvent.KEY_GESTURE_TYPE_APP_SWITCH);
                     mHomeConsumed = true;
                     toggleRecentApps();
                     break;
                 case DOUBLE_TAP_HOME_PIP_MENU:
+                    if (!isKeyEventForCurrentUser(
+                            event.getDisplayId(), event.getKeyCode(),
+                            "showPictureInPictureMenu")) {
+                        break;
+                    }
                     mHomeConsumed = true;
                     showPictureInPictureMenuInternal();
                     break;
@@ -2116,12 +2128,20 @@
                     }
                     break;
                 case LONG_PRESS_HOME_ASSIST:
+                    if (!isKeyEventForCurrentUser(
+                            event.getDisplayId(), event.getKeyCode(), "launchAssistAction")) {
+                        break;
+                    }
                     notifyKeyGestureCompleted(event,
                             KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_ASSISTANT);
                     launchAssistAction(null, event.getDeviceId(), event.getEventTime(),
                             AssistUtils.INVOCATION_TYPE_HOME_BUTTON_LONG_PRESS);
                     break;
                 case LONG_PRESS_HOME_NOTIFICATION_PANEL:
+                    if (!isKeyEventForCurrentUser(
+                            event.getDisplayId(), event.getKeyCode(), "toggleNotificationPanel")) {
+                        break;
+                    }
                     notifyKeyGestureCompleted(event,
                             KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_NOTIFICATION_PANEL);
                     toggleNotificationPanel();
@@ -3497,7 +3517,11 @@
 
         if (isUserSetupComplete() && !keyguardOn) {
             if (mModifierShortcutManager.interceptKey(event)) {
-                dismissKeyboardShortcutsMenu();
+                if (isKeyEventForCurrentUser(
+                        event.getDisplayId(), event.getKeyCode(),
+                        "dismissKeyboardShortcutsMenu")) {
+                    dismissKeyboardShortcutsMenu();
+                }
                 mPendingMetaAction = false;
                 mPendingCapsLockToggle = false;
                 return true;
@@ -4820,7 +4844,10 @@
         }
 
         // no keyguard stuff to worry about, just launch home!
-        if (mRecentsVisible) {
+        // If Recents is visible and the action is not from visible background users,
+        // hide Recents and notify it to launch Home.
+        if (mRecentsVisible
+                && (!mVisibleBackgroundUsersEnabled || displayId == DEFAULT_DISPLAY)) {
             try {
                 ActivityManager.getService().stopAppSwitches();
             } catch (RemoteException e) {}
@@ -5570,6 +5597,9 @@
      * Notify the StatusBar that a system key was pressed.
      */
     private void sendSystemKeyToStatusBar(KeyEvent key) {
+        if (!isKeyEventForCurrentUser(key.getDisplayId(), key.getKeyCode(), "handleSystemKey")) {
+            return;
+        }
         IStatusBarService statusBar = getStatusBarService();
         if (statusBar != null) {
             try {
diff --git a/services/core/java/com/android/server/power/feature/PowerManagerFlags.java b/services/core/java/com/android/server/power/feature/PowerManagerFlags.java
index fd60e06..db57d11 100644
--- a/services/core/java/com/android/server/power/feature/PowerManagerFlags.java
+++ b/services/core/java/com/android/server/power/feature/PowerManagerFlags.java
@@ -47,6 +47,9 @@
             Flags::perDisplayWakeByTouch
     );
 
+    private final FlagState mFrameworkWakelockInfo =
+            new FlagState(Flags.FLAG_FRAMEWORK_WAKELOCK_INFO, Flags::frameworkWakelockInfo);
+
     /** Returns whether early-screen-timeout-detector is enabled on not. */
     public boolean isEarlyScreenTimeoutDetectorEnabled() {
         return mEarlyScreenTimeoutDetectorFlagState.isEnabled();
@@ -67,6 +70,13 @@
     }
 
     /**
+     * @return Whether FrameworkWakelockInfo atom logging is enabled or not.
+     */
+    public boolean isFrameworkWakelockInfoEnabled() {
+        return mFrameworkWakelockInfo.isEnabled();
+    }
+
+    /**
      * dumps all flagstates
      * @param pw printWriter
      */
@@ -75,6 +85,7 @@
         pw.println(" " + mEarlyScreenTimeoutDetectorFlagState);
         pw.println(" " + mImproveWakelockLatency);
         pw.println(" " + mPerDisplayWakeByTouch);
+        pw.println(" " + mFrameworkWakelockInfo);
     }
 
     private static class FlagState {
diff --git a/services/core/java/com/android/server/power/feature/power_flags.aconfig b/services/core/java/com/android/server/power/feature/power_flags.aconfig
index 9cf3bb6..8bb69ba 100644
--- a/services/core/java/com/android/server/power/feature/power_flags.aconfig
+++ b/services/core/java/com/android/server/power/feature/power_flags.aconfig
@@ -26,3 +26,10 @@
     bug: "343295183"
     is_fixed_read_only: true
 }
+
+flag {
+    name: "framework_wakelock_info"
+    namespace: "power"
+    description: "Feature flag to enable statsd pulling of FrameworkWakelockInfo atoms"
+    bug: "352602149"
+}
diff --git a/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java b/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java
index 936fadf..391071f 100644
--- a/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java
+++ b/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java
@@ -145,6 +145,7 @@
 import com.android.modules.utils.TypedXmlPullParser;
 import com.android.modules.utils.TypedXmlSerializer;
 import com.android.server.LocalServices;
+import com.android.server.power.feature.PowerManagerFlags;
 import com.android.server.power.optimization.Flags;
 import com.android.server.power.stats.SystemServerCpuThreadReader.SystemServiceCpuThreadTimes;
 import com.android.server.power.stats.format.MobileRadioPowerStatsLayout;
@@ -5142,6 +5143,10 @@
             mFrameworkStatsLogger.wakelockStateChanged(mapIsolatedUid(uid), wc, name,
                     uidStats.mProcessState, true /* acquired */,
                     getPowerManagerWakeLockLevel(type));
+            if (mPowerManagerFlags.isFrameworkWakelockInfoEnabled()) {
+                mFrameworkEvents.noteStartWakeLock(
+                        mapIsolatedUid(uid), name, getPowerManagerWakeLockLevel(type), uptimeMs);
+            }
         }
     }
 
@@ -5187,6 +5192,10 @@
             mFrameworkStatsLogger.wakelockStateChanged(mapIsolatedUid(uid), wc, name,
                     uidStats.mProcessState, false/* acquired */,
                     getPowerManagerWakeLockLevel(type));
+            if (mPowerManagerFlags.isFrameworkWakelockInfoEnabled()) {
+                mFrameworkEvents.noteStopWakeLock(
+                        mapIsolatedUid(uid), name, getPowerManagerWakeLockLevel(type), uptimeMs);
+            }
 
             if (mappedUid != uid) {
                 // Decrement the ref count for the isolated uid and delete the mapping if uneeded.
@@ -11343,6 +11352,9 @@
         return mTmpCpuTimeInFreq;
     }
 
+    WakelockStatsFrameworkEvents mFrameworkEvents = new WakelockStatsFrameworkEvents();
+    PowerManagerFlags mPowerManagerFlags = new PowerManagerFlags();
+
     public BatteryStatsImpl(@NonNull BatteryStatsConfig config, @NonNull Clock clock,
             @NonNull MonotonicClock monotonicClock, @Nullable File systemDir,
             @NonNull Handler handler, @Nullable PlatformIdleStateCallback platformIdleStateCallback,
@@ -15964,6 +15976,10 @@
                 // Already plugged in. Schedule the long plug in alarm.
                 scheduleNextResetWhilePluggedInCheck();
             }
+
+            if (mPowerManagerFlags.isFrameworkWakelockInfoEnabled()) {
+                mFrameworkEvents.initialize(context);
+            }
         }
     }
 
@@ -16791,7 +16807,8 @@
         }
         int NSORPMS = in.readInt();
         if (NSORPMS > 10000) {
-            throw new ParcelFormatException("File corrupt: too many screen-off rpm stats " + NSORPMS);
+            throw new ParcelFormatException(
+                    "File corrupt: too many screen-off rpm stats " + NSORPMS);
         }
         for (int irpm = 0; irpm < NSORPMS; irpm++) {
             if (in.readInt() != 0) {
diff --git a/services/core/java/com/android/server/power/stats/WakelockStatsFrameworkEvents.java b/services/core/java/com/android/server/power/stats/WakelockStatsFrameworkEvents.java
new file mode 100644
index 0000000..c9693bd
--- /dev/null
+++ b/services/core/java/com/android/server/power/stats/WakelockStatsFrameworkEvents.java
@@ -0,0 +1,328 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.power.stats;
+
+import android.app.StatsManager;
+import android.content.Context;
+import android.os.SystemClock;
+import android.util.Log;
+import android.util.StatsEvent;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.ConcurrentUtils;
+import com.android.internal.util.FrameworkStatsLog;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+
+/** A class to initialise and log metrics pulled by statsd. */
+public class WakelockStatsFrameworkEvents {
+    // statsd has a dimensional limit on the number of different keys it can handle.
+    // Beyond that limit, statsd will drop data.
+    //
+    // When we have seem SUMMARY_THRESHOLD distinct (uid, tag, wakeLockLevel) keys,
+    // we start summarizing new keys as (uid, OVERFLOW_TAG, OVERFLOW_LEVEL) to
+    // reduce the number of keys we pass to statsd.
+    //
+    // When we reach MAX_WAKELOCK_DIMENSIONS distinct keys, we summarize all new keys
+    // as (OVERFLOW_UID, HARD_CAP_TAG, OVERFLOW_LEVEL) to hard cap the number of
+    // distinct keys we pass to statsd.
+    @VisibleForTesting public static final int SUMMARY_THRESHOLD = 500;
+    @VisibleForTesting public static final int MAX_WAKELOCK_DIMENSIONS = 1000;
+
+    @VisibleForTesting public static final int HARD_CAP_UID = -1;
+    @VisibleForTesting public static final String OVERFLOW_TAG = "*overflow*";
+    @VisibleForTesting public static final String HARD_CAP_TAG = "*overflow hard cap*";
+    @VisibleForTesting public static final int OVERFLOW_LEVEL = 1;
+
+    private static class WakeLockKey {
+        private int uid;
+        private String tag;
+        private int powerManagerWakeLockLevel;
+        private int hashCode;
+
+        WakeLockKey(int uid, String tag, int powerManagerWakeLockLevel) {
+            this.uid = uid;
+            this.tag = new String(tag);
+            this.powerManagerWakeLockLevel = powerManagerWakeLockLevel;
+
+            this.hashCode = Objects.hash(uid, tag, powerManagerWakeLockLevel);
+        }
+
+        int getUid() {
+            return uid;
+        }
+
+        String getTag() {
+            return tag;
+        }
+
+        int getPowerManagerWakeLockLevel() {
+            return powerManagerWakeLockLevel;
+        }
+
+        void setOverflow() {
+            tag = OVERFLOW_TAG;
+            powerManagerWakeLockLevel = OVERFLOW_LEVEL;
+            this.hashCode = Objects.hash(uid, tag, powerManagerWakeLockLevel);
+        }
+
+        void setHardCap() {
+            uid = HARD_CAP_UID;
+            tag = HARD_CAP_TAG;
+            powerManagerWakeLockLevel = OVERFLOW_LEVEL;
+            this.hashCode = Objects.hash(uid, tag, powerManagerWakeLockLevel);
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) return true;
+            if (o == null || !(o instanceof WakeLockKey)) return false;
+
+            WakeLockKey that = (WakeLockKey) o;
+            return uid == that.uid
+                    && tag.equals(that.tag)
+                    && powerManagerWakeLockLevel == that.powerManagerWakeLockLevel;
+        }
+
+        @Override
+        public int hashCode() {
+            return this.hashCode;
+        }
+    }
+
+    private static class WakeLockStats {
+        // accumulated uptime attributed to this WakeLock since boot, where overlap
+        // (including nesting) is ignored
+        public long uptimeMillis = 0;
+
+        // count of WakeLocks that have been acquired and then released
+        public long completedCount = 0;
+    }
+
+    private final Object mLock = new Object();
+
+    @GuardedBy("mLock")
+    private final Map<WakeLockKey, WakeLockStats> mWakeLockStats = new HashMap<>();
+
+    private static class WakeLockData {
+        // uptime millis when first acquired
+        public long acquireUptimeMillis = 0;
+        public int refCount = 0;
+
+        WakeLockData(long uptimeMillis) {
+            acquireUptimeMillis = uptimeMillis;
+        }
+    }
+
+    @GuardedBy("mLock")
+    private final Map<WakeLockKey, WakeLockData> mOpenWakeLocks = new HashMap<>();
+
+    public void noteStartWakeLock(
+            int uid, String tag, int powerManagerWakeLockLevel, long eventUptimeMillis) {
+        final WakeLockKey key = new WakeLockKey(uid, tag, powerManagerWakeLockLevel);
+
+        synchronized (mLock) {
+            WakeLockData data =
+                    mOpenWakeLocks.computeIfAbsent(key, k -> new WakeLockData(eventUptimeMillis));
+            data.refCount++;
+            mOpenWakeLocks.put(key, data);
+        }
+    }
+
+    @VisibleForTesting
+    public boolean inOverflow() {
+        synchronized (mLock) {
+            return inOverflowLocked();
+        }
+    }
+
+    @GuardedBy("mLock")
+    private boolean inOverflowLocked() {
+        return mWakeLockStats.size() >= SUMMARY_THRESHOLD;
+    }
+
+    @VisibleForTesting
+    public boolean inHardCap() {
+        synchronized (mLock) {
+            return inHardCapLocked();
+        }
+    }
+
+    @GuardedBy("mLock")
+    private boolean inHardCapLocked() {
+        return mWakeLockStats.size() >= MAX_WAKELOCK_DIMENSIONS;
+    }
+
+    public void noteStopWakeLock(
+            int uid, String tag, int powerManagerWakeLockLevel, long eventUptimeMillis) {
+        WakeLockKey key = new WakeLockKey(uid, tag, powerManagerWakeLockLevel);
+
+        synchronized (mLock) {
+            WakeLockData data = mOpenWakeLocks.get(key);
+            if (data == null) {
+                Log.e(TAG, "WakeLock not found when stopping: " + uid + " " + tag);
+                return;
+            }
+
+            if (data.refCount == 1) {
+                mOpenWakeLocks.remove(key);
+                long wakeLockDur = eventUptimeMillis - data.acquireUptimeMillis;
+
+                // Rewrite key if in an overflow state.
+                if (inOverflowLocked() && !mWakeLockStats.containsKey(key)) {
+                    key.setOverflow();
+                    if (inHardCapLocked() && !mWakeLockStats.containsKey(key)) {
+                        key.setHardCap();
+                    }
+                }
+
+                WakeLockStats stats = mWakeLockStats.computeIfAbsent(key, k -> new WakeLockStats());
+                stats.uptimeMillis += wakeLockDur;
+                stats.completedCount++;
+                mWakeLockStats.put(key, stats);
+            } else {
+                data.refCount--;
+                mOpenWakeLocks.put(key, data);
+            }
+        }
+    }
+
+    public List<StatsEvent> pullFrameworkWakelockInfoAtoms() {
+        return pullFrameworkWakelockInfoAtoms(SystemClock.uptimeMillis());
+    }
+
+    public List<StatsEvent> pullFrameworkWakelockInfoAtoms(long nowMillis) {
+        List<StatsEvent> result = new ArrayList<>();
+        HashSet<WakeLockKey> keys = new HashSet<>();
+
+        // Used to collect open WakeLocks when in an overflow state.
+        HashMap<WakeLockKey, WakeLockStats> openOverflowStats = new HashMap<>();
+
+        synchronized (mLock) {
+            keys.addAll(mWakeLockStats.keySet());
+
+            // If we are in an overflow state, an open wakelock may have a new key
+            // that needs to be summarized.
+            if (inOverflowLocked()) {
+                for (WakeLockKey key : mOpenWakeLocks.keySet()) {
+                    if (!mWakeLockStats.containsKey(key)) {
+                        WakeLockData data = mOpenWakeLocks.get(key);
+
+                        key.setOverflow();
+                        if (inHardCapLocked() && !mWakeLockStats.containsKey(key)) {
+                            key.setHardCap();
+                        }
+                        keys.add(key);
+
+                        WakeLockStats stats =
+                                openOverflowStats.computeIfAbsent(key, k -> new WakeLockStats());
+                        stats.uptimeMillis += nowMillis - data.acquireUptimeMillis;
+                        openOverflowStats.put(key, stats);
+                    }
+                }
+            } else {
+                keys.addAll(mOpenWakeLocks.keySet());
+            }
+
+            for (WakeLockKey key : keys) {
+                long openWakeLockUptime = 0;
+                WakeLockData data = mOpenWakeLocks.get(key);
+                if (data != null) {
+                    openWakeLockUptime = nowMillis - data.acquireUptimeMillis;
+                }
+
+                WakeLockStats stats = mWakeLockStats.computeIfAbsent(key, k -> new WakeLockStats());
+                WakeLockStats extraTime =
+                        openOverflowStats.computeIfAbsent(key, k -> new WakeLockStats());
+
+                stats.uptimeMillis += openWakeLockUptime + extraTime.uptimeMillis;
+
+                StatsEvent event =
+                        StatsEvent.newBuilder()
+                                .setAtomId(FrameworkStatsLog.FRAMEWORK_WAKELOCK_INFO)
+                                .writeInt(key.getUid())
+                                .writeString(key.getTag())
+                                .writeInt(key.getPowerManagerWakeLockLevel())
+                                .writeLong(stats.uptimeMillis)
+                                .writeLong(stats.completedCount)
+                                .build();
+                result.add(event);
+            }
+        }
+
+        return result;
+    }
+
+    private static final String TAG = "BatteryStatsPulledMetrics";
+
+    private final StatsPullCallbackHandler mStatsPullCallbackHandler =
+            new StatsPullCallbackHandler();
+
+    private boolean mIsInitialized = false;
+
+    public void initialize(Context context) {
+        if (mIsInitialized) {
+            return;
+        }
+
+        final StatsManager statsManager = context.getSystemService(StatsManager.class);
+        if (statsManager == null) {
+            Log.e(
+                    TAG,
+                    "Error retrieving StatsManager. Cannot initialize BatteryStatsPulledMetrics.");
+        } else {
+            Log.d(TAG, "Registering callback with StatsManager");
+
+            // DIRECT_EXECUTOR means that callback will run on binder thread.
+            statsManager.setPullAtomCallback(
+                    FrameworkStatsLog.FRAMEWORK_WAKELOCK_INFO,
+                    null /* metadata */,
+                    ConcurrentUtils.DIRECT_EXECUTOR,
+                    mStatsPullCallbackHandler);
+            mIsInitialized = true;
+        }
+    }
+
+    private class StatsPullCallbackHandler implements StatsManager.StatsPullAtomCallback {
+        @Override
+        public int onPullAtom(int atomTag, List<StatsEvent> data) {
+            // handle the tags appropriately.
+            List<StatsEvent> events = pullEvents(atomTag);
+            if (events == null) {
+                return StatsManager.PULL_SKIP;
+            }
+
+            data.addAll(events);
+            return StatsManager.PULL_SUCCESS;
+        }
+
+        private List<StatsEvent> pullEvents(int atomTag) {
+            switch (atomTag) {
+                case FrameworkStatsLog.FRAMEWORK_WAKELOCK_INFO:
+                    return pullFrameworkWakelockInfoAtoms();
+                default:
+                    return null;
+            }
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/rollback/Rollback.java b/services/core/java/com/android/server/rollback/Rollback.java
index 685ab3a..ab756f2 100644
--- a/services/core/java/com/android/server/rollback/Rollback.java
+++ b/services/core/java/com/android/server/rollback/Rollback.java
@@ -54,7 +54,7 @@
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.internal.util.Preconditions;
 import com.android.server.LocalServices;
-import com.android.server.RescueParty;
+import com.android.server.crashrecovery.CrashRecoveryAdaptor;
 import com.android.server.pm.pkg.AndroidPackage;
 
 import java.io.File;
@@ -627,7 +627,7 @@
 
             if (!deprecateFlagsAndSettingsResets()) {
                 // Clear flags.
-                RescueParty.resetDeviceConfigForPackages(packageNames);
+                CrashRecoveryAdaptor.rescuePartyResetDeviceConfigForPackages(packageNames);
             }
 
             Consumer<Intent> onResult = result -> {
diff --git a/services/core/java/com/android/server/search/SearchManagerService.java b/services/core/java/com/android/server/search/SearchManagerService.java
index 9b39fa1..a49a9fd 100644
--- a/services/core/java/com/android/server/search/SearchManagerService.java
+++ b/services/core/java/com/android/server/search/SearchManagerService.java
@@ -46,6 +46,7 @@
 import com.android.server.LocalServices;
 import com.android.server.SystemService;
 import com.android.server.SystemService.TargetUser;
+import com.android.server.pm.UserManagerInternal;
 import com.android.server.statusbar.StatusBarManagerInternal;
 
 import java.io.FileDescriptor;
@@ -89,6 +90,8 @@
     @GuardedBy("mSearchables")
     private final SparseArray<Searchables> mSearchables = new SparseArray<>();
 
+    private final UserManagerInternal mUserManagerInternal;
+
     /**
      * Initializes the Search Manager service in the provided system context.
      * Only one instance of this object should be created!
@@ -101,6 +104,7 @@
         mMyPackageMonitor.register(context, null, UserHandle.ALL, true);
         new GlobalSearchProviderObserver(context.getContentResolver());
         mHandler = BackgroundThread.getHandler();
+        mUserManagerInternal = LocalServices.getService(UserManagerInternal.class);
     }
 
     private Searchables getSearchables(int userId) {
@@ -336,6 +340,14 @@
 
     @Override
     public void launchAssist(int userHandle, Bundle args) {
+        // Currently, visible background users are not allowed to launch assist.(b/332222893)
+        // TODO(b/368715893): Consider indirect calls from system service when checking the
+        // calling user.
+        final int callingUserId = UserHandle.getCallingUserId();
+        if (mUserManagerInternal.isVisibleBackgroundFullUser(callingUserId)) {
+            throw new SecurityException("Visible background user(u" + callingUserId
+                    + ") is not permitted to launch assist.");
+        }
         StatusBarManagerInternal statusBarManager =
                 LocalServices.getService(StatusBarManagerInternal.class);
         if (statusBarManager != null) {
diff --git a/services/core/java/com/android/server/stats/bootstrap/StatsBootstrapAtomService.java b/services/core/java/com/android/server/stats/bootstrap/StatsBootstrapAtomService.java
index 0d420a5..dcb47a7 100644
--- a/services/core/java/com/android/server/stats/bootstrap/StatsBootstrapAtomService.java
+++ b/services/core/java/com/android/server/stats/bootstrap/StatsBootstrapAtomService.java
@@ -62,6 +62,9 @@
                 case StatsBootstrapAtomValue.bytesValue:
                     builder.writeByteArray(value.getBytesValue());
                     break;
+                case StatsBootstrapAtomValue.stringArrayValue:
+                    builder.writeStringArray(value.getStringArrayValue());
+                    break;
                 default:
                     Slog.e(TAG, "Unexpected value type " + value.getTag()
                             + " when logging atom " + atom.atomId);
diff --git a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
index 74c1124e..e7735d8 100644
--- a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
+++ b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
@@ -63,6 +63,7 @@
 import static com.android.internal.util.FrameworkStatsLog.TIME_ZONE_DETECTOR_STATE__DETECTION_MODE__TELEPHONY;
 import static com.android.internal.util.FrameworkStatsLog.TIME_ZONE_DETECTOR_STATE__DETECTION_MODE__UNKNOWN;
 import static com.android.server.am.MemoryStatUtil.readMemoryStatFromFilesystem;
+import static com.android.server.stats.Flags.accumulateNetworkStatsSinceBoot;
 import static com.android.server.stats.Flags.addMobileBytesTransferByProcStatePuller;
 import static com.android.server.stats.Flags.applyNetworkStatsPollRateLimit;
 import static com.android.server.stats.pull.IonMemoryUtil.readProcessSystemIonHeapSizesFromDebugfs;
@@ -229,6 +230,7 @@
 import com.android.server.power.stats.SystemServerCpuThreadReader.SystemServiceCpuThreadTimes;
 import com.android.server.stats.pull.IonMemoryUtil.IonAllocations;
 import com.android.server.stats.pull.ProcfsMemoryUtil.MemorySnapshot;
+import com.android.server.stats.pull.netstats.NetworkStatsAccumulator;
 import com.android.server.stats.pull.netstats.NetworkStatsExt;
 import com.android.server.stats.pull.netstats.SubInfo;
 import com.android.server.storage.DiskStatsFileLogger;
@@ -424,6 +426,14 @@
     @GuardedBy("mDataBytesTransferLock")
     private final ArrayList<NetworkStatsExt> mNetworkStatsBaselines = new ArrayList<>();
 
+    // Accumulates NetworkStats from initialization till the present moment.
+    // It is necessary to accumulate stats internally, because NetworkStats persists data for a
+    // limited amount of time, after which diff becomes incorrect without accumulation.
+    @NonNull
+    @GuardedBy("mDataBytesTransferLock")
+    private final ArrayList<NetworkStatsAccumulator> mNetworkStatsAccumulators =
+            new ArrayList<>();
+
     @GuardedBy("mDataBytesTransferLock")
     private long mLastNetworkStatsPollTime = -NETSTATS_POLL_RATE_LIMIT_MS;
 
@@ -1265,49 +1275,39 @@
             case FrameworkStatsLog.WIFI_BYTES_TRANSFER: {
                 final NetworkStats stats = getUidNetworkStatsSnapshotForTransportLocked(
                         TRANSPORT_WIFI);
-                if (stats != null) {
-                    ret.add(new NetworkStatsExt(sliceNetworkStatsByUid(stats),
-                            new int[]{TRANSPORT_WIFI}, /*slicedByFgbg=*/false));
-                }
+                ret.add(new NetworkStatsExt(sliceNetworkStatsByUid(stats),
+                        new int[]{TRANSPORT_WIFI}, /*slicedByFgbg=*/false));
                 break;
             }
             case FrameworkStatsLog.WIFI_BYTES_TRANSFER_BY_FG_BG: {
                 final NetworkStats stats = getUidNetworkStatsSnapshotForTransportLocked(
                         TRANSPORT_WIFI);
-                if (stats != null) {
-                    ret.add(new NetworkStatsExt(sliceNetworkStatsByUidAndFgbg(stats),
-                            new int[]{TRANSPORT_WIFI}, /*slicedByFgbg=*/true));
-                }
+                ret.add(new NetworkStatsExt(sliceNetworkStatsByUidAndFgbg(stats),
+                        new int[]{TRANSPORT_WIFI}, /*slicedByFgbg=*/true));
                 break;
             }
             case FrameworkStatsLog.MOBILE_BYTES_TRANSFER: {
                 final NetworkStats stats =
                         getUidNetworkStatsSnapshotForTransportLocked(TRANSPORT_CELLULAR);
-                if (stats != null) {
-                    ret.add(new NetworkStatsExt(sliceNetworkStatsByUid(stats),
-                            new int[]{TRANSPORT_CELLULAR}, /*slicedByFgbg=*/false));
-                }
+                ret.add(new NetworkStatsExt(sliceNetworkStatsByUid(stats),
+                        new int[]{TRANSPORT_CELLULAR}, /*slicedByFgbg=*/false));
                 break;
             }
             case FrameworkStatsLog.MOBILE_BYTES_TRANSFER_BY_FG_BG: {
                 final NetworkStats stats =
                         getUidNetworkStatsSnapshotForTransportLocked(TRANSPORT_CELLULAR);
-                if (stats != null) {
-                    ret.add(new NetworkStatsExt(sliceNetworkStatsByUidAndFgbg(stats),
-                            new int[]{TRANSPORT_CELLULAR}, /*slicedByFgbg=*/true));
-                }
+                ret.add(new NetworkStatsExt(sliceNetworkStatsByUidAndFgbg(stats),
+                        new int[]{TRANSPORT_CELLULAR}, /*slicedByFgbg=*/true));
                 break;
             }
             case FrameworkStatsLog.PROXY_BYTES_TRANSFER_BY_FG_BG: {
                 final NetworkStats stats = getUidNetworkStatsSnapshotForTemplateLocked(
                         new NetworkTemplate.Builder(MATCH_PROXY).build(),  /*includeTags=*/false);
-                if (stats != null) {
-                    ret.add(new NetworkStatsExt(sliceNetworkStatsByUidAndFgbg(stats),
-                            new int[]{TRANSPORT_BLUETOOTH},
-                            /*slicedByFgbg=*/true, /*slicedByTag=*/false,
-                            /*slicedByMetered=*/false, TelephonyManager.NETWORK_TYPE_UNKNOWN,
-                            /*subInfo=*/null, OEM_MANAGED_ALL, /*isTypeProxy=*/true));
-                }
+                ret.add(new NetworkStatsExt(sliceNetworkStatsByUidAndFgbg(stats),
+                        new int[]{TRANSPORT_BLUETOOTH},
+                        /*slicedByFgbg=*/true, /*slicedByTag=*/false,
+                        /*slicedByMetered=*/false, TelephonyManager.NETWORK_TYPE_UNKNOWN,
+                        /*subInfo=*/null, OEM_MANAGED_ALL, /*isTypeProxy=*/true));
                 break;
             }
             case FrameworkStatsLog.BYTES_TRANSFER_BY_TAG_AND_METERED: {
@@ -1316,14 +1316,12 @@
                 final NetworkStats cellularStats = getUidNetworkStatsSnapshotForTemplateLocked(
                         new NetworkTemplate.Builder(MATCH_MOBILE)
                                 .setMeteredness(METERED_YES).build(), /*includeTags=*/true);
-                if (wifiStats != null && cellularStats != null) {
-                    final NetworkStats stats = wifiStats.add(cellularStats);
-                    ret.add(new NetworkStatsExt(sliceNetworkStatsByUidTagAndMetered(stats),
-                            new int[]{TRANSPORT_WIFI, TRANSPORT_CELLULAR},
-                            /*slicedByFgbg=*/false, /*slicedByTag=*/true,
-                            /*slicedByMetered=*/true, TelephonyManager.NETWORK_TYPE_UNKNOWN,
-                            /*subInfo=*/null, OEM_MANAGED_ALL, /*isTypeProxy=*/false));
-                }
+                final NetworkStats stats = wifiStats.add(cellularStats);
+                ret.add(new NetworkStatsExt(sliceNetworkStatsByUidTagAndMetered(stats),
+                        new int[]{TRANSPORT_WIFI, TRANSPORT_CELLULAR},
+                        /*slicedByFgbg=*/false, /*slicedByTag=*/true,
+                        /*slicedByMetered=*/true, TelephonyManager.NETWORK_TYPE_UNKNOWN,
+                        /*subInfo=*/null, OEM_MANAGED_ALL, /*isTypeProxy=*/false));
                 break;
             }
             case FrameworkStatsLog.DATA_USAGE_BYTES_TRANSFER: {
@@ -1509,12 +1507,10 @@
                 final NetworkStats stats = getUidNetworkStatsSnapshotForTemplateLocked(
                         template, false);
                 final Integer transport = ruleAndTransport.second;
-                if (stats != null) {
-                    ret.add(new NetworkStatsExt(sliceNetworkStatsByUidAndFgbg(stats),
-                            new int[]{transport}, /*slicedByFgbg=*/true, /*slicedByTag=*/false,
-                            /*slicedByMetered=*/false, TelephonyManager.NETWORK_TYPE_UNKNOWN,
-                            /*subInfo=*/null, oemManaged, /*isTypeProxy=*/false));
-                }
+                ret.add(new NetworkStatsExt(sliceNetworkStatsByUidAndFgbg(stats),
+                        new int[]{transport}, /*slicedByFgbg=*/true, /*slicedByTag=*/false,
+                        /*slicedByMetered=*/false, TelephonyManager.NETWORK_TYPE_UNKNOWN,
+                        /*subInfo=*/null, oemManaged, /*isTypeProxy=*/false));
             }
         }
 
@@ -1525,7 +1521,7 @@
      * Create a snapshot of NetworkStats for a given transport.
      */
     @GuardedBy("mDataBytesTransferLock")
-    @Nullable
+    @NonNull
     private NetworkStats getUidNetworkStatsSnapshotForTransportLocked(int transport) {
         NetworkTemplate template = null;
         switch (transport) {
@@ -1564,20 +1560,49 @@
      * some traffic before boot.
      */
     @GuardedBy("mDataBytesTransferLock")
-    @Nullable
+    @NonNull
     private NetworkStats getUidNetworkStatsSnapshotForTemplateLocked(
             @NonNull NetworkTemplate template, boolean includeTags) {
         final long elapsedMillisSinceBoot = SystemClock.elapsedRealtime();
-        final long currentTimeInMillis = MICROSECONDS.toMillis(SystemClock.currentTimeMicro());
-        final long bucketDuration = Settings.Global.getLong(mContext.getContentResolver(),
+        final long currentTimeMillis = MICROSECONDS.toMillis(SystemClock.currentTimeMicro());
+        final long bootTimeMillis = currentTimeMillis - elapsedMillisSinceBoot;
+        final long bucketDurationMillis = Settings.Global.getLong(mContext.getContentResolver(),
                 NETSTATS_UID_BUCKET_DURATION, NETSTATS_UID_DEFAULT_BUCKET_DURATION_MS);
 
-        // Set startTime before boot so that NetworkStats includes at least one full bucket.
-        // Set endTime in the future so that NetworkStats includes everything in the active bucket.
-        final long startTime = currentTimeInMillis - elapsedMillisSinceBoot - bucketDuration;
-        final long endTime = currentTimeInMillis + bucketDuration;
+        if (accumulateNetworkStatsSinceBoot()) {
+            NetworkStatsAccumulator accumulator = CollectionUtils.find(
+                    mNetworkStatsAccumulators, it -> it.hasEqualParameters(template, includeTags));
+            if (accumulator == null) {
+                accumulator = new NetworkStatsAccumulator(
+                        template,
+                        includeTags,
+                        bucketDurationMillis,
+                        bootTimeMillis - bucketDurationMillis);
+                mNetworkStatsAccumulators.add(accumulator);
+            }
 
-        // NetworkStatsManager#forceUpdate updates stats for all networks
+            return accumulator.queryStats(currentTimeMillis,
+                    (aTemplate, aIncludeTags, aStartTime, aEndTime) -> {
+                        synchronized (mDataBytesTransferLock) {
+                            return getUidNetworkStatsSnapshotForTemplateLocked(aTemplate,
+                                    aIncludeTags, aStartTime, aEndTime);
+                        }
+                    });
+
+        } else {
+            // Set end time in the future to include all stats in the active bucket.
+            return getUidNetworkStatsSnapshotForTemplateLocked(
+                    template, includeTags,
+                    bootTimeMillis - bucketDurationMillis,
+                    currentTimeMillis + bucketDurationMillis);
+        }
+    }
+
+    @GuardedBy("mDataBytesTransferLock")
+    @NonNull
+    private NetworkStats getUidNetworkStatsSnapshotForTemplateLocked(
+            @NonNull NetworkTemplate template, boolean includeTags, long startTime, long endTime) {
+        final long elapsedMillisSinceBoot = SystemClock.elapsedRealtime();
         if (applyNetworkStatsPollRateLimit()) {
             // The new way: rate-limit force-polling for all NetworkStats queries
             if (elapsedMillisSinceBoot - mLastNetworkStatsPollTime >= NETSTATS_POLL_RATE_LIMIT_MS) {
@@ -1621,12 +1646,10 @@
                             .setMeteredness(METERED_YES).build();
             final NetworkStats stats =
                     getUidNetworkStatsSnapshotForTemplateLocked(template, /*includeTags=*/false);
-            if (stats != null) {
-                ret.add(new NetworkStatsExt(sliceNetworkStatsByFgbg(stats),
-                        new int[]{TRANSPORT_CELLULAR}, /*slicedByFgbg=*/true,
-                        /*slicedByTag=*/false, /*slicedByMetered=*/false, ratType, subInfo,
-                        OEM_MANAGED_ALL, /*isTypeProxy=*/false));
-            }
+            ret.add(new NetworkStatsExt(sliceNetworkStatsByFgbg(stats),
+                    new int[]{TRANSPORT_CELLULAR}, /*slicedByFgbg=*/true,
+                    /*slicedByTag=*/false, /*slicedByMetered=*/false, ratType, subInfo,
+                    OEM_MANAGED_ALL, /*isTypeProxy=*/false));
         }
         return ret;
     }
diff --git a/services/core/java/com/android/server/stats/pull/netstats/NetworkStatsAccumulator.java b/services/core/java/com/android/server/stats/pull/netstats/NetworkStatsAccumulator.java
new file mode 100644
index 0000000..e798bc4
--- /dev/null
+++ b/services/core/java/com/android/server/stats/pull/netstats/NetworkStatsAccumulator.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.stats.pull.netstats;
+
+import android.annotation.NonNull;
+import android.net.NetworkStats;
+import android.net.NetworkTemplate;
+
+import java.util.Objects;
+
+/**
+ * A class that queries NetworkStats, accumulates query results, and exposes cumulative stats across
+ * the time range covered by the queries. This class is not thread-safe.
+ * <p>
+ * This is class should be used when querying NetworkStats since boot, as NetworkStats persists data
+ * only for a limited period of time.
+ *
+ * @hide
+ */
+public class NetworkStatsAccumulator {
+
+    private final NetworkTemplate mTemplate;
+    private final boolean mWithTags;
+    private final long mBucketDurationMillis;
+    private NetworkStats mSnapshot;
+    private long mSnapshotEndTimeMillis;
+
+    public NetworkStatsAccumulator(@NonNull NetworkTemplate template, boolean withTags,
+            long bucketDurationMillis, long snapshotEndTimeMillis) {
+        mTemplate = template;
+        mWithTags = withTags;
+        mBucketDurationMillis = bucketDurationMillis;
+        mSnapshot = new NetworkStats(0, 1);
+        mSnapshotEndTimeMillis = snapshotEndTimeMillis;
+    }
+
+    /**
+     * Provides cumulative NetworkStats until given timestamp.
+     * <p>
+     * This method method may call {@code queryFunction} more than once, which includes maintaining
+     * an internal cumulative stats snapshot and querying stats after the snapshot.
+     */
+    @NonNull
+    public NetworkStats queryStats(long currentTimeMillis,
+            @NonNull StatsQueryFunction queryFunction) {
+        maybeExpandSnapshot(currentTimeMillis, queryFunction);
+        return snapshotPlusFollowingStats(currentTimeMillis, queryFunction);
+    }
+
+    /**
+     * Returns true if the accumulator is using given query parameters.
+     */
+    public boolean hasEqualParameters(@NonNull NetworkTemplate template, boolean withTags) {
+        return Objects.equals(mTemplate, template) && mWithTags == withTags;
+    }
+
+    /**
+     * Expands the internal cumulative stats snapshot, if possible, by querying NetworkStats.
+     */
+    private void maybeExpandSnapshot(long currentTimeMillis,
+            @NonNull StatsQueryFunction queryFunction) {
+        // Update snapshot only if it is possible to expand it by at least one full bucket, and only
+        // if the new snapshot's end is not in the active bucket.
+        long newEndTimeMillis = currentTimeMillis - mBucketDurationMillis;
+        if (newEndTimeMillis - mSnapshotEndTimeMillis > mBucketDurationMillis) {
+            NetworkStats extraStats = queryFunction.queryNetworkStats(mTemplate, mWithTags,
+                    mSnapshotEndTimeMillis, newEndTimeMillis);
+            mSnapshot = mSnapshot.add(extraStats);
+            mSnapshotEndTimeMillis = newEndTimeMillis;
+        }
+    }
+
+    /**
+     * Adds up stats in the internal cumulative snapshot and the stats that follow after it.
+     */
+    @NonNull
+    private NetworkStats snapshotPlusFollowingStats(long currentTimeMillis,
+            @NonNull StatsQueryFunction queryFunction) {
+        // Set end time in the future to include all stats in the active bucket.
+        NetworkStats extraStats = queryFunction.queryNetworkStats(mTemplate, mWithTags,
+                mSnapshotEndTimeMillis, currentTimeMillis + mBucketDurationMillis);
+        return mSnapshot.add(extraStats);
+    }
+
+    @FunctionalInterface
+    public interface StatsQueryFunction {
+        /**
+         * Returns network stats during the given time period.
+         */
+        @NonNull
+        NetworkStats queryNetworkStats(@NonNull NetworkTemplate template, boolean includeTags,
+                long startTime, long endTime);
+    }
+}
diff --git a/services/core/java/com/android/server/stats/stats_flags.aconfig b/services/core/java/com/android/server/stats/stats_flags.aconfig
index afea303..8686458f 100644
--- a/services/core/java/com/android/server/stats/stats_flags.aconfig
+++ b/services/core/java/com/android/server/stats/stats_flags.aconfig
@@ -30,3 +30,11 @@
     bug: "352495181"
     is_fixed_read_only: true
 }
+
+flag {
+    name: "accumulate_network_stats_since_boot"
+    namespace: "statsd"
+    description: "Accumulate results of NetworkStats queries to avoid hitting NetworkStats persistence limit"
+    bug: "352537247"
+    is_fixed_read_only: true
+}
diff --git a/services/core/java/com/android/server/tv/tunerresourcemanager/CasResource.java b/services/core/java/com/android/server/tv/tunerresourcemanager/CasResource.java
index eb5361c..d161070 100644
--- a/services/core/java/com/android/server/tv/tunerresourcemanager/CasResource.java
+++ b/services/core/java/com/android/server/tv/tunerresourcemanager/CasResource.java
@@ -30,7 +30,7 @@
      * Handle of the current resource. Should not be changed and should be aligned with the driver
      * level implementation.
      */
-    final int mHandle;
+    final long mHandle;
 
     private final int mSystemId;
 
@@ -50,7 +50,7 @@
         this.mAvailableSessionNum = builder.mMaxSessionNum;
     }
 
-    public int getHandle() {
+    public long getHandle() {
         return mHandle;
     }
 
@@ -146,11 +146,11 @@
      */
     public static class Builder {
 
-        private final int mHandle;
+        private final long mHandle;
         private int mSystemId;
         protected int mMaxSessionNum;
 
-        Builder(int handle, int systemId) {
+        Builder(long handle, int systemId) {
             this.mHandle = handle;
             this.mSystemId = systemId;
         }
diff --git a/services/core/java/com/android/server/tv/tunerresourcemanager/CiCamResource.java b/services/core/java/com/android/server/tv/tunerresourcemanager/CiCamResource.java
index 5cef729..b325570 100644
--- a/services/core/java/com/android/server/tv/tunerresourcemanager/CiCamResource.java
+++ b/services/core/java/com/android/server/tv/tunerresourcemanager/CiCamResource.java
@@ -42,7 +42,7 @@
      * Builder class for {@link CiCamResource}.
      */
     public static class Builder extends CasResource.Builder {
-        Builder(int handle, int systemId) {
+        Builder(long handle, int systemId) {
             super(handle, systemId);
         }
 
diff --git a/services/core/java/com/android/server/tv/tunerresourcemanager/ClientProfile.java b/services/core/java/com/android/server/tv/tunerresourcemanager/ClientProfile.java
index 8e37527..0962319 100644
--- a/services/core/java/com/android/server/tv/tunerresourcemanager/ClientProfile.java
+++ b/services/core/java/com/android/server/tv/tunerresourcemanager/ClientProfile.java
@@ -67,19 +67,19 @@
     /**
      * The handle of the primary frontend resource
      */
-    private int mPrimaryUsingFrontendHandle = TunerResourceManager.INVALID_RESOURCE_HANDLE;
+    private long mPrimaryUsingFrontendHandle = TunerResourceManager.INVALID_RESOURCE_HANDLE;
 
     /**
      * List of the frontend handles that are used by the current client.
      */
-    private Set<Integer> mUsingFrontendHandles = new HashSet<>();
+    private Set<Long> mUsingFrontendHandles = new HashSet<>();
 
     /**
      * List of the client ids that share frontend with the current client.
      */
     private Set<Integer> mShareFeClientIds = new HashSet<>();
 
-    private Set<Integer> mUsingDemuxHandles = new HashSet<>();
+    private Set<Long> mUsingDemuxHandles = new HashSet<>();
 
     /**
      * Client id sharee that has shared frontend with the current client.
@@ -89,7 +89,7 @@
     /**
      * List of the Lnb handles that are used by the current client.
      */
-    private Set<Integer> mUsingLnbHandles = new HashSet<>();
+    private Set<Long> mUsingLnbHandles = new HashSet<>();
 
     /**
      * List of the Cas system ids that are used by the current client.
@@ -184,7 +184,7 @@
      *
      * @param frontendHandle being used.
      */
-    public void useFrontend(int frontendHandle) {
+    public void useFrontend(long frontendHandle) {
         mUsingFrontendHandles.add(frontendHandle);
     }
 
@@ -193,14 +193,14 @@
      *
      * @param frontendHandle being used.
      */
-    public void setPrimaryFrontend(int frontendHandle) {
+    public void setPrimaryFrontend(long frontendHandle) {
         mPrimaryUsingFrontendHandle = frontendHandle;
     }
 
     /**
      * Get the primary frontend used by the client
      */
-    public int getPrimaryFrontend() {
+    public long getPrimaryFrontend() {
         return mPrimaryUsingFrontendHandle;
     }
 
@@ -222,7 +222,7 @@
         mShareFeClientIds.remove(clientId);
     }
 
-    public Set<Integer> getInUseFrontendHandles() {
+    public Set<Long> getInUseFrontendHandles() {
         return mUsingFrontendHandles;
     }
 
@@ -253,14 +253,14 @@
      *
      * @param demuxHandle the demux being used.
      */
-    public void useDemux(int demuxHandle) {
+    public void useDemux(long demuxHandle) {
         mUsingDemuxHandles.add(demuxHandle);
     }
 
     /**
      * Get the set of demux handles in use.
      */
-    public Set<Integer> getInUseDemuxHandles() {
+    public Set<Long> getInUseDemuxHandles() {
         return mUsingDemuxHandles;
     }
 
@@ -269,7 +269,7 @@
      *
      * @param demuxHandle the demux handl being released.
      */
-    public void releaseDemux(int demuxHandle) {
+    public void releaseDemux(long demuxHandle) {
         mUsingDemuxHandles.remove(demuxHandle);
     }
 
@@ -278,11 +278,11 @@
      *
      * @param lnbHandle being used.
      */
-    public void useLnb(int lnbHandle) {
+    public void useLnb(long lnbHandle) {
         mUsingLnbHandles.add(lnbHandle);
     }
 
-    public Set<Integer> getInUseLnbHandles() {
+    public Set<Long> getInUseLnbHandles() {
         return mUsingLnbHandles;
     }
 
@@ -291,7 +291,7 @@
      *
      * @param lnbHandle being released.
      */
-    public void releaseLnb(int lnbHandle) {
+    public void releaseLnb(long lnbHandle) {
         mUsingLnbHandles.remove(lnbHandle);
     }
 
diff --git a/services/core/java/com/android/server/tv/tunerresourcemanager/DemuxResource.java b/services/core/java/com/android/server/tv/tunerresourcemanager/DemuxResource.java
index df73565..14bc216 100644
--- a/services/core/java/com/android/server/tv/tunerresourcemanager/DemuxResource.java
+++ b/services/core/java/com/android/server/tv/tunerresourcemanager/DemuxResource.java
@@ -69,7 +69,7 @@
     public static class Builder extends TunerResourceBasic.Builder {
         private int mFilterTypes;
 
-        Builder(int handle) {
+        Builder(long handle) {
             super(handle);
         }
 
diff --git a/services/core/java/com/android/server/tv/tunerresourcemanager/FrontendResource.java b/services/core/java/com/android/server/tv/tunerresourcemanager/FrontendResource.java
index 7ef75e3..953d974 100644
--- a/services/core/java/com/android/server/tv/tunerresourcemanager/FrontendResource.java
+++ b/services/core/java/com/android/server/tv/tunerresourcemanager/FrontendResource.java
@@ -42,7 +42,7 @@
     /**
      * An array to save all the FE handles under the same exclisive group.
      */
-    private Set<Integer> mExclusiveGroupMemberHandles = new HashSet<>();
+    private Set<Long> mExclusiveGroupMemberHandles = new HashSet<>();
 
     private FrontendResource(Builder builder) {
         super(builder);
@@ -58,7 +58,7 @@
         return mExclusiveGroupId;
     }
 
-    public Set<Integer> getExclusiveGroupMemberFeHandles() {
+    public Set<Long> getExclusiveGroupMemberFeHandles() {
         return mExclusiveGroupMemberHandles;
     }
 
@@ -67,7 +67,7 @@
      *
      * @param handle the handle to be added.
      */
-    public void addExclusiveGroupMemberFeHandle(int handle) {
+    public void addExclusiveGroupMemberFeHandle(long handle) {
         mExclusiveGroupMemberHandles.add(handle);
     }
 
@@ -76,7 +76,7 @@
      *
      * @param handles the handle collection to be added.
      */
-    public void addExclusiveGroupMemberFeHandles(Collection<Integer> handles) {
+    public void addExclusiveGroupMemberFeHandles(Collection<Long> handles) {
         mExclusiveGroupMemberHandles.addAll(handles);
     }
 
@@ -85,7 +85,7 @@
      *
      * @param id the id to be removed.
      */
-    public void removeExclusiveGroupMemberFeId(int handle) {
+    public void removeExclusiveGroupMemberFeId(long handle) {
         mExclusiveGroupMemberHandles.remove(handle);
     }
 
@@ -104,7 +104,7 @@
         @Type private int mType;
         private int mExclusiveGroupId;
 
-        Builder(int handle) {
+        Builder(long handle) {
             super(handle);
         }
 
diff --git a/services/core/java/com/android/server/tv/tunerresourcemanager/LnbResource.java b/services/core/java/com/android/server/tv/tunerresourcemanager/LnbResource.java
index 41cacea..ab28371 100644
--- a/services/core/java/com/android/server/tv/tunerresourcemanager/LnbResource.java
+++ b/services/core/java/com/android/server/tv/tunerresourcemanager/LnbResource.java
@@ -37,8 +37,7 @@
      * Builder class for {@link LnbResource}.
      */
     public static class Builder extends TunerResourceBasic.Builder {
-
-        Builder(int handle) {
+        Builder(long handle) {
             super(handle);
         }
 
diff --git a/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceBasic.java b/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceBasic.java
index 07853fc..d2ff8fa 100644
--- a/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceBasic.java
+++ b/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceBasic.java
@@ -28,7 +28,7 @@
      * Handle of the current resource. Should not be changed and should be aligned with the driver
      * level implementation.
      */
-    final int mHandle;
+    final long mHandle;
 
     /**
      * If the current resource is in use.
@@ -44,7 +44,7 @@
         this.mHandle = builder.mHandle;
     }
 
-    public int getHandle() {
+    public long getHandle() {
         return mHandle;
     }
 
@@ -78,9 +78,9 @@
      * Builder class for {@link TunerResourceBasic}.
      */
     public static class Builder {
-        private final int mHandle;
+        private final long mHandle;
 
-        Builder(int handle) {
+        Builder(long handle) {
             this.mHandle = handle;
         }
 
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 9229f7f..c5b6bbf 100644
--- a/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java
+++ b/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java
@@ -78,12 +78,18 @@
 
     private static final int INVALID_FE_COUNT = -1;
 
+    private static final int RESOURCE_ID_SHIFT = 24;
+    private static final int RESOURCE_TYPE_SHIFT = 56;
+    private static final long RESOURCE_COUNT_MASK = 0xffffff;
+    private static final long RESOURCE_ID_MASK = 0xffffffff;
+    private static final long RESOURCE_TYPE_MASK = 0xff;
+
     // Map of the registered client profiles
     private Map<Integer, ClientProfile> mClientProfiles = new HashMap<>();
     private int mNextUnusedClientId = 0;
 
     // Map of the current available frontend resources
-    private Map<Integer, FrontendResource> mFrontendResources = new HashMap<>();
+    private Map<Long, FrontendResource> mFrontendResources = new HashMap<>();
     // SparseIntArray of the max usable number for each frontend resource type
     private SparseIntArray mFrontendMaxUsableNums = new SparseIntArray();
     // SparseIntArray of the currently used number for each frontend resource type
@@ -93,15 +99,15 @@
 
     // Backups for the frontend resource maps for enabling testing with custom resource maps
     // such as TunerTest.testHasUnusedFrontend1()
-    private Map<Integer, FrontendResource> mFrontendResourcesBackup = new HashMap<>();
+    private Map<Long, FrontendResource> mFrontendResourcesBackup = new HashMap<>();
     private SparseIntArray mFrontendMaxUsableNumsBackup = new SparseIntArray();
     private SparseIntArray mFrontendUsedNumsBackup = new SparseIntArray();
     private SparseIntArray mFrontendExistingNumsBackup = new SparseIntArray();
 
     // Map of the current available demux resources
-    private Map<Integer, DemuxResource> mDemuxResources = new HashMap<>();
+    private Map<Long, DemuxResource> mDemuxResources = new HashMap<>();
     // Map of the current available lnb resources
-    private Map<Integer, LnbResource> mLnbResources = new HashMap<>();
+    private Map<Long, LnbResource> mLnbResources = new HashMap<>();
     // Map of the current available Cas resources
     private Map<Integer, CasResource> mCasResources = new HashMap<>();
     // Map of the current available CiCam resources
@@ -266,7 +272,7 @@
         }
 
         @Override
-        public void setLnbInfoList(int[] lnbHandles) throws RemoteException {
+        public void setLnbInfoList(long[] lnbHandles) throws RemoteException {
             enforceTrmAccessPermission("setLnbInfoList");
             if (lnbHandles == null) {
                 throw new RemoteException("Lnb handle list can't be null");
@@ -277,8 +283,8 @@
         }
 
         @Override
-        public boolean requestFrontend(@NonNull TunerFrontendRequest request,
-                @NonNull int[] frontendHandle) {
+        public boolean requestFrontend(
+                @NonNull TunerFrontendRequest request, @NonNull long[] frontendHandle) {
             enforceTunerAccessPermission("requestFrontend");
             enforceTrmAccessPermission("requestFrontend");
             if (frontendHandle == null) {
@@ -350,8 +356,8 @@
         }
 
         @Override
-        public boolean requestDemux(@NonNull TunerDemuxRequest request,
-                    @NonNull int[] demuxHandle) throws RemoteException {
+        public boolean requestDemux(@NonNull TunerDemuxRequest request, @NonNull long[] demuxHandle)
+                throws RemoteException {
             enforceTunerAccessPermission("requestDemux");
             enforceTrmAccessPermission("requestDemux");
             if (demuxHandle == null) {
@@ -362,7 +368,7 @@
 
         @Override
         public boolean requestDescrambler(@NonNull TunerDescramblerRequest request,
-                    @NonNull int[] descramblerHandle) throws RemoteException {
+                @NonNull long[] descramblerHandle) throws RemoteException {
             enforceDescramblerAccessPermission("requestDescrambler");
             enforceTrmAccessPermission("requestDescrambler");
             if (descramblerHandle == null) {
@@ -379,7 +385,7 @@
 
         @Override
         public boolean requestCasSession(@NonNull CasSessionRequest request,
-                @NonNull int[] casSessionHandle) throws RemoteException {
+                @NonNull long[] casSessionHandle) throws RemoteException {
             enforceTrmAccessPermission("requestCasSession");
             if (casSessionHandle == null) {
                 throw new RemoteException("casSessionHandle can't be null");
@@ -388,8 +394,8 @@
         }
 
         @Override
-        public boolean requestCiCam(@NonNull TunerCiCamRequest request,
-                @NonNull int[] ciCamHandle) throws RemoteException {
+        public boolean requestCiCam(@NonNull TunerCiCamRequest request, @NonNull long[] ciCamHandle)
+                throws RemoteException {
             enforceTrmAccessPermission("requestCiCam");
             if (ciCamHandle == null) {
                 throw new RemoteException("ciCamHandle can't be null");
@@ -398,7 +404,7 @@
         }
 
         @Override
-        public boolean requestLnb(@NonNull TunerLnbRequest request, @NonNull int[] lnbHandle)
+        public boolean requestLnb(@NonNull TunerLnbRequest request, @NonNull long[] lnbHandle)
                 throws RemoteException {
             enforceTunerAccessPermission("requestLnb");
             enforceTrmAccessPermission("requestLnb");
@@ -409,14 +415,14 @@
         }
 
         @Override
-        public void releaseFrontend(int frontendHandle, int clientId) throws RemoteException {
+        public void releaseFrontend(long frontendHandle, int clientId) throws RemoteException {
             enforceTunerAccessPermission("releaseFrontend");
             enforceTrmAccessPermission("releaseFrontend");
             releaseFrontendInternal(frontendHandle, clientId);
         }
 
         @Override
-        public void releaseDemux(int demuxHandle, int clientId) throws RemoteException {
+        public void releaseDemux(long demuxHandle, int clientId) throws RemoteException {
             enforceTunerAccessPermission("releaseDemux");
             enforceTrmAccessPermission("releaseDemux");
             if (DEBUG) {
@@ -447,7 +453,7 @@
         }
 
         @Override
-        public void releaseDescrambler(int descramblerHandle, int clientId) {
+        public void releaseDescrambler(long descramblerHandle, int clientId) {
             enforceTunerAccessPermission("releaseDescrambler");
             enforceTrmAccessPermission("releaseDescrambler");
             if (DEBUG) {
@@ -456,7 +462,7 @@
         }
 
         @Override
-        public void releaseCasSession(int casSessionHandle, int clientId) throws RemoteException {
+        public void releaseCasSession(long casSessionHandle, int clientId) throws RemoteException {
             enforceTrmAccessPermission("releaseCasSession");
             if (!validateResourceHandle(
                     TunerResourceManager.TUNER_RESOURCE_TYPE_CAS_SESSION, casSessionHandle)) {
@@ -480,7 +486,7 @@
         }
 
         @Override
-        public void releaseCiCam(int ciCamHandle, int clientId) throws RemoteException {
+        public void releaseCiCam(long ciCamHandle, int clientId) throws RemoteException {
             enforceTrmAccessPermission("releaseCiCam");
             if (!validateResourceHandle(
                     TunerResourceManager.TUNER_RESOURCE_TYPE_FRONTEND_CICAM, ciCamHandle)) {
@@ -508,7 +514,7 @@
         }
 
         @Override
-        public void releaseLnb(int lnbHandle, int clientId) throws RemoteException {
+        public void releaseLnb(long lnbHandle, int clientId) throws RemoteException {
             enforceTunerAccessPermission("releaseLnb");
             enforceTrmAccessPermission("releaseLnb");
             if (!validateResourceHandle(TunerResourceManager.TUNER_RESOURCE_TYPE_LNB, lnbHandle)) {
@@ -812,7 +818,7 @@
         // A set to record the frontends pending on updating. Ids will be removed
         // from this set once its updating finished. Any frontend left in this set when all
         // the updates are done will be removed from mFrontendResources.
-        Set<Integer> updatingFrontendHandles = new HashSet<>(getFrontendResources().keySet());
+        Set<Long> updatingFrontendHandles = new HashSet<>(getFrontendResources().keySet());
 
         // Update frontendResources map and other mappings accordingly
         for (int i = 0; i < infos.length; i++) {
@@ -831,7 +837,7 @@
             }
         }
 
-        for (int removingHandle : updatingFrontendHandles) {
+        for (long removingHandle : updatingFrontendHandles) {
             // update the exclusive group id member list
             removeFrontendResource(removingHandle);
         }
@@ -849,7 +855,7 @@
         // A set to record the demuxes pending on updating. Ids will be removed
         // from this set once its updating finished. Any demux left in this set when all
         // the updates are done will be removed from mDemuxResources.
-        Set<Integer> updatingDemuxHandles = new HashSet<>(getDemuxResources().keySet());
+        Set<Long> updatingDemuxHandles = new HashSet<>(getDemuxResources().keySet());
 
         // Update demuxResources map and other mappings accordingly
         for (int i = 0; i < infos.length; i++) {
@@ -867,13 +873,13 @@
             }
         }
 
-        for (int removingHandle : updatingDemuxHandles) {
+        for (long removingHandle : updatingDemuxHandles) {
             // update the exclusive group id member list
             removeDemuxResource(removingHandle);
         }
     }
     @VisibleForTesting
-    protected void setLnbInfoListInternal(int[] lnbHandles) {
+    protected void setLnbInfoListInternal(long[] lnbHandles) {
         if (DEBUG) {
             for (int i = 0; i < lnbHandles.length; i++) {
                 Slog.d(TAG, "updateLnbInfo(lnbHanle=" + lnbHandles[i] + ")");
@@ -883,7 +889,7 @@
         // A set to record the Lnbs pending on updating. Handles will be removed
         // from this set once its updating finished. Any lnb left in this set when all
         // the updates are done will be removed from mLnbResources.
-        Set<Integer> updatingLnbHandles = new HashSet<>(getLnbResources().keySet());
+        Set<Long> updatingLnbHandles = new HashSet<>(getLnbResources().keySet());
 
         // Update lnbResources map and other mappings accordingly
         for (int i = 0; i < lnbHandles.length; i++) {
@@ -899,7 +905,7 @@
             }
         }
 
-        for (int removingHandle : updatingLnbHandles) {
+        for (long removingHandle : updatingLnbHandles) {
             removeLnbResource(removingHandle);
         }
     }
@@ -933,12 +939,12 @@
             return;
         }
         // Add the new Cas Resource.
-        int casSessionHandle = generateResourceHandle(
+        long casSessionHandle = generateResourceHandle(
                 TunerResourceManager.TUNER_RESOURCE_TYPE_CAS_SESSION, casSystemId);
         cas = new CasResource.Builder(casSessionHandle, casSystemId)
                              .maxSessionNum(maxSessionNum)
                              .build();
-        int ciCamHandle = generateResourceHandle(
+        long ciCamHandle = generateResourceHandle(
                 TunerResourceManager.TUNER_RESOURCE_TYPE_FRONTEND_CICAM, casSystemId);
         ciCam = new CiCamResource.Builder(ciCamHandle, casSystemId)
                              .maxSessionNum(maxSessionNum)
@@ -948,7 +954,7 @@
     }
 
     @VisibleForTesting
-    protected boolean requestFrontendInternal(TunerFrontendRequest request, int[] frontendHandle) {
+    protected boolean requestFrontendInternal(TunerFrontendRequest request, long[] frontendHandle) {
         if (DEBUG) {
             Slog.d(TAG, "requestFrontend(request=" + request + ")");
         }
@@ -977,7 +983,7 @@
 
     protected boolean claimFrontend(
             TunerFrontendRequest request,
-            int[] frontendHandle,
+            long[] frontendHandle,
             int[] reclaimOwnerId
     ) {
         frontendHandle[0] = TunerResourceManager.INVALID_RESOURCE_HANDLE;
@@ -1032,7 +1038,7 @@
                             // currently in primary use (and simply blocked due to exclusive group)
                             ClientProfile targetOwnerProfile =
                                     getClientProfile(fr.getOwnerClientId());
-                            int primaryFeId = targetOwnerProfile.getPrimaryFrontend();
+                            long primaryFeId = targetOwnerProfile.getPrimaryFrontend();
                             FrontendResource primaryFe = getFrontendResource(primaryFeId);
                             if (fr.getType() != primaryFe.getType()
                                     && isFrontendMaxNumUseReached(fr.getType())) {
@@ -1081,7 +1087,7 @@
             getClientProfile(shareeFeClientId).stopSharingFrontend(selfClientId);
             getClientProfile(selfClientId).releaseFrontend();
         }
-        for (int feId : getClientProfile(targetClientId).getInUseFrontendHandles()) {
+        for (long feId : getClientProfile(targetClientId).getInUseFrontendHandles()) {
             getClientProfile(selfClientId).useFrontend(feId);
         }
         getClientProfile(selfClientId).setShareeFeClientId(targetClientId);
@@ -1096,14 +1102,14 @@
         currentOwnerProfile.stopSharingFrontend(newOwnerId);
         newOwnerProfile.setShareeFeClientId(ClientProfile.INVALID_RESOURCE_ID);
         currentOwnerProfile.setShareeFeClientId(newOwnerId);
-        for (int inUseHandle : newOwnerProfile.getInUseFrontendHandles()) {
+        for (long inUseHandle : newOwnerProfile.getInUseFrontendHandles()) {
             getFrontendResource(inUseHandle).setOwner(newOwnerId);
         }
         // change the primary frontend
         newOwnerProfile.setPrimaryFrontend(currentOwnerProfile.getPrimaryFrontend());
         currentOwnerProfile.setPrimaryFrontend(TunerResourceManager.INVALID_RESOURCE_HANDLE);
         // double check there is no other resources tied to the previous owner
-        for (int inUseHandle : currentOwnerProfile.getInUseFrontendHandles()) {
+        for (long inUseHandle : currentOwnerProfile.getInUseFrontendHandles()) {
             int ownerId = getFrontendResource(inUseHandle).getOwnerClientId();
             if (ownerId != newOwnerId) {
                 Slog.e(TAG, "something is wrong in transferFeOwner:" + inUseHandle
@@ -1135,8 +1141,8 @@
         ClientProfile currentOwnerProfile = getClientProfile(currentOwnerId);
         ClientProfile newOwnerProfile = getClientProfile(newOwnerId);
 
-        Set<Integer> inUseLnbHandles = new HashSet<>();
-        for (Integer lnbHandle : currentOwnerProfile.getInUseLnbHandles()) {
+        Set<Long> inUseLnbHandles = new HashSet<>();
+        for (Long lnbHandle : currentOwnerProfile.getInUseLnbHandles()) {
             // link lnb handle to the new profile
             newOwnerProfile.useLnb(lnbHandle);
 
@@ -1148,7 +1154,7 @@
         }
 
         // unlink lnb handles from the original owner
-        for (Integer lnbHandle : inUseLnbHandles) {
+        for (Long lnbHandle : inUseLnbHandles) {
             currentOwnerProfile.releaseLnb(lnbHandle);
         }
 
@@ -1171,7 +1177,7 @@
     }
 
     @VisibleForTesting
-    protected boolean requestLnbInternal(TunerLnbRequest request, int[] lnbHandle)
+    protected boolean requestLnbInternal(TunerLnbRequest request, long[] lnbHandle)
             throws RemoteException {
         if (DEBUG) {
             Slog.d(TAG, "requestLnb(request=" + request + ")");
@@ -1199,7 +1205,7 @@
         return true;
     }
 
-    protected boolean claimLnb(TunerLnbRequest request, int[] lnbHandle, int[] reclaimOwnerId)
+    protected boolean claimLnb(TunerLnbRequest request, long[] lnbHandle, int[] reclaimOwnerId)
             throws RemoteException {
         lnbHandle[0] = TunerResourceManager.INVALID_RESOURCE_HANDLE;
         reclaimOwnerId[0] = INVALID_CLIENT_ID;
@@ -1256,7 +1262,7 @@
     }
 
     @VisibleForTesting
-    protected boolean requestCasSessionInternal(CasSessionRequest request, int[] casSessionHandle)
+    protected boolean requestCasSessionInternal(CasSessionRequest request, long[] casSessionHandle)
             throws RemoteException {
         if (DEBUG) {
             Slog.d(TAG, "requestCasSession(request=" + request + ")");
@@ -1284,7 +1290,7 @@
         return true;
     }
 
-    protected boolean claimCasSession(CasSessionRequest request, int[] casSessionHandle,
+    protected boolean claimCasSession(CasSessionRequest request, long[] casSessionHandle,
             int[] reclaimOwnerId) throws RemoteException {
         casSessionHandle[0] = TunerResourceManager.INVALID_RESOURCE_HANDLE;
         reclaimOwnerId[0] = INVALID_CLIENT_ID;
@@ -1296,7 +1302,7 @@
             CasResource cas = getCasResource(request.casSystemId);
             // Unregistered Cas System is treated as having unlimited sessions.
             if (cas == null) {
-                int resourceHandle = generateResourceHandle(
+                long resourceHandle = generateResourceHandle(
                         TunerResourceManager.TUNER_RESOURCE_TYPE_CAS_SESSION, request.clientId);
                 cas = new CasResource.Builder(resourceHandle, request.casSystemId)
                                     .maxSessionNum(Integer.MAX_VALUE)
@@ -1341,7 +1347,7 @@
     }
 
     @VisibleForTesting
-    protected boolean requestCiCamInternal(TunerCiCamRequest request, int[] ciCamHandle)
+    protected boolean requestCiCamInternal(TunerCiCamRequest request, long[] ciCamHandle)
             throws RemoteException {
         if (DEBUG) {
             Slog.d(TAG, "requestCiCamInternal(TunerCiCamRequest=" + request + ")");
@@ -1369,7 +1375,7 @@
         return true;
     }
 
-    protected boolean claimCiCam(TunerCiCamRequest request, int[] ciCamHandle,
+    protected boolean claimCiCam(TunerCiCamRequest request, long[] ciCamHandle,
             int[] reclaimOwnerId) throws RemoteException {
         ciCamHandle[0] = TunerResourceManager.INVALID_RESOURCE_HANDLE;
         reclaimOwnerId[0] = INVALID_CLIENT_ID;
@@ -1381,7 +1387,7 @@
             CiCamResource ciCam = getCiCamResource(request.ciCamId);
             // Unregistered CiCam is treated as having unlimited sessions.
             if (ciCam == null) {
-                int resourceHandle = generateResourceHandle(
+                long resourceHandle = generateResourceHandle(
                         TunerResourceManager.TUNER_RESOURCE_TYPE_FRONTEND_CICAM, request.ciCamId);
                 ciCam = new CiCamResource.Builder(resourceHandle, request.ciCamId)
                                     .maxSessionNum(Integer.MAX_VALUE)
@@ -1454,7 +1460,7 @@
     }
 
     @VisibleForTesting
-    protected void releaseFrontendInternal(int frontendHandle, int clientId)
+    protected void releaseFrontendInternal(long frontendHandle, int clientId)
             throws RemoteException {
         if (DEBUG) {
             Slog.d(TAG, "releaseFrontend(id=" + frontendHandle + ", clientId=" + clientId + " )");
@@ -1475,7 +1481,7 @@
         }
     }
 
-    private Set<Integer> unclaimFrontend(int frontendHandle, int clientId) throws RemoteException {
+    private Set<Integer> unclaimFrontend(long frontendHandle, int clientId) throws RemoteException {
         Set<Integer> reclaimedResourceOwnerIds = null;
         synchronized (mLock) {
             if (!checkClientExists(clientId)) {
@@ -1533,7 +1539,7 @@
 
     @VisibleForTesting
     public boolean requestDemuxInternal(@NonNull TunerDemuxRequest request,
-                @NonNull int[] demuxHandle) throws RemoteException {
+                @NonNull long[] demuxHandle) throws RemoteException {
         if (DEBUG) {
             Slog.d(TAG, "requestDemux(request=" + request + ")");
         }
@@ -1560,7 +1566,8 @@
         return true;
     }
 
-    protected boolean claimDemux(TunerDemuxRequest request, int[] demuxHandle, int[] reclaimOwnerId)
+    protected boolean claimDemux(
+            TunerDemuxRequest request, long[] demuxHandle, int[] reclaimOwnerId)
             throws RemoteException {
         demuxHandle[0] = TunerResourceManager.INVALID_RESOURCE_HANDLE;
         reclaimOwnerId[0] = INVALID_CLIENT_ID;
@@ -1676,7 +1683,7 @@
 
     @VisibleForTesting
     protected boolean requestDescramblerInternal(
-            TunerDescramblerRequest request, int[] descramblerHandle) {
+            TunerDescramblerRequest request, long[] descramblerHandle) {
         if (DEBUG) {
             Slog.d(TAG, "requestDescrambler(request=" + request + ")");
         }
@@ -2008,20 +2015,20 @@
         return false;
     }
 
-    private void updateFrontendClientMappingOnNewGrant(int grantingHandle, int ownerClientId) {
+    private void updateFrontendClientMappingOnNewGrant(long grantingHandle, int ownerClientId) {
         FrontendResource grantingFrontend = getFrontendResource(grantingHandle);
         ClientProfile ownerProfile = getClientProfile(ownerClientId);
         grantingFrontend.setOwner(ownerClientId);
         increFrontendNum(mFrontendUsedNums, grantingFrontend.getType());
         ownerProfile.useFrontend(grantingHandle);
-        for (int exclusiveGroupMember : grantingFrontend.getExclusiveGroupMemberFeHandles()) {
+        for (long exclusiveGroupMember : grantingFrontend.getExclusiveGroupMemberFeHandles()) {
             getFrontendResource(exclusiveGroupMember).setOwner(ownerClientId);
             ownerProfile.useFrontend(exclusiveGroupMember);
         }
         ownerProfile.setPrimaryFrontend(grantingHandle);
     }
 
-    private void updateDemuxClientMappingOnNewGrant(int grantingHandle, int ownerClientId) {
+    private void updateDemuxClientMappingOnNewGrant(long grantingHandle, int ownerClientId) {
         DemuxResource grantingDemux = getDemuxResource(grantingHandle);
         if (grantingDemux != null) {
             ClientProfile ownerProfile = getClientProfile(ownerClientId);
@@ -2036,7 +2043,7 @@
         ownerProfile.releaseDemux(releasingDemux.getHandle());
     }
 
-    private void updateLnbClientMappingOnNewGrant(int grantingHandle, int ownerClientId) {
+    private void updateLnbClientMappingOnNewGrant(long grantingHandle, int ownerClientId) {
         LnbResource grantingLnb = getLnbResource(grantingHandle);
         ClientProfile ownerProfile = getClientProfile(ownerClientId);
         grantingLnb.setOwner(ownerClientId);
@@ -2120,23 +2127,23 @@
 
     @VisibleForTesting
     @Nullable
-    protected FrontendResource getFrontendResource(int frontendHandle) {
+    protected FrontendResource getFrontendResource(long frontendHandle) {
         return mFrontendResources.get(frontendHandle);
     }
 
     @VisibleForTesting
-    protected Map<Integer, FrontendResource> getFrontendResources() {
+    protected Map<Long, FrontendResource> getFrontendResources() {
         return mFrontendResources;
     }
 
     @VisibleForTesting
     @Nullable
-    protected DemuxResource getDemuxResource(int demuxHandle) {
+    protected DemuxResource getDemuxResource(long demuxHandle) {
         return mDemuxResources.get(demuxHandle);
     }
 
     @VisibleForTesting
-    protected Map<Integer, DemuxResource> getDemuxResources() {
+    protected Map<Long, DemuxResource> getDemuxResources() {
         return mDemuxResources;
     }
 
@@ -2195,8 +2202,8 @@
         }
     }
 
-    private void replaceFeResourceMap(Map<Integer, FrontendResource> srcMap, Map<Integer,
-            FrontendResource> dstMap) {
+    private void replaceFeResourceMap(
+            Map<Long, FrontendResource> srcMap, Map<Long, FrontendResource> dstMap) {
         if (dstMap != null) {
             dstMap.clear();
             if (srcMap != null && srcMap.size() > 0) {
@@ -2249,7 +2256,7 @@
             if (fe.getExclusiveGroupId() == newFe.getExclusiveGroupId()) {
                 newFe.addExclusiveGroupMemberFeHandle(fe.getHandle());
                 newFe.addExclusiveGroupMemberFeHandles(fe.getExclusiveGroupMemberFeHandles());
-                for (int excGroupmemberFeHandle : fe.getExclusiveGroupMemberFeHandles()) {
+                for (long excGroupmemberFeHandle : fe.getExclusiveGroupMemberFeHandles()) {
                     getFrontendResource(excGroupmemberFeHandle)
                             .addExclusiveGroupMemberFeHandle(newFe.getHandle());
                 }
@@ -2267,7 +2274,7 @@
         mDemuxResources.put(newDemux.getHandle(), newDemux);
     }
 
-    private void removeFrontendResource(int removingHandle) {
+    private void removeFrontendResource(long removingHandle) {
         FrontendResource fe = getFrontendResource(removingHandle);
         if (fe == null) {
             return;
@@ -2279,7 +2286,7 @@
             }
             clearFrontendAndClientMapping(ownerClient);
         }
-        for (int excGroupmemberFeHandle : fe.getExclusiveGroupMemberFeHandles()) {
+        for (long excGroupmemberFeHandle : fe.getExclusiveGroupMemberFeHandles()) {
             getFrontendResource(excGroupmemberFeHandle)
                     .removeExclusiveGroupMemberFeId(fe.getHandle());
         }
@@ -2287,7 +2294,7 @@
         mFrontendResources.remove(removingHandle);
     }
 
-    private void removeDemuxResource(int removingHandle) {
+    private void removeDemuxResource(long removingHandle) {
         DemuxResource demux = getDemuxResource(removingHandle);
         if (demux == null) {
             return;
@@ -2300,12 +2307,12 @@
 
     @VisibleForTesting
     @Nullable
-    protected LnbResource getLnbResource(int lnbHandle) {
+    protected LnbResource getLnbResource(long lnbHandle) {
         return mLnbResources.get(lnbHandle);
     }
 
     @VisibleForTesting
-    protected Map<Integer, LnbResource> getLnbResources() {
+    protected Map<Long, LnbResource> getLnbResources() {
         return mLnbResources;
     }
 
@@ -2314,7 +2321,7 @@
         mLnbResources.put(newLnb.getHandle(), newLnb);
     }
 
-    private void removeLnbResource(int removingHandle) {
+    private void removeLnbResource(long removingHandle) {
         LnbResource lnb = getLnbResource(removingHandle);
         if (lnb == null) {
             return;
@@ -2416,7 +2423,7 @@
         if (profile == null) {
             return;
         }
-        for (Integer feId : profile.getInUseFrontendHandles()) {
+        for (Long feId : profile.getInUseFrontendHandles()) {
             FrontendResource fe = getFrontendResource(feId);
             int ownerClientId = fe.getOwnerClientId();
             if (ownerClientId == profile.getId()) {
@@ -2427,10 +2434,9 @@
             if (ownerClientProfile != null) {
                 ownerClientProfile.stopSharingFrontend(profile.getId());
             }
-
         }
 
-        int primaryFeId = profile.getPrimaryFrontend();
+        long primaryFeId = profile.getPrimaryFrontend();
         if (primaryFeId != TunerResourceManager.INVALID_RESOURCE_HANDLE) {
             FrontendResource primaryFe = getFrontendResource(primaryFeId);
             if (primaryFe != null) {
@@ -2448,7 +2454,7 @@
             return;
         }
         // Clear Lnb
-        for (Integer lnbHandle : profile.getInUseLnbHandles()) {
+        for (Long lnbHandle : profile.getInUseLnbHandles()) {
             getLnbResource(lnbHandle).removeOwner();
         }
         // Clear Cas
@@ -2460,7 +2466,7 @@
             getCiCamResource(profile.getInUseCiCamId()).removeOwner(profile.getId());
         }
         // Clear Demux
-        for (Integer demuxHandle : profile.getInUseDemuxHandles()) {
+        for (Long demuxHandle : profile.getInUseDemuxHandles()) {
             getDemuxResource(demuxHandle).removeOwner();
         }
         // Clear Frontend
@@ -2473,24 +2479,31 @@
         return mClientProfiles.keySet().contains(clientId);
     }
 
-    private int generateResourceHandle(
+    /**
+     *   Generate resource handle for resourceType and resourceId
+     *   Resource Handle Allotment : 64 bits (long)
+     *   8 bits - resourceType
+     *   32 bits - resourceId
+     *   24 bits - resourceRequestCount
+     */
+    private long generateResourceHandle(
             @TunerResourceManager.TunerResourceType int resourceType, int resourceId) {
-        return (resourceType & 0x000000ff) << 24
-                | (resourceId << 16)
-                | (mResourceRequestCount++ & 0xffff);
+        return (resourceType & RESOURCE_TYPE_MASK) << RESOURCE_TYPE_SHIFT
+                | (resourceId & RESOURCE_ID_MASK) << RESOURCE_ID_SHIFT
+                | (mResourceRequestCount++ & RESOURCE_COUNT_MASK);
     }
 
     @VisibleForTesting
-    protected int getResourceIdFromHandle(int resourceHandle) {
+    protected int getResourceIdFromHandle(long resourceHandle) {
         if (resourceHandle == TunerResourceManager.INVALID_RESOURCE_HANDLE) {
-            return resourceHandle;
+            return (int) resourceHandle;
         }
-        return (resourceHandle & 0x00ff0000) >> 16;
+        return (int) ((resourceHandle >> RESOURCE_ID_SHIFT) & RESOURCE_ID_MASK);
     }
 
-    private boolean validateResourceHandle(int resourceType, int resourceHandle) {
+    private boolean validateResourceHandle(int resourceType, long resourceHandle) {
         if (resourceHandle == TunerResourceManager.INVALID_RESOURCE_HANDLE
-                || ((resourceHandle & 0xff000000) >> 24) != resourceType) {
+                || ((resourceHandle >> RESOURCE_TYPE_SHIFT) & RESOURCE_TYPE_MASK) != resourceType) {
             return false;
         }
         return true;
diff --git a/services/core/java/com/android/server/uri/UriPermission.java b/services/core/java/com/android/server/uri/UriPermission.java
index 0d1f367..0ff23ea 100644
--- a/services/core/java/com/android/server/uri/UriPermission.java
+++ b/services/core/java/com/android/server/uri/UriPermission.java
@@ -25,6 +25,8 @@
 import android.util.Log;
 import android.util.Slog;
 
+import com.android.internal.annotations.GuardedBy;
+
 import com.google.android.collect.Sets;
 
 import java.io.PrintWriter;
@@ -82,7 +84,9 @@
 
     static final long INVALID_TIME = Long.MIN_VALUE;
 
+    @GuardedBy("this")
     private ArraySet<UriPermissionOwner> mReadOwners;
+    @GuardedBy("this")
     private ArraySet<UriPermissionOwner> mWriteOwners;
 
     private String stringName;
@@ -204,14 +208,16 @@
                 persistedModeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
             }
             globalModeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
-            if (mReadOwners != null && includingOwners) {
-                ownedModeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
-                for (UriPermissionOwner r : mReadOwners) {
-                    if (r != null) {
-                        r.removeReadPermission(this);
+            synchronized (this) {
+                if (mReadOwners != null && includingOwners) {
+                    ownedModeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
+                    for (UriPermissionOwner r : mReadOwners) {
+                        if (r != null) {
+                            r.removeReadPermission(this);
+                        }
                     }
+                    mReadOwners = null;
                 }
-                mReadOwners = null;
             }
         }
         if ((modeFlags & Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
@@ -220,14 +226,16 @@
                 persistedModeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
             }
             globalModeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
-            if (mWriteOwners != null && includingOwners) {
-                ownedModeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
-                for (UriPermissionOwner r : mWriteOwners) {
-                    if (r != null) {
-                        r.removeWritePermission(this);
+            synchronized (this) {
+                if (mWriteOwners != null && includingOwners) {
+                    ownedModeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
+                    for (UriPermissionOwner r : mWriteOwners) {
+                        if (r != null) {
+                            r.removeWritePermission(this);
+                        }
                     }
+                    mWriteOwners = null;
                 }
-                mWriteOwners = null;
             }
         }
 
@@ -256,7 +264,7 @@
         }
     }
 
-    private void addReadOwner(UriPermissionOwner owner) {
+    private synchronized void addReadOwner(UriPermissionOwner owner) {
         if (mReadOwners == null) {
             mReadOwners = Sets.newArraySet();
             ownedModeFlags |= Intent.FLAG_GRANT_READ_URI_PERMISSION;
@@ -270,7 +278,7 @@
     /**
      * Remove given read owner, updating {@Link #modeFlags} as needed.
      */
-    void removeReadOwner(UriPermissionOwner owner) {
+    synchronized void removeReadOwner(UriPermissionOwner owner) {
         if (mReadOwners == null || !mReadOwners.remove(owner)) {
             Slog.wtf(TAG, "Unknown read owner " + owner + " in " + this);
             return;
@@ -282,7 +290,7 @@
         }
     }
 
-    private void addWriteOwner(UriPermissionOwner owner) {
+    private synchronized void addWriteOwner(UriPermissionOwner owner) {
         if (mWriteOwners == null) {
             mWriteOwners = Sets.newArraySet();
             ownedModeFlags |= Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
@@ -296,7 +304,7 @@
     /**
      * Remove given write owner, updating {@Link #modeFlags} as needed.
      */
-    void removeWriteOwner(UriPermissionOwner owner) {
+    synchronized void removeWriteOwner(UriPermissionOwner owner) {
         if (mWriteOwners == null || !mWriteOwners.remove(owner)) {
             Slog.wtf(TAG, "Unknown write owner " + owner + " in " + this);
             return;
@@ -339,20 +347,22 @@
         }
         pw.println();
 
-        if (mReadOwners != null) {
-            pw.print(prefix);
-            pw.println("readOwners:");
-            for (UriPermissionOwner owner : mReadOwners) {
+        synchronized (this) {
+            if (mReadOwners != null) {
                 pw.print(prefix);
-                pw.println("  * " + owner);
+                pw.println("readOwners:");
+                for (UriPermissionOwner owner : mReadOwners) {
+                    pw.print(prefix);
+                    pw.println("  * " + owner);
+                }
             }
-        }
-        if (mWriteOwners != null) {
-            pw.print(prefix);
-            pw.println("writeOwners:");
-            for (UriPermissionOwner owner : mWriteOwners) {
+            if (mWriteOwners != null) {
                 pw.print(prefix);
-                pw.println("  * " + owner);
+                pw.println("writeOwners:");
+                for (UriPermissionOwner owner : mWriteOwners) {
+                    pw.print(prefix);
+                    pw.println("  * " + owner);
+                }
             }
         }
     }
diff --git a/services/core/java/com/android/server/vibrator/ClippingAmplitudeAndFrequencyAdapter.java b/services/core/java/com/android/server/vibrator/ClippingAmplitudeAndFrequencyAdapter.java
index 111e075a..245d902 100644
--- a/services/core/java/com/android/server/vibrator/ClippingAmplitudeAndFrequencyAdapter.java
+++ b/services/core/java/com/android/server/vibrator/ClippingAmplitudeAndFrequencyAdapter.java
@@ -26,10 +26,10 @@
 
 /**
  * Adapter that clips frequency values to the supported range specified by
- * {@link VibratorInfo.FrequencyProfile}, then clips amplitude values to the max supported one at
+ * {@link VibratorInfo.FrequencyProfileLegacy}, then clips amplitude values to the max supported one at
  * each frequency.
  *
- * <p>The {@link VibratorInfo.FrequencyProfile} is only applicable to PWLE compositions. This
+ * <p>The {@link VibratorInfo.FrequencyProfileLegacy} is only applicable to PWLE compositions. This
  * adapter is only applied to {@link RampSegment} and all other segments will remain unchanged.
  */
 final class ClippingAmplitudeAndFrequencyAdapter implements VibrationSegmentsAdapter {
@@ -59,7 +59,7 @@
     }
 
     private float clampFrequency(VibratorInfo info, float frequencyHz) {
-        Range<Float> frequencyRangeHz = info.getFrequencyProfile().getFrequencyRangeHz();
+        Range<Float> frequencyRangeHz = info.getFrequencyProfileLegacy().getFrequencyRangeHz();
         if (frequencyHz == 0 || frequencyRangeHz == null)  {
             return Float.isNaN(info.getResonantFrequencyHz()) ? 0 : info.getResonantFrequencyHz();
         }
@@ -67,7 +67,7 @@
     }
 
     private float clampAmplitude(VibratorInfo info, float frequencyHz, float amplitude) {
-        VibratorInfo.FrequencyProfile mapping = info.getFrequencyProfile();
+        VibratorInfo.FrequencyProfileLegacy mapping = info.getFrequencyProfileLegacy();
         if (mapping.isEmpty()) {
             // No frequency mapping was specified so leave amplitude unchanged.
             // The frequency will be clamped to the device's resonant frequency.
diff --git a/services/core/java/com/android/server/vibrator/HapticFeedbackVibrationProvider.java b/services/core/java/com/android/server/vibrator/HapticFeedbackVibrationProvider.java
index 006a5bb..a235ba15 100644
--- a/services/core/java/com/android/server/vibrator/HapticFeedbackVibrationProvider.java
+++ b/services/core/java/com/android/server/vibrator/HapticFeedbackVibrationProvider.java
@@ -148,8 +148,8 @@
             case HapticFeedbackConstants.SCROLL_TICK:
             case HapticFeedbackConstants.SCROLL_ITEM_FOCUS:
             case HapticFeedbackConstants.SCROLL_LIMIT:
-                attrs = hapticFeedbackInputSourceCustomizationEnabled() ? TOUCH_VIBRATION_ATTRIBUTES
-                        : HARDWARE_FEEDBACK_VIBRATION_ATTRIBUTES;
+                // TODO(b/372820923): use touch attributes by default.
+                attrs = HARDWARE_FEEDBACK_VIBRATION_ATTRIBUTES;
                 break;
             case HapticFeedbackConstants.KEYBOARD_TAP:
             case HapticFeedbackConstants.KEYBOARD_RELEASE:
@@ -176,14 +176,15 @@
             int inputSource,
             @HapticFeedbackConstants.Flags int flags,
             @HapticFeedbackConstants.PrivateFlags int privFlags) {
-        if (hapticFeedbackInputSourceCustomizationEnabled()
-                && inputSource == InputDevice.SOURCE_ROTARY_ENCODER) {
+        if (hapticFeedbackInputSourceCustomizationEnabled()) {
             switch (effectId) {
                 case HapticFeedbackConstants.SCROLL_TICK,
                         HapticFeedbackConstants.SCROLL_ITEM_FOCUS,
                         HapticFeedbackConstants.SCROLL_LIMIT -> {
-                    return getVibrationAttributesWithFlags(HARDWARE_FEEDBACK_VIBRATION_ATTRIBUTES,
-                            effectId, flags);
+                    VibrationAttributes attrs = inputSource == InputDevice.SOURCE_ROTARY_ENCODER
+                            ? HARDWARE_FEEDBACK_VIBRATION_ATTRIBUTES
+                            : TOUCH_VIBRATION_ATTRIBUTES;
+                    return getVibrationAttributesWithFlags(attrs, effectId, flags);
                 }
             }
         }
diff --git a/services/core/java/com/android/server/wm/ActivityClientController.java b/services/core/java/com/android/server/wm/ActivityClientController.java
index 517f631..ae30fcd 100644
--- a/services/core/java/com/android/server/wm/ActivityClientController.java
+++ b/services/core/java/com/android/server/wm/ActivityClientController.java
@@ -442,6 +442,8 @@
             throw new IllegalArgumentException("File descriptors passed in Intent");
         }
 
+        mService.mAmInternal.addCreatorToken(resultData);
+
         final ActivityRecord r;
         synchronized (mGlobalLock) {
             r = ActivityRecord.isInRootTaskLocked(token);
diff --git a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
index fb5c115..3f814f9 100644
--- a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
+++ b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
@@ -244,7 +244,7 @@
                     status = ":completed-same-process:";
                 } else {
                     if (endInfo.mTransitionType == TYPE_TRANSITION_HOT_LAUNCH) {
-                        status = ":completed-hot:";
+                        status = !endInfo.mRelaunched ? ":completed-hot:" : ":completed-relaunch:";
                     } else if (endInfo.mTransitionType == TYPE_TRANSITION_WARM_LAUNCH) {
                         status = ":completed-warm:";
                     } else {
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 0b36c7e..a44eb48 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -33,7 +33,6 @@
 import static android.app.ActivityTaskManager.INVALID_TASK_ID;
 import static android.app.AppOpsManager.MODE_ALLOWED;
 import static android.app.AppOpsManager.OP_PICTURE_IN_PICTURE;
-import static android.app.CameraCompatTaskInfo.CAMERA_COMPAT_FREEFORM_NONE;
 import static android.app.WaitResult.INVALID_DELAY;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_DREAM;
@@ -42,7 +41,6 @@
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
 import static android.app.WindowConfiguration.ROTATION_UNDEFINED;
-import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
 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;
@@ -880,8 +878,6 @@
     })
     @interface SplashScreenBehavior { }
 
-    // TODO: Have a WindowContainer state for tracking exiting/deferred removal.
-    boolean mIsExiting;
     // Force an app transition to be ran in the case the visibility of the app did not change.
     // We use this for the case of moving a Root Task to the back with multiple activities, and the
     // top activity enters PIP; the bottom activity's visibility stays the same, but we need to
@@ -1227,10 +1223,9 @@
             pw.print(" lastAllDrawn="); pw.print(mLastAllDrawn);
             pw.println(")");
         }
-        if (mStartingData != null || firstWindowDrawn || mIsExiting) {
+        if (mStartingData != null || firstWindowDrawn) {
             pw.print(prefix); pw.print("startingData="); pw.print(mStartingData);
-            pw.print(" firstWindowDrawn="); pw.print(firstWindowDrawn);
-            pw.print(" mIsExiting="); pw.println(mIsExiting);
+            pw.print(" firstWindowDrawn="); pw.println(firstWindowDrawn);
         }
         if (mStartingWindow != null || mStartingData != null || mStartingSurface != null
                 || startingMoved || mVisibleSetFromTransferredStartingWindow) {
@@ -3201,6 +3196,9 @@
         if (!compatEnabled && !mWmService.mConstants.mIgnoreActivityOrientationRequest) {
             return false;
         }
+        if (mWmService.mConstants.isPackageOptOutIgnoreActivityOrientationRequest(packageName)) {
+            return false;
+        }
         // If the user preference respects aspect ratio, then it becomes non-resizable.
         return !mAppCompatController.getAppCompatOverrides().getAppCompatAspectRatioOverrides()
                 .shouldApplyUserMinAspectRatioOverride();
@@ -4370,21 +4368,6 @@
         super.removeImmediately();
     }
 
-    @Override
-    void removeIfPossible() {
-        mIsExiting = false;
-        removeAllWindowsIfPossible();
-        removeImmediately();
-    }
-
-    @Override
-    boolean handleCompleteDeferredRemoval() {
-        if (mIsExiting) {
-            removeIfPossible();
-        }
-        return super.handleCompleteDeferredRemoval();
-    }
-
     void onRemovedFromDisplay() {
         if (mRemovingFromDisplay) {
             return;
@@ -5895,6 +5878,7 @@
             return;
         }
 
+        final State prevState = mState;
         mState = state;
 
         if (getTaskFragment() != null) {
@@ -5935,6 +5919,14 @@
                 mAtmService.updateBatteryStats(this, false);
                 mAtmService.updateActivityUsageStats(this, Event.ACTIVITY_PAUSED);
                 break;
+            case STOPPING:
+                // It is possible that an Activity is scheduled to be STOPPED directly from RESUMED
+                // state. Updating the PAUSED usage state in that case, since the Activity will be
+                // STOPPED while cycled through the PAUSED state.
+                if (prevState == RESUMED) {
+                    mAtmService.updateActivityUsageStats(this, Event.ACTIVITY_PAUSED);
+                }
+                break;
             case STOPPED:
                 mAtmService.updateActivityUsageStats(this, Event.ACTIVITY_STOPPED);
                 if (mDisplayContent != null) {
@@ -8400,15 +8392,12 @@
         // and back which can cause visible issues (see b/184078928).
         final int parentWindowingMode =
                 newParentConfiguration.windowConfiguration.getWindowingMode();
-        final boolean isInCameraCompatFreeform = parentWindowingMode == WINDOWING_MODE_FREEFORM
-                && mAppCompatController.getAppCompatCameraOverrides().getFreeformCameraCompatMode()
-                        != CAMERA_COMPAT_FREEFORM_NONE;
 
         // Bubble activities should always fill their parent and should not be letterboxed.
         final boolean isFixedOrientationLetterboxAllowed = !getLaunchedFromBubble()
                 && (parentWindowingMode == WINDOWING_MODE_MULTI_WINDOW
                         || parentWindowingMode == WINDOWING_MODE_FULLSCREEN
-                        || isInCameraCompatFreeform
+                        || AppCompatCameraPolicy.shouldCameraCompatControlOrientation(this)
                         // When starting to switch between PiP and fullscreen, the task is pinned
                         // and the activity is fullscreen. But only allow to apply letterbox if the
                         // activity is exiting PiP because an entered PiP should fill the task.
diff --git a/services/core/java/com/android/server/wm/ActivityStartController.java b/services/core/java/com/android/server/wm/ActivityStartController.java
index 35ec5ad..0580d4a 100644
--- a/services/core/java/com/android/server/wm/ActivityStartController.java
+++ b/services/core/java/com/android/server/wm/ActivityStartController.java
@@ -43,7 +43,6 @@
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.os.Binder;
-import android.os.Bundle;
 import android.os.IBinder;
 import android.os.Trace;
 import android.os.UserHandle;
@@ -550,14 +549,14 @@
      * Starts an activity in the TaskFragment.
      * @param taskFragment TaskFragment {@link TaskFragment} to start the activity in.
      * @param activityIntent intent to start the activity.
-     * @param activityOptions ActivityOptions to start the activity with.
+     * @param activityOptions SafeActivityOptions to start the activity with.
      * @param resultTo the caller activity
      * @param callingUid the caller uid
      * @param callingPid the caller pid
      * @return the start result.
      */
     int startActivityInTaskFragment(@NonNull TaskFragment taskFragment,
-            @NonNull Intent activityIntent, @Nullable Bundle activityOptions,
+            @NonNull Intent activityIntent, @Nullable SafeActivityOptions activityOptions,
             @Nullable IBinder resultTo, int callingUid, int callingPid,
             @Nullable IBinder errorCallbackToken) {
         final ActivityRecord caller =
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index dc960a0..3dfc8f4 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -1228,6 +1228,7 @@
             String callingFeatureId, Intent intent, String resolvedType, IBinder resultTo,
             String resultWho, int requestCode, int startFlags, ProfilerInfo profilerInfo,
             Bundle bOptions) {
+        mAmInternal.addCreatorToken(intent);
         return startActivityAsUser(caller, callingPackage, callingFeatureId, intent, resolvedType,
                 resultTo, resultWho, requestCode, startFlags, profilerInfo, bOptions,
                 UserHandle.getCallingUserId());
@@ -1240,6 +1241,11 @@
         assertPackageMatchesCallingUid(callingPackage);
         final String reason = "startActivities";
         enforceNotIsolatedCaller(reason);
+        if (intents != null) {
+            for (Intent intent : intents) {
+                mAmInternal.addCreatorToken(intent);
+            }
+        }
         userId = handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), userId, reason);
         // TODO: Switch to user app stacks here.
         return getActivityStartController().startActivities(caller, -1, 0, -1, callingPackage,
@@ -1269,6 +1275,7 @@
             @Nullable String callingFeatureId, Intent intent, String resolvedType,
             IBinder resultTo, String resultWho, int requestCode, int startFlags,
             ProfilerInfo profilerInfo, Bundle bOptions, int userId, boolean validateIncomingUser) {
+        mAmInternal.addCreatorToken(intent);
         final SafeActivityOptions opts = SafeActivityOptions.fromBundle(bOptions);
 
         assertPackageMatchesCallingUid(callingPackage);
@@ -1323,6 +1330,7 @@
             }
             // Remove existing mismatch flag so it can be properly updated later
             fillInIntent.removeExtendedFlags(Intent.EXTENDED_FLAG_FILTER_MISMATCH);
+            mAmInternal.addCreatorToken(fillInIntent);
         }
 
         if (!(target instanceof PendingIntentRecord)) {
@@ -1352,6 +1360,9 @@
         if (intent != null && intent.hasFileDescriptors()) {
             throw new IllegalArgumentException("File descriptors passed in Intent");
         }
+
+        mAmInternal.addCreatorToken(intent);
+
         SafeActivityOptions options = SafeActivityOptions.fromBundle(bOptions);
 
         synchronized (mGlobalLock) {
diff --git a/services/core/java/com/android/server/wm/AppCompatCameraPolicy.java b/services/core/java/com/android/server/wm/AppCompatCameraPolicy.java
index 1d00136..8c5689c1 100644
--- a/services/core/java/com/android/server/wm/AppCompatCameraPolicy.java
+++ b/services/core/java/com/android/server/wm/AppCompatCameraPolicy.java
@@ -22,6 +22,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.app.CameraCompatTaskInfo;
 import android.content.pm.ActivityInfo.ScreenOrientation;
 import android.content.res.Configuration;
 import android.widget.Toast;
@@ -250,6 +251,14 @@
                 cameraCompatFreeformPolicyAspectRatio);
     }
 
+    @CameraCompatTaskInfo.FreeformCameraCompatMode
+    static int getCameraCompatFreeformMode(@NonNull ActivityRecord activity) {
+        final AppCompatCameraPolicy cameraPolicy = getAppCompatCameraPolicy(activity);
+        return cameraPolicy != null && cameraPolicy.mCameraCompatFreeformPolicy != null
+                ? cameraPolicy.mCameraCompatFreeformPolicy.getCameraCompatMode(activity)
+                : CameraCompatTaskInfo.CAMERA_COMPAT_FREEFORM_NONE;
+    }
+
     /**
      * Whether we should apply the min aspect ratio per-app override only when an app is connected
      * to the camera.
diff --git a/services/core/java/com/android/server/wm/AppCompatOrientationOverrides.java b/services/core/java/com/android/server/wm/AppCompatOrientationOverrides.java
index bd01351..c84711d 100644
--- a/services/core/java/com/android/server/wm/AppCompatOrientationOverrides.java
+++ b/services/core/java/com/android/server/wm/AppCompatOrientationOverrides.java
@@ -16,6 +16,7 @@
 
 package com.android.server.wm;
 
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
 import static android.content.pm.ActivityInfo.OVERRIDE_ANY_ORIENTATION;
 import static android.content.pm.ActivityInfo.OVERRIDE_ENABLE_COMPAT_IGNORE_ORIENTATION_REQUEST_WHEN_LOOP_DETECTED;
 import static android.content.pm.ActivityInfo.OVERRIDE_ENABLE_COMPAT_IGNORE_REQUESTED_ORIENTATION;
@@ -106,6 +107,16 @@
         return isChangeEnabled(mActivityRecord, OVERRIDE_RESPECT_REQUESTED_ORIENTATION);
     }
 
+    boolean shouldRespectRequestedOrientationDueToOverride() {
+        // Checking TaskFragment rather than ActivityRecord to ensure that transition
+        // between fullscreen and PiP would work well. Checking TaskFragment rather than
+        // Task to ensure that Activity Embedding is excluded.
+        return mActivityRecord.isVisibleRequested() && mActivityRecord.getTaskFragment() != null
+                && mActivityRecord.getTaskFragment().getWindowingMode() == WINDOWING_MODE_FULLSCREEN
+                && mActivityRecord.mAppCompatController.getAppCompatOrientationOverrides()
+                    .isOverrideRespectRequestedOrientationEnabled();
+    }
+
     /**
      * Whether an app is calling {@link android.app.Activity#setRequestedOrientation}
      * in a loop and orientation request should be ignored.
diff --git a/services/core/java/com/android/server/wm/AppCompatUtils.java b/services/core/java/com/android/server/wm/AppCompatUtils.java
index 69421d0..8d84248 100644
--- a/services/core/java/com/android/server/wm/AppCompatUtils.java
+++ b/services/core/java/com/android/server/wm/AppCompatUtils.java
@@ -185,8 +185,8 @@
                         && aspectRatioOverrides.shouldEnableUserAspectRatioSettings();
         appCompatTaskInfo.setEligibleForUserAspectRatioButton(eligibleForAspectRatioButton);
         appCompatTaskInfo.setTopActivityLetterboxed(top.areBoundsLetterboxed());
-        appCompatTaskInfo.cameraCompatTaskInfo.freeformCameraCompatMode = top.mAppCompatController
-                .getAppCompatCameraOverrides().getFreeformCameraCompatMode();
+        appCompatTaskInfo.cameraCompatTaskInfo.freeformCameraCompatMode =
+                AppCompatCameraPolicy.getCameraCompatFreeformMode(top);
         appCompatTaskInfo.setHasMinAspectRatioOverride(top.mAppCompatController
                 .getDesktopAppCompatAspectRatioPolicy().hasMinAspectRatioOverride(task));
     }
diff --git a/services/core/java/com/android/server/wm/AppTaskImpl.java b/services/core/java/com/android/server/wm/AppTaskImpl.java
index d699af8..4d17ed2 100644
--- a/services/core/java/com/android/server/wm/AppTaskImpl.java
+++ b/services/core/java/com/android/server/wm/AppTaskImpl.java
@@ -160,6 +160,7 @@
             Intent intent, String resolvedType, Bundle bOptions) {
         checkCallerOrSystemOrRoot();
         mService.assertPackageMatchesCallingUid(callingPackage);
+        mService.mAmInternal.addCreatorToken(intent);
 
         int callingUser = UserHandle.getCallingUserId();
         Task task;
diff --git a/services/core/java/com/android/server/wm/CameraCompatFreeformPolicy.java b/services/core/java/com/android/server/wm/CameraCompatFreeformPolicy.java
index 4f0cbf9..2a0252a 100644
--- a/services/core/java/com/android/server/wm/CameraCompatFreeformPolicy.java
+++ b/services/core/java/com/android/server/wm/CameraCompatFreeformPolicy.java
@@ -21,6 +21,8 @@
 import static android.app.CameraCompatTaskInfo.CAMERA_COMPAT_FREEFORM_NONE;
 import static android.app.CameraCompatTaskInfo.CAMERA_COMPAT_FREEFORM_PORTRAIT_DEVICE_IN_LANDSCAPE;
 import static android.app.CameraCompatTaskInfo.CAMERA_COMPAT_FREEFORM_PORTRAIT_DEVICE_IN_PORTRAIT;
+import static android.app.WindowConfiguration.WINDOW_CONFIG_APP_BOUNDS;
+import static android.app.WindowConfiguration.WINDOW_CONFIG_DISPLAY_ROTATION;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LOCKED;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_NOSENSOR;
 import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
@@ -35,6 +37,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.app.CameraCompatTaskInfo;
 import android.content.pm.ActivityInfo;
 import android.content.res.Configuration;
 import android.view.DisplayInfo;
@@ -64,8 +67,6 @@
     @NonNull
     private final CameraStateMonitor mCameraStateMonitor;
 
-    private boolean mIsCameraCompatTreatmentPending = false;
-
     @Nullable
     private Task mCameraTask;
 
@@ -100,13 +101,27 @@
         return mIsRunning;
     }
 
-    // Refreshing only when configuration changes after rotation or camera split screen aspect ratio
-    // treatment is enabled.
+    // Refreshing only when configuration changes after applying camera compat treatment.
     @Override
     public boolean shouldRefreshActivity(@NonNull ActivityRecord activity,
             @NonNull Configuration newConfig,
             @NonNull Configuration lastReportedConfig) {
-        return isTreatmentEnabledForActivity(activity) && mIsCameraCompatTreatmentPending;
+        return isTreatmentEnabledForActivity(activity, /* shouldCheckOrientation= */ true)
+                && haveCameraCompatAttributesChanged(newConfig, lastReportedConfig);
+    }
+
+    private boolean haveCameraCompatAttributesChanged(@NonNull Configuration newConfig,
+            @NonNull Configuration lastReportedConfig) {
+        // Camera compat treatment changes the following:
+        // - Letterboxes app bounds to camera compat aspect ratio in app's requested orientation,
+        // - Changes display rotation so it matches what the app expects in its chosen orientation,
+        // - Rotate-and-crop camera feed to match that orientation (this changes iff the display
+        //     rotation changes, so no need to check).
+        final long diff = newConfig.windowConfiguration.diff(lastReportedConfig.windowConfiguration,
+                /* compareUndefined= */ true);
+        final boolean appBoundsChanged = (diff & WINDOW_CONFIG_APP_BOUNDS) != 0;
+        final boolean displayRotationChanged = (diff & WINDOW_CONFIG_DISPLAY_ROTATION) != 0;
+        return appBoundsChanged || displayRotationChanged;
     }
 
     /**
@@ -132,22 +147,26 @@
     @Override
     public void onCameraOpened(@NonNull ActivityRecord cameraActivity,
             @NonNull String cameraId) {
-        if (!isTreatmentEnabledForActivity(cameraActivity)) {
+        // Do not check orientation outside of the config recompute, as the app's orientation intent
+        // might be obscured by a fullscreen override. Especially for apps which have a camera
+        // functionality which is not the main focus of the app: while most of the app might work
+        // well in fullscreen, often the camera setup still assumes it will run on a portrait device
+        // in its natural orientation and comes out stretched or sideways.
+        // Config recalculation will later check the original orientation to avoid applying
+        // treatment to apps optimized for large screens.
+        if (!isTreatmentEnabledForActivity(cameraActivity, /* shouldCheckOrientation= */ false)) {
             return;
         }
-        final int existingCameraCompatMode = cameraActivity.mAppCompatController
-                .getAppCompatCameraOverrides()
-                        .getFreeformCameraCompatMode();
-        final int newCameraCompatMode = getCameraCompatMode(cameraActivity);
-        if (newCameraCompatMode != existingCameraCompatMode) {
-            mIsCameraCompatTreatmentPending = true;
-            mCameraTask = cameraActivity.getTask();
-            cameraActivity.mAppCompatController.getAppCompatCameraOverrides()
-                    .setFreeformCameraCompatMode(newCameraCompatMode);
-            forceUpdateActivityAndTask(cameraActivity);
-        } else {
-            mIsCameraCompatTreatmentPending = false;
-        }
+
+        cameraActivity.recomputeConfiguration();
+        updateCameraCompatMode(cameraActivity);
+        cameraActivity.getTask().dispatchTaskInfoChangedIfNeeded(/* force= */ true);
+        cameraActivity.ensureActivityConfiguration(/* ignoreVisibility= */ false);
+    }
+
+    private void updateCameraCompatMode(@NonNull ActivityRecord cameraActivity) {
+        cameraActivity.mAppCompatController.getAppCompatCameraOverrides()
+                .setFreeformCameraCompatMode(getCameraCompatMode(cameraActivity));
     }
 
     @Override
@@ -167,7 +186,6 @@
             }
         }
         mCameraTask = null;
-        mIsCameraCompatTreatmentPending = false;
         return true;
     }
 
@@ -184,13 +202,12 @@
         // Camera compat should direct aspect ratio when in camera compat mode, unless an app has a
         // different camera compat aspect ratio set: this allows per-app camera compat override
         // aspect ratio to be smaller than the default.
-        return isInCameraCompatMode(activity) && !activity.mAppCompatController
+        return isInFreeformCameraCompatMode(activity) && !activity.mAppCompatController
                 .getAppCompatCameraOverrides().isOverrideMinAspectRatioForCameraEnabled();
     }
 
-    private boolean isInCameraCompatMode(@NonNull ActivityRecord activity) {
-        return activity.mAppCompatController.getAppCompatCameraOverrides()
-                .getFreeformCameraCompatMode() != CAMERA_COMPAT_FREEFORM_NONE;
+    boolean isInFreeformCameraCompatMode(@NonNull ActivityRecord activity) {
+        return getCameraCompatMode(activity) != CAMERA_COMPAT_FREEFORM_NONE;
     }
 
     float getCameraCompatAspectRatio(@NonNull ActivityRecord activityRecord) {
@@ -201,16 +218,11 @@
         return MIN_FIXED_ORIENTATION_LETTERBOX_ASPECT_RATIO;
     }
 
-    private void forceUpdateActivityAndTask(ActivityRecord cameraActivity) {
-        cameraActivity.recomputeConfiguration();
-        cameraActivity.updateReportedConfigurationAndSend();
-        Task cameraTask = cameraActivity.getTask();
-        if (cameraTask != null) {
-            cameraTask.dispatchTaskInfoChangedIfNeeded(/* force= */ true);
+    @CameraCompatTaskInfo.FreeformCameraCompatMode
+    int getCameraCompatMode(@NonNull ActivityRecord topActivity) {
+        if (!isTreatmentEnabledForActivity(topActivity, /* shouldCheckOrientation= */ true)) {
+            return CAMERA_COMPAT_FREEFORM_NONE;
         }
-    }
-
-    private static int getCameraCompatMode(@NonNull ActivityRecord topActivity) {
         final int appOrientation = topActivity.getRequestedConfigurationOrientation();
         // It is very important to check the original (actual) display rotation, and not the
         // sandboxed rotation that camera compat treatment sets.
@@ -250,15 +262,24 @@
      * <ul>
      *     <li>Treatment is enabled.
      *     <li>Camera is active for the package.
-     *     <li>The app has a fixed orientation.
+     *     <li>The app has a fixed orientation if {@code checkOrientation} is true.
      *     <li>The app is in freeform windowing mode.
      * </ul>
+     *
+     * @param checkOrientation Whether to take apps orientation into account for this check. Only
+     *                         fixed-orientation apps should be targeted, but this might be
+     *                         obscured by OEMs via fullscreen override and the app's original
+     *                         intent inaccessible when the camera opens. Thus, policy would pass
+     *                         {@code false} here when considering whether to trigger config
+     *                         recalculation, and later pass {@code true} during recalculation.
      */
-    private boolean isTreatmentEnabledForActivity(@NonNull ActivityRecord activity) {
+    @VisibleForTesting
+    boolean isTreatmentEnabledForActivity(@NonNull ActivityRecord activity,
+            boolean checkOrientation) {
         int orientation = activity.getRequestedConfigurationOrientation();
         return isCameraCompatForFreeformEnabledForActivity(activity)
                 && mCameraStateMonitor.isCameraRunningForActivity(activity)
-                && orientation != ORIENTATION_UNDEFINED
+                && (!checkOrientation || orientation != ORIENTATION_UNDEFINED)
                 && activity.inFreeformWindowingMode()
                 // "locked" and "nosensor" values are often used by camera apps that can't
                 // handle dynamic changes so we shouldn't force-letterbox them.
@@ -270,7 +291,7 @@
 
     private boolean isActivityForCameraIdRefreshing(@NonNull ActivityRecord topActivity,
             @NonNull String cameraId) {
-        if (!isTreatmentEnabledForActivity(topActivity)
+        if (!isTreatmentEnabledForActivity(topActivity, /* checkOrientation= */ true)
                 || mCameraStateMonitor.isCameraWithIdRunningForActivity(topActivity, cameraId)) {
             return false;
         }
diff --git a/services/core/java/com/android/server/wm/ConfigurationContainer.java b/services/core/java/com/android/server/wm/ConfigurationContainer.java
index 670a61d..05dcbb7 100644
--- a/services/core/java/com/android/server/wm/ConfigurationContainer.java
+++ b/services/core/java/com/android/server/wm/ConfigurationContainer.java
@@ -25,6 +25,7 @@
 import static android.app.WindowConfiguration.ROTATION_UNDEFINED;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
 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.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
 import static android.app.WindowConfiguration.activityTypeToString;
@@ -268,7 +269,16 @@
             }
             final DisplayPolicy.DecorInsets.Info decor =
                     displayContent.getDisplayPolicy().getDecorInsetsInfo(rotation, dw, dh);
-            outAppBounds.intersectUnchecked(decor.mOverrideNonDecorFrame);
+            if (!outAppBounds.intersect(decor.mOverrideNonDecorFrame)) {
+                // TODO (b/364883053): When a split screen is requested from an app intent for a new
+                //  task, the bounds is not the final bounds, and this is also not a bounds change
+                //  event handled correctly with the offset. Revert back to legacy method for this
+                //  case.
+                if (inOutConfig.windowConfiguration.getWindowingMode()
+                        == WINDOWING_MODE_MULTI_WINDOW) {
+                    outAppBounds.inset(decor.mOverrideNonDecorInsets);
+                }
+            }
             if (task != null && (task.mOffsetYForInsets != 0 || task.mOffsetXForInsets != 0)) {
                 outAppBounds.offset(-task.mOffsetXForInsets, -task.mOffsetYForInsets);
             }
diff --git a/services/core/java/com/android/server/wm/ContentRecorder.java b/services/core/java/com/android/server/wm/ContentRecorder.java
index bc33946..0b5872b 100644
--- a/services/core/java/com/android/server/wm/ContentRecorder.java
+++ b/services/core/java/com/android/server/wm/ContentRecorder.java
@@ -285,6 +285,11 @@
         }
     }
 
+    private boolean isDisplayReadyForMirroring() {
+        return mDisplayContent.getDisplayInfo().type != Display.TYPE_EXTERNAL
+                || mDisplayContent.mWmService.mDisplayManagerInternal.isDisplayReadyForMirroring(
+                        mDisplayContent.getDisplayId());
+    }
 
     /**
      * Ensure recording does not fall back to the display stack; ensure the recording is stopped
@@ -335,7 +340,7 @@
             return;
         }
 
-        if (mContentRecordingSession.isWaitingForConsent()) {
+        if (mContentRecordingSession.isWaitingForConsent() || !isDisplayReadyForMirroring()) {
             ProtoLog.v(WM_DEBUG_CONTENT_RECORDING, "Content Recording: waiting to record, so do "
                     + "nothing");
             return;
diff --git a/services/core/java/com/android/server/wm/DesktopModeBoundsCalculator.java b/services/core/java/com/android/server/wm/DesktopModeBoundsCalculator.java
index 34b5f6a..fcf88d3 100644
--- a/services/core/java/com/android/server/wm/DesktopModeBoundsCalculator.java
+++ b/services/core/java/com/android/server/wm/DesktopModeBoundsCalculator.java
@@ -30,14 +30,13 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.ActivityOptions;
-import android.app.TaskInfo;
 import android.content.pm.ActivityInfo.ScreenOrientation;
 import android.content.pm.ActivityInfo.WindowLayout;
 import android.graphics.Rect;
 import android.os.SystemProperties;
 import android.util.Size;
 import android.view.Gravity;
-import android.window.flags.DesktopModeFlags;
+import android.window.DesktopModeFlags;
 
 import java.util.function.Consumer;
 
@@ -98,7 +97,6 @@
     private static Rect calculateInitialBounds(@NonNull Task task,
             @NonNull ActivityRecord activity, @NonNull Rect stableBounds
     ) {
-        final TaskInfo taskInfo = task.getTaskInfo();
         // Display bounds not taking into account insets.
         final TaskDisplayArea displayArea = task.getDisplayArea();
         final Rect screenBounds = displayArea.getBounds();
@@ -118,14 +116,15 @@
         float appAspectRatio = desktopAppCompatAspectRatioPolicy.calculateAspectRatio(task);
         final float tdaWidth = stableBounds.width();
         final float tdaHeight = stableBounds.height();
+        final int taskConfigOrientation = task.getConfiguration().orientation;
         final int activityOrientation = getActivityOrientation(activity, task);
-        final Size initialSize = switch (taskInfo.configuration.orientation) {
+        final Size initialSize = switch (taskConfigOrientation) {
             case ORIENTATION_LANDSCAPE -> {
                 // Device in landscape orientation.
                 if (appAspectRatio == 0) {
                     appAspectRatio = 1;
                 }
-                if (canChangeAspectRatio(desktopAppCompatAspectRatioPolicy, taskInfo, task)) {
+                if (canChangeAspectRatio(desktopAppCompatAspectRatioPolicy, task)) {
                     if (isFixedOrientationPortrait(activityOrientation)) {
                         // For portrait resizeable activities, respect apps fullscreen width but
                         // apply ideal size height.
@@ -143,7 +142,7 @@
                 // Device in portrait orientation.
                 final int customPortraitWidthForLandscapeApp = screenBounds.width()
                         - (DESKTOP_MODE_LANDSCAPE_APP_PADDING * 2);
-                if (canChangeAspectRatio(desktopAppCompatAspectRatioPolicy, taskInfo, task)) {
+                if (canChangeAspectRatio(desktopAppCompatAspectRatioPolicy, task)) {
                     if (isFixedOrientationLandscape(activityOrientation)) {
                         if (appAspectRatio == 0) {
                             appAspectRatio = tdaWidth / (tdaWidth - 1);
@@ -182,8 +181,8 @@
      */
     private static boolean canChangeAspectRatio(
             @NonNull DesktopAppCompatAspectRatioPolicy desktopAppCompatAspectRatioPolicy,
-            @NonNull TaskInfo taskInfo, @NonNull Task task) {
-        return taskInfo.isResizeable
+            @NonNull Task task) {
+        return task.isResizeable()
                 && !desktopAppCompatAspectRatioPolicy.hasMinAspectRatioOverride(task);
     }
 
diff --git a/services/core/java/com/android/server/wm/DesktopModeHelper.java b/services/core/java/com/android/server/wm/DesktopModeHelper.java
index b5ea0bd..6bf1c46 100644
--- a/services/core/java/com/android/server/wm/DesktopModeHelper.java
+++ b/services/core/java/com/android/server/wm/DesktopModeHelper.java
@@ -19,7 +19,7 @@
 import android.annotation.NonNull;
 import android.content.Context;
 import android.os.SystemProperties;
-import android.window.flags.DesktopModeFlags;
+import android.window.DesktopModeFlags;
 
 import com.android.internal.R;
 import com.android.internal.annotations.VisibleForTesting;
diff --git a/services/core/java/com/android/server/wm/DisplayArea.java b/services/core/java/com/android/server/wm/DisplayArea.java
index 0416f74..29ffda7 100644
--- a/services/core/java/com/android/server/wm/DisplayArea.java
+++ b/services/core/java/com/android/server/wm/DisplayArea.java
@@ -16,7 +16,6 @@
 
 package com.android.server.wm;
 
-import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
@@ -260,15 +259,14 @@
         if (mDisplayContent == null) {
             return false;
         }
-        ActivityRecord activity = mDisplayContent.topRunningActivity(
-                /* considerKeyguardState= */ true);
-        return activity != null && activity.getTaskFragment() != null
-                // Checking TaskFragment rather than ActivityRecord to ensure that transition
-                // between fullscreen and PiP would work well. Checking TaskFragment rather than
-                // Task to ensure that Activity Embedding is excluded.
-                && activity.getTaskFragment().getWindowingMode() == WINDOWING_MODE_FULLSCREEN
-                && activity.mAppCompatController.getAppCompatOrientationOverrides()
-                    .isOverrideRespectRequestedOrientationEnabled();
+
+        // Top running activity can be freeform and ignore orientation request from bottom activity
+        // that should be respected, Check all activities in display to make sure any eligible
+        // activity should be respected.
+        final ActivityRecord activity = mDisplayContent.getActivity((r) ->
+                r.mAppCompatController.getAppCompatOrientationOverrides()
+                    .shouldRespectRequestedOrientationDueToOverride());
+        return activity != null;
     }
 
     boolean getIgnoreOrientationRequest() {
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index c062f5a..04a625b 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -79,6 +79,7 @@
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
+import static com.android.window.flags.Flags.enableFullyImmersiveInDesktop;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -2515,10 +2516,16 @@
                 defaultTaskDisplayArea.getRootTask(task -> task.isVisible()
                         && task.getTopLeafTask().getAdjacentTask() != null)
                         != null;
-        final boolean freeformRootTaskVisible =
-                defaultTaskDisplayArea.isRootTaskVisible(WINDOWING_MODE_FREEFORM);
+        final Task topFreeformTask = defaultTaskDisplayArea
+                .getTopRootTaskInWindowingMode(WINDOWING_MODE_FREEFORM);
+        final boolean freeformRootTaskVisible = topFreeformTask != null
+                && topFreeformTask.isVisible();
+        final boolean inNonFullscreenFreeformMode = freeformRootTaskVisible
+                && !topFreeformTask.getBounds().equals(mDisplayContent.getBounds());
 
-        getInsetsPolicy().updateSystemBars(win, adjacentTasksVisible, freeformRootTaskVisible);
+        getInsetsPolicy().updateSystemBars(win, adjacentTasksVisible,
+                enableFullyImmersiveInDesktop()
+                        ? inNonFullscreenFreeformMode : freeformRootTaskVisible);
 
         final boolean topAppHidesStatusBar = topAppHidesSystemBar(Type.statusBars());
         if (getStatusBar() != null) {
diff --git a/services/core/java/com/android/server/wm/InputManagerCallback.java b/services/core/java/com/android/server/wm/InputManagerCallback.java
index dcf0319..a4fe064 100644
--- a/services/core/java/com/android/server/wm/InputManagerCallback.java
+++ b/services/core/java/com/android/server/wm/InputManagerCallback.java
@@ -16,6 +16,7 @@
 package com.android.server.wm;
 
 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
+import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
 import static android.view.Display.DEFAULT_DISPLAY;
 
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_INPUT;
@@ -28,9 +29,12 @@
 import android.gui.StalledTransactionInfo;
 import android.os.Debug;
 import android.os.IBinder;
+import android.os.Trace;
 import android.util.Slog;
+import android.util.SparseIntArray;
 import android.view.Display;
 import android.view.InputApplicationHandle;
+import android.view.InputDevice;
 import android.view.KeyEvent;
 import android.view.SurfaceControl;
 import android.view.WindowManager;
@@ -64,6 +68,12 @@
     // which point the ActivityManager will enable dispatching.
     private boolean mInputDispatchEnabled;
 
+    /**
+     * The last input devices info which may affect display configuration. This is a quick lookup
+     * to detect interested changes without entering WM lock.
+     */
+    private SparseIntArray mLastInputConfigurationSources;
+
     public InputManagerCallback(WindowManagerService service) {
         mService = service;
     }
@@ -117,8 +127,16 @@
     /** Notifies that the input device configuration has changed. */
     @Override
     public void notifyConfigurationChanged() {
-        synchronized (mService.mGlobalLock) {
-            mService.mRoot.forAllDisplays(DisplayContent::sendNewConfiguration);
+        Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "notifyConfigurationChanged");
+        final boolean changed = !com.android.window.flags.Flags.filterIrrelevantInputDeviceChange()
+                || updateLastInputConfigurationSources();
+
+        if (changed) {
+            synchronized (mService.mGlobalLock) {
+                Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "inputDeviceConfigChanged");
+                mService.mRoot.forAllDisplays(DisplayContent::sendNewConfiguration);
+                Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
+            }
         }
 
         synchronized (mInputDevicesReadyMonitor) {
@@ -127,6 +145,40 @@
                 mInputDevicesReadyMonitor.notifyAll();
             }
         }
+        Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
+    }
+
+    /** Returns {@code true} if the change of input devices may affect display configuration. */
+    private boolean updateLastInputConfigurationSources() {
+        final InputDevice[] devices = mService.mInputManager.getInputDevices();
+        final SparseIntArray newSources = new SparseIntArray(8);
+        final SparseIntArray lastSources = mLastInputConfigurationSources;
+        boolean changed = lastSources == null;
+        for (InputDevice device : devices) {
+            final String descriptor = device.getDescriptor();
+            if (descriptor == null || device.isVirtual()) {
+                continue;
+            }
+            final int key = descriptor.hashCode();
+            // The interested attributes from DisplayContent#computeScreenConfiguration.
+            int newSourceHash = device.getSources();
+            newSourceHash = newSourceHash * 31 + device.getKeyboardType();
+            newSourceHash = newSourceHash * 31 + device.getAssociatedDisplayId();
+            newSourceHash = newSourceHash * 31 + (device.isExternal() ? 1 : 0);
+            newSourceHash = newSourceHash * 31 + (device.isEnabled() ? 1 : 0);
+            newSources.put(key, newSourceHash);
+            if (lastSources != null && !changed) {
+                final int lastSource = lastSources.get(key, 0 /* valueIfKeyNotFound */);
+                if (lastSource != newSourceHash) {
+                    changed = true;
+                }
+            }
+        }
+        if (lastSources != null && lastSources.size() != newSources.size()) {
+            changed = true;
+        }
+        mLastInputConfigurationSources = newSources;
+        return changed;
     }
 
     /** Notifies that the pointer location configuration has changed. */
diff --git a/services/core/java/com/android/server/wm/InsetsPolicy.java b/services/core/java/com/android/server/wm/InsetsPolicy.java
index 61b13a8..24a6f118 100644
--- a/services/core/java/com/android/server/wm/InsetsPolicy.java
+++ b/services/core/java/com/android/server/wm/InsetsPolicy.java
@@ -628,8 +628,9 @@
         return (mForcedShowingTypes & types) == types;
     }
 
-    void updateSystemBars(WindowState win, boolean inSplitScreenMode, boolean inFreeformMode) {
-        mForcedShowingTypes = (inSplitScreenMode || inFreeformMode)
+    void updateSystemBars(WindowState win, boolean inSplitScreenMode,
+            boolean inNonFullscreenFreeformMode) {
+        mForcedShowingTypes = (inSplitScreenMode || inNonFullscreenFreeformMode)
                 ? (Type.statusBars() | Type.navigationBars())
                 : forceShowingNavigationBars(win)
                         ? Type.navigationBars()
diff --git a/services/core/java/com/android/server/wm/InsetsSourceProvider.java b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
index 8f28f59..6067a99 100644
--- a/services/core/java/com/android/server/wm/InsetsSourceProvider.java
+++ b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
@@ -384,16 +384,19 @@
         }
         final boolean serverVisibleChanged = mServerVisible != isServerVisible;
         setServerVisible(isServerVisible);
-        final boolean positionChanged = updateInsetsControlPosition(windowState);
-        if (mControl != null && !positionChanged
-                // The insets hint would be updated if the position is changed. Here updates it for
-                // the possible change of the bounds or the server visibility.
-                && (updateInsetsHint()
-                        || serverVisibleChanged
-                                && android.view.inputmethod.Flags.refactorInsetsController())) {
-            // Only call notifyControlChanged here when the position is not changed. Otherwise, it
-            // is called or is scheduled to be called during updateInsetsControlPosition.
-            mStateController.notifyControlChanged(mControlTarget, this);
+        if (mControl != null) {
+            final boolean positionChanged = updateInsetsControlPosition(windowState);
+            if (!(positionChanged || mHasPendingPosition)
+                    // The insets hint would be updated while changing the position. Here updates it
+                    // for the possible change of the bounds or the server visibility.
+                    && (updateInsetsHint()
+                            || (android.view.inputmethod.Flags.refactorInsetsController()))
+                                    && serverVisibleChanged) {
+                // Only call notifyControlChanged here when the position hasn't been or won't be
+                // changed. Otherwise, it has been called or scheduled to be called during
+                // updateInsetsControlPosition.
+                mStateController.notifyControlChanged(mControlTarget, this);
+            }
         }
     }
 
@@ -409,6 +412,7 @@
             mPosition.set(position.x, position.y);
             if (windowState != null && windowState.getWindowFrames().didFrameSizeChange()
                     && windowState.mWinAnimator.getShown() && mWindowContainer.okToDisplay()) {
+                mHasPendingPosition = true;
                 windowState.applyWithNextDraw(mSetControlPositionConsumer);
             } else {
                 Transaction t = mWindowContainer.getSyncTransaction();
diff --git a/services/core/java/com/android/server/wm/KeyguardController.java b/services/core/java/com/android/server/wm/KeyguardController.java
index 0c489d6..2fde5aa 100644
--- a/services/core/java/com/android/server/wm/KeyguardController.java
+++ b/services/core/java/com/android/server/wm/KeyguardController.java
@@ -62,6 +62,7 @@
 import com.android.internal.policy.IKeyguardDismissCallback;
 import com.android.server.inputmethod.InputMethodManagerInternal;
 import com.android.server.policy.WindowManagerPolicy;
+import com.android.window.flags.Flags;
 
 import java.io.PrintWriter;
 
@@ -73,6 +74,9 @@
  */
 class KeyguardController {
 
+    private static final boolean ENABLE_NEW_KEYGUARD_SHELL_TRANSITIONS =
+            Flags.ensureKeyguardDoesTransitionStarting();
+
     private static final String TAG = TAG_WITH_CLASS_NAME ? "KeyguardController" : TAG_ATM;
 
     static final String KEYGUARD_SLEEP_TOKEN_TAG = "keyguard";
@@ -201,6 +205,19 @@
             setWakeTransitionReady();
             return;
         }
+
+        if (ENABLE_NEW_KEYGUARD_SHELL_TRANSITIONS) {
+            final TransitionController transitionController =
+                    mWindowManager.mAtmService.getTransitionController();
+            final Transition transition = transitionController.getCollectingTransition();
+            if (transition != null && displayId == DEFAULT_DISPLAY) {
+                if (!keyguardShowing && state.mKeyguardShowing) {
+                    transition.addFlag(TRANSIT_FLAG_KEYGUARD_GOING_AWAY);
+                } else if (keyguardShowing && !state.mKeyguardShowing) {
+                    transition.addFlag(TRANSIT_FLAG_KEYGUARD_APPEARING);
+                }
+            }
+        }
         // Update the task snapshot if the screen will not be turned off. To make sure that the
         // unlocking animation can animate consistent content. The conditions are:
         // - Either AOD or keyguard changes to be showing. So if the states change individually,
@@ -231,8 +248,10 @@
                     || (keyguardShowing && !Display.isOffState(dc.getDisplayInfo().state))) {
                 // Keyguard decided to show or stopped going away. Send a transition to animate back
                 // to the locked state before holding the sleep token again
-                dc.requestTransitionAndLegacyPrepare(
-                        TRANSIT_TO_FRONT, TRANSIT_FLAG_KEYGUARD_APPEARING);
+                if (!ENABLE_NEW_KEYGUARD_SHELL_TRANSITIONS) {
+                    dc.requestTransitionAndLegacyPrepare(
+                            TRANSIT_TO_FRONT, TRANSIT_FLAG_KEYGUARD_APPEARING);
+                }
                 dc.mWallpaperController.adjustWallpaperWindows();
                 dc.executeAppTransition();
             }
diff --git a/services/core/java/com/android/server/wm/Letterbox.java b/services/core/java/com/android/server/wm/Letterbox.java
index 252590e..ca47133 100644
--- a/services/core/java/com/android/server/wm/Letterbox.java
+++ b/services/core/java/com/android/server/wm/Letterbox.java
@@ -19,6 +19,7 @@
 import static android.os.InputConstants.DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
 import static android.view.SurfaceControl.HIDDEN;
 import static android.window.TaskConstants.TASK_CHILD_LAYER_LETTERBOX_BACKGROUND;
+import static android.window.TaskConstants.TASK_CHILD_LAYER_TASK_OVERLAY;
 
 import android.annotation.NonNull;
 import android.graphics.Color;
@@ -37,6 +38,7 @@
 import android.view.WindowManager;
 
 import com.android.server.UiThread;
+import com.android.window.flags.Flags;
 
 import java.util.function.Supplier;
 
@@ -66,6 +68,7 @@
     // for overlaping an app window and letterbox surfaces.
     private final LetterboxSurface mFullWindowSurface = new LetterboxSurface("fullWindow");
     private final LetterboxSurface[] mSurfaces = { mLeft, mTop, mRight, mBottom };
+
     @NonNull
     private final AppCompatReachabilityPolicy mAppCompatReachabilityPolicy;
     @NonNull
@@ -222,12 +225,14 @@
 
     void onMovedToDisplay(int displayId) {
         for (LetterboxSurface surface : mSurfaces) {
-            if (surface.mInputInterceptor != null) {
-                surface.mInputInterceptor.mWindowHandle.displayId = displayId;
-            }
+            setSurfaceDisplayID(surface, displayId);
         }
-        if (mFullWindowSurface.mInputInterceptor != null) {
-            mFullWindowSurface.mInputInterceptor.mWindowHandle.displayId = displayId;
+        setSurfaceDisplayID(mFullWindowSurface, displayId);
+    }
+
+    private void setSurfaceDisplayID(LetterboxSurface surface, int displayId) {
+        if (surface.mInputInterceptor != null) {
+            surface.mInputInterceptor.mWindowHandle.displayId = displayId;
         }
     }
 
@@ -242,14 +247,13 @@
     private final class TapEventReceiver extends InputEventReceiver {
 
         private final GestureDetector mDoubleTapDetector;
-        private final DoubleTapListener mDoubleTapListener;
 
         TapEventReceiver(InputChannel inputChannel, WindowManagerService wmService,
                 Handler uiHandler) {
             super(inputChannel, uiHandler.getLooper());
-            mDoubleTapListener = new DoubleTapListener(wmService);
-            mDoubleTapDetector = new GestureDetector(wmService.mContext, mDoubleTapListener,
-                    uiHandler);
+            final DoubleTapListener doubleTapListener = new DoubleTapListener(wmService);
+            mDoubleTapDetector =
+                    new GestureDetector(wmService.mContext, doubleTapListener, uiHandler);
         }
 
         @Override
@@ -293,7 +297,8 @@
         InputInterceptor(String namePrefix, WindowState win) {
             mWmService = win.mWmService;
             mHandler = UiThread.getHandler();
-            final String name = namePrefix + (win.mActivityRecord != null ? win.mActivityRecord : win);
+            final String name = namePrefix
+                    + (win.mActivityRecord != null ? win.mActivityRecord : win);
             mClientChannel = mWmService.mInputManager.createInputChannel(name);
             mInputEventReceiver = new TapEventReceiver(mClientChannel, mWmService, mHandler);
 
@@ -303,12 +308,15 @@
                     win.getDisplayId());
             mWindowHandle.name = name;
             mWindowHandle.token = mToken;
-            mWindowHandle.layoutParamsType = WindowManager.LayoutParams.TYPE_INPUT_CONSUMER;
+            mWindowHandle.layoutParamsType = Flags.scrollingFromLetterbox()
+                    ? WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY
+                    : WindowManager.LayoutParams.TYPE_INPUT_CONSUMER;
             mWindowHandle.dispatchingTimeoutMillis = DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
             mWindowHandle.ownerPid = WindowManagerService.MY_PID;
             mWindowHandle.ownerUid = WindowManagerService.MY_UID;
             mWindowHandle.scaleFactor = 1.0f;
-            mWindowHandle.inputConfig = InputConfig.NOT_FOCUSABLE | InputConfig.SLIPPERY;
+            mWindowHandle.inputConfig = InputConfig.NOT_FOCUSABLE
+                    | (Flags.scrollingFromLetterbox() ? InputConfig.SPY : InputConfig.SLIPPERY);
         }
 
         void updateTouchableRegion(Rect frame) {
@@ -341,6 +349,7 @@
 
         private final String mType;
         private SurfaceControl mSurface;
+        private SurfaceControl mInputSurface;
         private Color mColor;
         private boolean mHasWallpaperBackground;
         private SurfaceControl mParentSurface;
@@ -373,22 +382,36 @@
                     .setColorSpaceAgnostic(mSurface, true);
         }
 
+        private void createInputSurface(SurfaceControl.Transaction t) {
+            mInputSurface = mSurfaceControlFactory.get()
+                    .setName("LetterboxInput - " + mType)
+                    .setFlags(HIDDEN)
+                    .setContainerLayer()
+                    .setOpaque(true)
+                    .setCallsite("LetterboxSurface.createInputSurface")
+                    .build();
+
+            t.setLayer(mInputSurface, TASK_CHILD_LAYER_TASK_OVERLAY);
+        }
+
         void attachInput(WindowState win) {
             if (mInputInterceptor != null) {
                 mInputInterceptor.dispose();
             }
+            // TODO(b/371179559): only detect double tap on LB surfaces not used for cutout area.
+            // Potentially, the input interceptor may still be needed for slippery feature.
             mInputInterceptor = new InputInterceptor("Letterbox_" + mType + "_", win);
         }
 
-        boolean isRemoved() {
-            return mSurface != null || mInputInterceptor != null;
-        }
-
         public void remove() {
             if (mSurface != null) {
                 mTransactionFactory.get().remove(mSurface).apply();
                 mSurface = null;
             }
+            if (mInputSurface != null) {
+                mTransactionFactory.get().remove(mInputSurface).apply();
+                mInputSurface = null;
+            }
             if (mInputInterceptor != null) {
                 mInputInterceptor.dispose();
                 mInputInterceptor = null;
@@ -415,28 +438,54 @@
                     createSurface(t);
                 }
 
+                if (Flags.scrollingFromLetterbox()
+                        && mInputInterceptor != null
+                        && mInputSurface == null) {
+                    createInputSurface(inputT);
+                }
+
                 mColor = mAppCompatLetterboxOverrides.getLetterboxBackgroundColor();
                 mParentSurface = mParentSurfaceSupplier.get();
                 t.setColor(mSurface, getRgbColorArray());
-                t.setPosition(mSurface, mSurfaceFrameRelative.left, mSurfaceFrameRelative.top);
-                t.setWindowCrop(mSurface, mSurfaceFrameRelative.width(),
-                        mSurfaceFrameRelative.height());
-                t.reparent(mSurface, mParentSurface);
+                setPositionAndReparent(t, mSurface);
 
                 mHasWallpaperBackground = mAppCompatLetterboxOverrides
                         .hasWallpaperBackgroundForLetterbox();
                 updateAlphaAndBlur(t);
 
                 t.show(mSurface);
-            } else if (mSurface != null) {
-                t.hide(mSurface);
+
+                if (mInputSurface != null) {
+                    setPositionAndReparent(inputT, mInputSurface);
+                    inputT.setTrustedOverlay(mInputSurface, true);
+                    inputT.show(mInputSurface);
+                }
+
+            } else {
+                if (mSurface != null) {
+                    t.hide(mSurface);
+                }
+                if (mInputSurface != null) {
+                    inputT.hide(mInputSurface);
+                }
             }
-            if (mSurface != null && mInputInterceptor != null) {
+
+            SurfaceControl surfaceWithInput =
+                    Flags.scrollingFromLetterbox() ? mInputSurface : mSurface;
+            if (surfaceWithInput != null && mInputInterceptor != null) {
                 mInputInterceptor.updateTouchableRegion(mSurfaceFrameRelative);
-                inputT.setInputWindowInfo(mSurface, mInputInterceptor.mWindowHandle);
+                inputT.setInputWindowInfo(surfaceWithInput, mInputInterceptor.mWindowHandle);
             }
         }
 
+        private void setPositionAndReparent(@NonNull SurfaceControl.Transaction t,
+                @NonNull SurfaceControl surface) {
+            t.setPosition(surface, mSurfaceFrameRelative.left, mSurfaceFrameRelative.top);
+            t.setWindowCrop(surface, mSurfaceFrameRelative.width(),
+                    mSurfaceFrameRelative.height());
+            t.reparent(surface, mParentSurface);
+        }
+
         private void updateAlphaAndBlur(SurfaceControl.Transaction t) {
             if (!mHasWallpaperBackground) {
                 // Opaque
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 266fdbb..41a5804 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -1407,7 +1407,7 @@
             displayId = rootTask != null ? rootTask.getDisplayId() : DEFAULT_DISPLAY;
         }
 
-        final DisplayContent display = getDisplayContent(displayId);
+        final DisplayContent display = getDisplayContentOrCreate(displayId);
         return display.reduceOnAllTaskDisplayAreas((taskDisplayArea, result) ->
                         result | startHomeOnTaskDisplayArea(userId, reason, taskDisplayArea,
                                 allowInstrumenting, fromHomeKey),
diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java
index 188b368..585537b 100644
--- a/services/core/java/com/android/server/wm/Transition.java
+++ b/services/core/java/com/android/server/wm/Transition.java
@@ -547,13 +547,12 @@
             if (!ar.isVisible() || !ar.isVisibleRequested()) return;
             if (mConfigAtEndActivities == null) {
                 mConfigAtEndActivities = new ArrayList<>();
-            }
-            if (mConfigAtEndActivities.contains(ar)) {
+            } else if (mConfigAtEndActivities.contains(ar)) {
                 return;
             }
             mConfigAtEndActivities.add(ar);
             ar.pauseConfigurationDispatch();
-            snapshotStartState(ar);
+            collect(ar);
             mChanges.get(ar).mFlags |= ChangeInfo.FLAG_CHANGE_CONFIG_AT_END;
         });
     }
@@ -1705,55 +1704,6 @@
         change.mFlags |= ChangeInfo.FLAG_CHANGE_NO_ANIMATION;
     }
 
-    void prepareConfigAtEnd(SurfaceControl.Transaction transact, ArrayList<ChangeInfo> targets) {
-        if (mConfigAtEndActivities == null) return;
-        for (int i = 0; i < mConfigAtEndActivities.size(); ++i) {
-            final ActivityRecord ar = mConfigAtEndActivities.get(i);
-            if (!ar.isVisibleRequested()) continue;
-            final SurfaceControl sc = ar.getSurfaceControl();
-            if (sc == null) continue;
-            final Task task = ar.getTask();
-            if (task == null) continue;
-            // If task isn't animating, then it means shell is animating activity directly (within
-            // task), so don't do any setup.
-            if (!containsChangeFor(task, targets)) continue;
-            final ChangeInfo change = mChanges.get(ar);
-            final Rect startBounds = change.mAbsoluteBounds;
-            Rect hintRect = null;
-            if (ar.getWindowingMode() == WINDOWING_MODE_PINNED && ar.pictureInPictureArgs != null
-                    && ar.pictureInPictureArgs.getSourceRectHint() != null) {
-                hintRect = ar.pictureInPictureArgs.getSourceRectHint();
-            }
-            if (hintRect == null) {
-                hintRect = new Rect(startBounds);
-                hintRect.offsetTo(0, 0);
-            }
-            final Rect endBounds = ar.getBounds();
-            final Rect taskEndBounds = task.getBounds();
-            // FA = final activity bounds (absolute)
-            // FT = final task bounds (absolute)
-            // SA = start activity bounds (absolute)
-            // H = source hint (relative to start activity bounds)
-            // We want to transform the activity so that when the task is at FT, H overlaps with FA
-
-            // This scales the activity such that the hint rect has the same dimensions
-            // as the final activity bounds.
-            float hintToEndScaleX = ((float) endBounds.width()) / ((float) hintRect.width());
-            float hintToEndScaleY = ((float) endBounds.height()) / ((float) hintRect.height());
-            // top-left needs to be (FA.tl - FT.tl) - H.tl * hintToEnd . H is relative to the
-            // activity; so, for example, if shrinking H to FA (hintToEnd < 1), then the tl of the
-            // shrunk SA is closer to H than expected, so we need to reduce how much we offset SA
-            // to get H.tl to match.
-            float startActPosInTaskEndX =
-                    (endBounds.left - taskEndBounds.left) - hintRect.left * hintToEndScaleX;
-            float startActPosInTaskEndY =
-                    (endBounds.top - taskEndBounds.top) - hintRect.top * hintToEndScaleY;
-            transact.setScale(sc, hintToEndScaleX, hintToEndScaleY);
-            transact.setPosition(sc, startActPosInTaskEndX, startActPosInTaskEndY);
-        }
-    }
-
-    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
     static boolean containsChangeFor(WindowContainer wc, ArrayList<ChangeInfo> list) {
         for (int i = list.size() - 1; i >= 0; --i) {
             if (list.get(i).mContainer == wc) return true;
@@ -1834,7 +1784,6 @@
 
         // Resolve the animating targets from the participants.
         mTargets = calculateTargets(mParticipants, mChanges);
-        prepareConfigAtEnd(transaction, mTargets);
 
         // Check whether the participants were animated from back navigation.
         mController.mAtm.mBackNavigationController.onTransactionReady(this, mTargets,
@@ -2670,6 +2619,11 @@
             if (reportIfNotTop(target)) {
                 ProtoLog.v(WmProtoLogGroups.WM_DEBUG_WINDOW_TRANSITIONS,
                         "        keep as target %s", target);
+            } else if ((targetChange.mFlags & ChangeInfo.FLAG_CHANGE_CONFIG_AT_END) != 0) {
+                // config-at-end activities do not match the end-state, so they should be treated
+                // as independent.
+                ProtoLog.v(WmProtoLogGroups.WM_DEBUG_WINDOW_TRANSITIONS,
+                        "        keep as cfg-at-end target %s", target);
             } else {
                 ProtoLog.v(WmProtoLogGroups.WM_DEBUG_WINDOW_TRANSITIONS,
                         "        remove from targets %s", target);
diff --git a/services/core/java/com/android/server/wm/TransitionController.java b/services/core/java/com/android/server/wm/TransitionController.java
index b7fe327..87bdfa4 100644
--- a/services/core/java/com/android/server/wm/TransitionController.java
+++ b/services/core/java/com/android/server/wm/TransitionController.java
@@ -471,6 +471,16 @@
         return false;
     }
 
+    /** Returns {@code true} if the `wc` is a target of a playing transition. */
+    boolean isPlayingTarget(@NonNull WindowContainer<?> wc) {
+        for (int i = mPlayingTransitions.size() - 1; i >= 0; --i) {
+            if (Transition.containsChangeFor(wc, mPlayingTransitions.get(i).mTargets)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
     /** Returns {@code true} if the finishing transition contains `wc`. */
     boolean inFinishingTransition(WindowContainer<?> wc) {
         return mFinishingTransition != null && mFinishingTransition.isInTransition(wc);
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index af57c84..95cf6bc 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -36,7 +36,7 @@
 import static android.view.WindowManager.LayoutParams.INVALID_WINDOW_TYPE;
 import static android.view.WindowManager.TRANSIT_CHANGE;
 import static android.window.TaskFragmentAnimationParams.DEFAULT_ANIMATION_BACKGROUND_COLOR;
-import static android.window.flags.DesktopModeFlags.ENABLE_CAPTION_COMPAT_INSET_FORCE_CONSUMPTION;
+import static android.window.DesktopModeFlags.ENABLE_CAPTION_COMPAT_INSET_FORCE_CONSUMPTION;
 
 import static com.android.internal.protolog.WmProtoLogGroups.WM_DEBUG_ANIM;
 import static com.android.internal.protolog.WmProtoLogGroups.WM_DEBUG_APP_TRANSITIONS;
diff --git a/services/core/java/com/android/server/wm/WindowManagerConstants.java b/services/core/java/com/android/server/wm/WindowManagerConstants.java
index e0f24d8..31ca24c 100644
--- a/services/core/java/com/android/server/wm/WindowManagerConstants.java
+++ b/services/core/java/com/android/server/wm/WindowManagerConstants.java
@@ -22,10 +22,12 @@
 import android.provider.AndroidDeviceConfig;
 import android.provider.DeviceConfig;
 import android.provider.DeviceConfigInterface;
+import android.util.ArraySet;
 
 import com.android.internal.annotations.VisibleForTesting;
 
 import java.io.PrintWriter;
+import java.util.Arrays;
 import java.util.Objects;
 import java.util.concurrent.Executor;
 
@@ -38,6 +40,10 @@
     private static final String KEY_IGNORE_ACTIVITY_ORIENTATION_REQUEST =
             "ignore_activity_orientation_request";
 
+    /** The packages that ignore {@link #KEY_IGNORE_ACTIVITY_ORIENTATION_REQUEST}. */
+    private static final String KEY_OPT_OUT_IGNORE_ACTIVITY_ORIENTATION_REQUEST_LIST =
+            "opt_out_ignore_activity_orientation_request_list";
+
     /**
      * The minimum duration between gesture exclusion logging for a given window in
      * milliseconds.
@@ -65,6 +71,9 @@
     /** @see #KEY_IGNORE_ACTIVITY_ORIENTATION_REQUEST */
     boolean mIgnoreActivityOrientationRequest;
 
+    /** @see #KEY_OPT_OUT_IGNORE_ACTIVITY_ORIENTATION_REQUEST_LIST */
+    private ArraySet<String> mOptOutIgnoreActivityOrientationRequestPackages;
+
     private final WindowManagerGlobalLock mGlobalLock;
     private final Runnable mUpdateSystemGestureExclusionCallback;
     private final DeviceConfigInterface mDeviceConfig;
@@ -97,6 +106,7 @@
         updateSystemGestureExclusionLimitDp();
         updateSystemGestureExcludedByPreQStickyImmersive();
         updateIgnoreActivityOrientationRequest();
+        updateOptOutIgnoreActivityOrientationRequestList();
     }
 
     private void onAndroidPropertiesChanged(DeviceConfig.Properties properties) {
@@ -138,6 +148,9 @@
                     case KEY_IGNORE_ACTIVITY_ORIENTATION_REQUEST:
                         updateIgnoreActivityOrientationRequest();
                         break;
+                    case KEY_OPT_OUT_IGNORE_ACTIVITY_ORIENTATION_REQUEST_LIST:
+                        updateOptOutIgnoreActivityOrientationRequestList();
+                        break;
                     default:
                         break;
                 }
@@ -169,6 +182,25 @@
                 KEY_IGNORE_ACTIVITY_ORIENTATION_REQUEST, false);
     }
 
+    private void updateOptOutIgnoreActivityOrientationRequestList() {
+        final String packageList = mDeviceConfig.getString(
+                DeviceConfig.NAMESPACE_WINDOW_MANAGER,
+                KEY_OPT_OUT_IGNORE_ACTIVITY_ORIENTATION_REQUEST_LIST, "");
+        if (packageList.isEmpty()) {
+            mOptOutIgnoreActivityOrientationRequestPackages = null;
+            return;
+        }
+        mOptOutIgnoreActivityOrientationRequestPackages = new ArraySet<>();
+        mOptOutIgnoreActivityOrientationRequestPackages.addAll(
+                Arrays.asList(packageList.split(",")));
+    }
+
+    boolean isPackageOptOutIgnoreActivityOrientationRequest(String packageName) {
+        return mIgnoreActivityOrientationRequest
+                && mOptOutIgnoreActivityOrientationRequestPackages != null
+                && mOptOutIgnoreActivityOrientationRequestPackages.contains(packageName);
+    }
+
     void dump(PrintWriter pw) {
         pw.println("WINDOW MANAGER CONSTANTS (dumpsys window constants):");
 
@@ -180,6 +212,10 @@
         pw.print("="); pw.println(mSystemGestureExcludedByPreQStickyImmersive);
         pw.print("  "); pw.print(KEY_IGNORE_ACTIVITY_ORIENTATION_REQUEST);
         pw.print("="); pw.println(mIgnoreActivityOrientationRequest);
+        if (mOptOutIgnoreActivityOrientationRequestPackages != null) {
+            pw.print("  "); pw.print(KEY_OPT_OUT_IGNORE_ACTIVITY_ORIENTATION_REQUEST_LIST);
+            pw.print("="); pw.println(mOptOutIgnoreActivityOrientationRequestPackages);
+        }
         pw.println();
     }
 }
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index ebf645d..f4ad030 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -2109,7 +2109,7 @@
         ProtoLog.v(WM_DEBUG_ADD_REMOVE, "Removing %s from %s", win, token);
         // Window will already be removed from token before this post clean-up method is called.
         if (token.isEmpty() && !token.mPersistOnEmpty) {
-            token.removeImmediately();
+            token.removeIfPossible();
         }
 
         if (win.mActivityRecord != null) {
diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java
index f8d0bc2..82c7a93 100644
--- a/services/core/java/com/android/server/wm/WindowOrganizerController.java
+++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java
@@ -51,6 +51,7 @@
 import static android.window.WindowContainerTransaction.Change.CHANGE_FORCE_TRANSLUCENT;
 import static android.window.WindowContainerTransaction.Change.CHANGE_HIDDEN;
 import static android.window.WindowContainerTransaction.Change.CHANGE_RELATIVE_BOUNDS;
+import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_SET_KEYGUARD_STATE;
 import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_ADD_INSETS_FRAME_PROVIDER;
 import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_ADD_TASK_FRAGMENT_OPERATION;
 import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_CHILDREN_TASKS_REPARENT;
@@ -121,6 +122,7 @@
 import android.window.ITransitionPlayer;
 import android.window.IWindowContainerTransactionCallback;
 import android.window.IWindowOrganizerController;
+import android.window.KeyguardState;
 import android.window.RemoteTransition;
 import android.window.TaskFragmentAnimationParams;
 import android.window.TaskFragmentCreationParams;
@@ -1253,6 +1255,10 @@
                         caller, errorCallbackToken, organizer);
                 break;
             }
+            case HIERARCHY_OP_TYPE_SET_KEYGUARD_STATE: {
+                effects |= applyKeyguardState(hop);
+                break;
+            }
             case HIERARCHY_OP_TYPE_PENDING_INTENT: {
                 final Bundle launchOpts = hop.getLaunchOptions();
                 ActivityOptions activityOptions = launchOpts != null
@@ -1517,8 +1523,10 @@
                 final IBinder callerActivityToken = operation.getActivityToken();
                 final Intent activityIntent = operation.getActivityIntent();
                 final Bundle activityOptions = operation.getBundle();
+                final SafeActivityOptions safeOptions =
+                        SafeActivityOptions.fromBundle(activityOptions, caller.mPid, caller.mUid);
                 final int result = waitAsyncStart(() -> mService.getActivityStartController()
-                        .startActivityInTaskFragment(taskFragment, activityIntent, activityOptions,
+                        .startActivityInTaskFragment(taskFragment, activityIntent, safeOptions,
                                 callerActivityToken, caller.mUid, caller.mPid,
                                 errorCallbackToken));
                 if (!isStartResultSuccessful(result)) {
@@ -1788,6 +1796,19 @@
         return effects;
     }
 
+    private int applyKeyguardState(@NonNull WindowContainerTransaction.HierarchyOp hop) {
+        int effects = TRANSACT_EFFECTS_NONE;
+
+        final KeyguardState keyguardState = hop.getKeyguardState();
+        if (keyguardState != null) {
+            int displayId = keyguardState.getDisplayId();
+            boolean keyguardShowing = keyguardState.getKeyguardShowing();
+            boolean aodShowing = keyguardState.getAodShowing();
+            mService.mKeyguardController.setKeyguardShown(displayId, keyguardShowing, aodShowing);
+        }
+        return effects;
+    }
+
     /**
      * Executes the provided {@code runnable} after the {@code transition}. If the
      * {@code transition} is {@code null}, the {@code runnable} is executed immediately.
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 66f9230..76f2437 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -2777,6 +2777,9 @@
         }
 
         if (mTmpRect.isEmpty()) {
+            // TODO(b/371182877) If the app does not draw under cutout region, the touchable region
+            // should not include cutout regions (if scrolling from letterbox feature is not desired
+            // for this region).
             final Rect transformedBounds = mActivityRecord.getFixedRotationTransformDisplayBounds();
             if (transformedBounds != null) {
                 // Task is in the same orientation as display, so the rotated bounds should be
diff --git a/services/core/java/com/android/server/wm/WindowToken.java b/services/core/java/com/android/server/wm/WindowToken.java
index 7e7ca12..5bde8b5 100644
--- a/services/core/java/com/android/server/wm/WindowToken.java
+++ b/services/core/java/com/android/server/wm/WindowToken.java
@@ -90,6 +90,9 @@
     // Is key dispatching paused for this token?
     boolean paused = false;
 
+    /** Whether this container should be removed when it no longer animates. */
+    boolean mIsExiting;
+
     /** The owner has {@link android.Manifest.permission#MANAGE_APP_TOKENS} */
     final boolean mOwnerCanManageAppTokens;
 
@@ -276,6 +279,28 @@
         }
     }
 
+    @Override
+    void removeIfPossible() {
+        if (mTransitionController.isPlayingTarget(this)) {
+            // Defer removing this container until the transition is finished. So the removal can
+            // execute after the finish transaction (see Transition#buildFinishTransaction) which
+            // may reparent it to original parent.
+            mIsExiting = true;
+            return;
+        }
+        mIsExiting = false;
+        removeAllWindowsIfPossible();
+        removeImmediately();
+    }
+
+    @Override
+    boolean handleCompleteDeferredRemoval() {
+        if (mIsExiting) {
+            removeIfPossible();
+        }
+        return super.handleCompleteDeferredRemoval();
+    }
+
     /**
      * @return The scale for applications running in compatibility mode. Multiply the size in the
      *         application by this scale will be the size in the screen.
@@ -725,6 +750,9 @@
             pw.print("fixedRotationConfig=");
             pw.println(mFixedRotationTransformState.mRotatedOverrideConfiguration);
         }
+        if (mIsExiting) {
+            pw.print(prefix); pw.println("isExiting=true");
+        }
     }
 
     @Override
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index efca902..248ed1a 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -337,6 +337,8 @@
     int32_t getMousePointerSpeed();
     void setPointerSpeed(int32_t speed);
     void setMousePointerAccelerationEnabled(ui::LogicalDisplayId displayId, bool enabled);
+    void setMouseReverseVerticalScrollingEnabled(bool enabled);
+    void setMouseSwapPrimaryButtonEnabled(bool enabled);
     void setTouchpadPointerSpeed(int32_t speed);
     void setTouchpadNaturalScrollingEnabled(bool enabled);
     void setTouchpadTapToClickEnabled(bool enabled);
@@ -482,6 +484,12 @@
         // True if stylus button reporting through motion events is enabled.
         bool stylusButtonMotionEventsEnabled{true};
 
+        // True if mouse vertical scrolling is reversed.
+        bool mouseReverseVerticalScrollingEnabled{false};
+
+        // True if the mouse primary button is swapped (left/right buttons).
+        bool mouseSwapPrimaryButtonEnabled{false};
+
         // The touchpad pointer speed, as a number from -7 (slowest) to 7 (fastest).
         int32_t touchpadPointerSpeed{0};
 
@@ -762,6 +770,10 @@
 
         outConfig->defaultPointerDisplayId = mLocked.pointerDisplayId;
 
+        outConfig->mouseReverseVerticalScrollingEnabled =
+                mLocked.mouseReverseVerticalScrollingEnabled;
+        outConfig->mouseSwapPrimaryButtonEnabled = mLocked.mouseSwapPrimaryButtonEnabled;
+
         outConfig->touchpadPointerSpeed = mLocked.touchpadPointerSpeed;
         outConfig->touchpadNaturalScrollingEnabled = mLocked.touchpadNaturalScrollingEnabled;
         outConfig->touchpadTapToClickEnabled = mLocked.touchpadTapToClickEnabled;
@@ -1317,6 +1329,36 @@
     return mLocked.pointerSpeed;
 }
 
+void NativeInputManager::setMouseReverseVerticalScrollingEnabled(bool enabled) {
+    { // acquire lock
+        std::scoped_lock _l(mLock);
+
+        if (mLocked.mouseReverseVerticalScrollingEnabled == enabled) {
+            return;
+        }
+
+        mLocked.mouseReverseVerticalScrollingEnabled = enabled;
+    } // release lock
+
+    mInputManager->getReader().requestRefreshConfiguration(
+            InputReaderConfiguration::Change::MOUSE_SETTINGS);
+}
+
+void NativeInputManager::setMouseSwapPrimaryButtonEnabled(bool enabled) {
+    { // acquire lock
+        std::scoped_lock _l(mLock);
+
+        if (mLocked.mouseSwapPrimaryButtonEnabled == enabled) {
+            return;
+        }
+
+        mLocked.mouseSwapPrimaryButtonEnabled = enabled;
+    } // release lock
+
+    mInputManager->getReader().requestRefreshConfiguration(
+            InputReaderConfiguration::Change::MOUSE_SETTINGS);
+}
+
 void NativeInputManager::setPointerSpeed(int32_t speed) {
     { // acquire lock
         std::scoped_lock _l(mLock);
@@ -3002,6 +3044,18 @@
     return static_cast<jint>(im->getInputManager()->getReader().getLastUsedInputDeviceId());
 }
 
+static void nativeSetMouseReverseVerticalScrollingEnabled(JNIEnv* env, jobject nativeImplObj,
+                                                          bool enabled) {
+    NativeInputManager* im = getNativeInputManager(env, nativeImplObj);
+    im->setMouseReverseVerticalScrollingEnabled(enabled);
+}
+
+static void nativeSetMouseSwapPrimaryButtonEnabled(JNIEnv* env, jobject nativeImplObj,
+                                                   bool enabled) {
+    NativeInputManager* im = getNativeInputManager(env, nativeImplObj);
+    im->setMouseSwapPrimaryButtonEnabled(enabled);
+}
+
 // ----------------------------------------------------------------------------
 
 static const JNINativeMethod gInputManagerMethods[] = {
@@ -3048,6 +3102,9 @@
         {"setPointerSpeed", "(I)V", (void*)nativeSetPointerSpeed},
         {"setMousePointerAccelerationEnabled", "(IZ)V",
          (void*)nativeSetMousePointerAccelerationEnabled},
+        {"setMouseReverseVerticalScrollingEnabled", "(Z)V",
+         (void*)nativeSetMouseReverseVerticalScrollingEnabled},
+        {"setMouseSwapPrimaryButtonEnabled", "(Z)V", (void*)nativeSetMouseSwapPrimaryButtonEnabled},
         {"setTouchpadPointerSpeed", "(I)V", (void*)nativeSetTouchpadPointerSpeed},
         {"setTouchpadNaturalScrollingEnabled", "(Z)V",
          (void*)nativeSetTouchpadNaturalScrollingEnabled},
diff --git a/services/core/jni/com_android_server_utils_AnrTimer.cpp b/services/core/jni/com_android_server_utils_AnrTimer.cpp
index 2836d46..2add5b0 100644
--- a/services/core/jni/com_android_server_utils_AnrTimer.cpp
+++ b/services/core/jni/com_android_server_utils_AnrTimer.cpp
@@ -349,7 +349,7 @@
         return nullptr;
     }
 
-    // Return the currently watched pids.  The lock must be held.
+    // Return the currently watched pids as a comma-separated list.  The lock must be held.
     std::string watchedPidsLocked() const {
         if (watched_.size() == 0) return "none";
         bool first = true;
@@ -357,6 +357,7 @@
         for (auto i = watched_.cbegin(); i != watched_.cend(); i++) {
             if (first) {
                 result += StringPrintf("%d", *i);
+                first = false;
             } else {
                 result += StringPrintf(",%d", *i);
             }
diff --git a/services/core/jni/com_android_server_vibrator_VibratorController.cpp b/services/core/jni/com_android_server_vibrator_VibratorController.cpp
index 39c0c3e..903d892 100644
--- a/services/core/jni/com_android_server_vibrator_VibratorController.cpp
+++ b/services/core/jni/com_android_server_vibrator_VibratorController.cpp
@@ -41,6 +41,8 @@
 
 static JavaVM* sJvm = nullptr;
 static jmethodID sMethodIdOnComplete;
+static jclass sFrequencyProfileLegacyClass;
+static jmethodID sFrequencyProfileLegacyCtor;
 static jclass sFrequencyProfileClass;
 static jmethodID sFrequencyProfileCtor;
 static struct {
@@ -53,6 +55,7 @@
     jmethodID setPrimitiveDelayMax;
     jmethodID setCompositionSizeMax;
     jmethodID setQFactor;
+    jmethodID setFrequencyProfileLegacy;
     jmethodID setFrequencyProfile;
     jmethodID setMaxEnvelopeEffectSize;
     jmethodID setMinEnvelopeEffectControlPointDurationMillis;
@@ -517,11 +520,46 @@
         env->SetFloatArrayRegion(maxAmplitudes, 0, amplitudes.size(),
                                  reinterpret_cast<jfloat*>(amplitudes.data()));
     }
-    jobject frequencyProfile =
-            env->NewObject(sFrequencyProfileClass, sFrequencyProfileCtor, resonantFrequency,
-                           minFrequency, frequencyResolution, maxAmplitudes);
-    env->CallObjectMethod(vibratorInfoBuilder, sVibratorInfoBuilderClassInfo.setFrequencyProfile,
-                          frequencyProfile);
+    jobject frequencyProfileLegacy =
+            env->NewObject(sFrequencyProfileLegacyClass, sFrequencyProfileLegacyCtor,
+                           resonantFrequency, minFrequency, frequencyResolution, maxAmplitudes);
+    env->CallObjectMethod(vibratorInfoBuilder,
+                          sVibratorInfoBuilderClassInfo.setFrequencyProfileLegacy,
+                          frequencyProfileLegacy);
+
+    if (info.frequencyToOutputAccelerationMap.isOk()) {
+        size_t mapSize = info.frequencyToOutputAccelerationMap.value().size();
+
+        jfloatArray frequenciesHz = env->NewFloatArray(mapSize);
+        jfloatArray outputAccelerationsGs = env->NewFloatArray(mapSize);
+
+        jfloat* frequenciesHzPtr = env->GetFloatArrayElements(frequenciesHz, nullptr);
+        jfloat* outputAccelerationsGsPtr =
+                env->GetFloatArrayElements(outputAccelerationsGs, nullptr);
+
+        size_t i = 0;
+        for (auto const& dataEntry : info.frequencyToOutputAccelerationMap.value()) {
+            frequenciesHzPtr[i] = static_cast<jfloat>(dataEntry.frequencyHz);
+            outputAccelerationsGsPtr[i] = static_cast<jfloat>(dataEntry.maxOutputAccelerationGs);
+            i++;
+        }
+
+        // Release the float pointers
+        env->ReleaseFloatArrayElements(frequenciesHz, frequenciesHzPtr, 0);
+        env->ReleaseFloatArrayElements(outputAccelerationsGs, outputAccelerationsGsPtr, 0);
+
+        jobject frequencyProfile =
+                env->NewObject(sFrequencyProfileClass, sFrequencyProfileCtor, resonantFrequency,
+                               frequenciesHz, outputAccelerationsGs);
+
+        env->CallObjectMethod(vibratorInfoBuilder,
+                              sVibratorInfoBuilderClassInfo.setFrequencyProfile, frequencyProfile);
+
+        // Delete local references to avoid memory leaks
+        env->DeleteLocalRef(frequenciesHz);
+        env->DeleteLocalRef(outputAccelerationsGs);
+        env->DeleteLocalRef(frequencyProfile);
+    }
 
     return info.shouldRetry() ? JNI_FALSE : JNI_TRUE;
 }
@@ -566,9 +604,16 @@
     sRampClassInfo.endFrequencyHz = GetFieldIDOrDie(env, rampClass, "mEndFrequencyHz", "F");
     sRampClassInfo.duration = GetFieldIDOrDie(env, rampClass, "mDuration", "I");
 
+    jclass frequencyProfileLegacyClass =
+            FindClassOrDie(env, "android/os/VibratorInfo$FrequencyProfileLegacy");
+    sFrequencyProfileLegacyClass =
+            static_cast<jclass>(env->NewGlobalRef(frequencyProfileLegacyClass));
+    sFrequencyProfileLegacyCtor =
+            GetMethodIDOrDie(env, sFrequencyProfileLegacyClass, "<init>", "(FFF[F)V");
+
     jclass frequencyProfileClass = FindClassOrDie(env, "android/os/VibratorInfo$FrequencyProfile");
     sFrequencyProfileClass = static_cast<jclass>(env->NewGlobalRef(frequencyProfileClass));
-    sFrequencyProfileCtor = GetMethodIDOrDie(env, sFrequencyProfileClass, "<init>", "(FFF[F)V");
+    sFrequencyProfileCtor = GetMethodIDOrDie(env, sFrequencyProfileClass, "<init>", "(F[F[F)V");
 
     jclass vibratorInfoBuilderClass = FindClassOrDie(env, "android/os/VibratorInfo$Builder");
     sVibratorInfoBuilderClassInfo.setCapabilities =
@@ -598,6 +643,10 @@
     sVibratorInfoBuilderClassInfo.setQFactor =
             GetMethodIDOrDie(env, vibratorInfoBuilderClass, "setQFactor",
                              "(F)Landroid/os/VibratorInfo$Builder;");
+    sVibratorInfoBuilderClassInfo.setFrequencyProfileLegacy =
+            GetMethodIDOrDie(env, vibratorInfoBuilderClass, "setFrequencyProfileLegacy",
+                             "(Landroid/os/VibratorInfo$FrequencyProfileLegacy;)"
+                             "Landroid/os/VibratorInfo$Builder;");
     sVibratorInfoBuilderClassInfo.setFrequencyProfile =
             GetMethodIDOrDie(env, vibratorInfoBuilderClass, "setFrequencyProfile",
                              "(Landroid/os/VibratorInfo$FrequencyProfile;)"
diff --git a/services/core/xsd/display-device-config/display-device-config.xsd b/services/core/xsd/display-device-config/display-device-config.xsd
index 776de2e..20c69ac 100644
--- a/services/core/xsd/display-device-config/display-device-config.xsd
+++ b/services/core/xsd/display-device-config/display-device-config.xsd
@@ -464,7 +464,7 @@
             <xs:annotation name="nonnull"/>
             <xs:annotation name="final"/>
         </xs:element>
-        <xs:element name="customAnimationRateSec" type="nonNegativeDecimal" minOccurs="0" maxOccurs="1">
+        <xs:element name="customAnimationRate" type="nonNegativeDecimal" minOccurs="0" maxOccurs="1">
             <xs:annotation name="nonnull"/>
             <xs:annotation name="final"/>
         </xs:element>
diff --git a/services/core/xsd/display-device-config/schema/current.txt b/services/core/xsd/display-device-config/schema/current.txt
index 110a5a2..a8f18b3 100644
--- a/services/core/xsd/display-device-config/schema/current.txt
+++ b/services/core/xsd/display-device-config/schema/current.txt
@@ -345,12 +345,12 @@
   public class PowerThrottlingConfig {
     ctor public PowerThrottlingConfig();
     method @NonNull public final java.math.BigDecimal getBrightnessLowestCapAllowed();
-    method @NonNull public final java.math.BigDecimal getCustomAnimationRateSec();
+    method @NonNull public final java.math.BigDecimal getCustomAnimationRate();
     method @NonNull public final java.math.BigInteger getPollingWindowMaxMillis();
     method @NonNull public final java.math.BigInteger getPollingWindowMinMillis();
     method public final java.util.List<com.android.server.display.config.PowerThrottlingMap> getPowerThrottlingMap();
     method public final void setBrightnessLowestCapAllowed(@NonNull java.math.BigDecimal);
-    method public final void setCustomAnimationRateSec(@NonNull java.math.BigDecimal);
+    method public final void setCustomAnimationRate(@NonNull java.math.BigDecimal);
     method public final void setPollingWindowMaxMillis(@NonNull java.math.BigInteger);
     method public final void setPollingWindowMinMillis(@NonNull java.math.BigInteger);
   }
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 2be999f..7e450dd 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -11874,75 +11874,51 @@
             throw new IllegalArgumentException("Invalid package name: " + validationResult);
         }
 
-        if (Flags.setApplicationRestrictionsCoexistence()) {
-            EnforcingAdmin enforcingAdmin = enforcePermissionAndGetEnforcingAdmin(
-                    who,
-                    MANAGE_DEVICE_POLICY_APP_RESTRICTIONS,
-                    caller.getPackageName(),
-                    caller.getUserId()
-            );
-
+        final boolean isRoleHolder;
+        if (who != null) {
+            // DO or PO
+            Preconditions.checkCallAuthorization(
+                    (isProfileOwner(caller) || isDefaultDeviceOwner(caller)));
+            Preconditions.checkCallAuthorization(!parent,
+                    "DO or PO cannot call this on parent");
+            // Caller has opted to be treated as DPC (by passing a non-null who), so don't
+            // consider it as the DMRH, even if the caller is both the DPC and the DMRH.
+            isRoleHolder = false;
+        } else {
+            // Delegates, or the DMRH. Only DMRH can call this on COPE parent
+            isRoleHolder = isCallerDevicePolicyManagementRoleHolder(caller);
+            if (parent) {
+                Preconditions.checkCallAuthorization(isRoleHolder);
+                Preconditions.checkState(isOrganizationOwnedDeviceWithManagedProfile(),
+                        "Role Holder can only operate parent app restriction on COPE devices");
+            } else {
+                Preconditions.checkCallAuthorization(isRoleHolder
+                        || isCallerDelegate(caller, DELEGATION_APP_RESTRICTIONS));
+            }
+        }
+        // DMRH caller uses policy engine, others still use legacy code path
+        if (isRoleHolder) {
+            EnforcingAdmin enforcingAdmin = getEnforcingAdminForCaller(/* who */ null,
+                    caller.getPackageName());
+            int affectedUserId = parent
+                    ? getProfileParentId(caller.getUserId()) : caller.getUserId();
             if (restrictions == null || restrictions.isEmpty()) {
                 mDevicePolicyEngine.removeLocalPolicy(
                         PolicyDefinition.APPLICATION_RESTRICTIONS(packageName),
                         enforcingAdmin,
-                        caller.getUserId());
+                        affectedUserId);
             } else {
                 mDevicePolicyEngine.setLocalPolicy(
                         PolicyDefinition.APPLICATION_RESTRICTIONS(packageName),
                         enforcingAdmin,
                         new BundlePolicyValue(restrictions),
-                        caller.getUserId());
+                        affectedUserId);
             }
-            setBackwardsCompatibleAppRestrictions(
-                    caller, packageName, restrictions, caller.getUserHandle());
         } else {
-            final boolean isRoleHolder;
-            if (who != null) {
-                // DO or PO
-                Preconditions.checkCallAuthorization(
-                        (isProfileOwner(caller) || isDefaultDeviceOwner(caller)));
-                Preconditions.checkCallAuthorization(!parent,
-                        "DO or PO cannot call this on parent");
-                // Caller has opted to be treated as DPC (by passing a non-null who), so don't
-                // consider it as the DMRH, even if the caller is both the DPC and the DMRH.
-                isRoleHolder = false;
-            } else {
-                // Delegates, or the DMRH. Only DMRH can call this on COPE parent
-                isRoleHolder = isCallerDevicePolicyManagementRoleHolder(caller);
-                if (parent) {
-                    Preconditions.checkCallAuthorization(isRoleHolder);
-                    Preconditions.checkState(isOrganizationOwnedDeviceWithManagedProfile(),
-                            "Role Holder can only operate parent app restriction on COPE devices");
-                } else {
-                    Preconditions.checkCallAuthorization(isRoleHolder
-                            || isCallerDelegate(caller, DELEGATION_APP_RESTRICTIONS));
-                }
-            }
-            // DMRH caller uses policy engine, others still use legacy code path
-            if (isRoleHolder) {
-                EnforcingAdmin enforcingAdmin = getEnforcingAdminForCaller(/* who */ null,
-                        caller.getPackageName());
-                int affectedUserId = parent
-                        ? getProfileParentId(caller.getUserId()) : caller.getUserId();
-                if (restrictions == null || restrictions.isEmpty()) {
-                    mDevicePolicyEngine.removeLocalPolicy(
-                            PolicyDefinition.APPLICATION_RESTRICTIONS(packageName),
-                            enforcingAdmin,
-                            affectedUserId);
-                } else {
-                    mDevicePolicyEngine.setLocalPolicy(
-                            PolicyDefinition.APPLICATION_RESTRICTIONS(packageName),
-                            enforcingAdmin,
-                            new BundlePolicyValue(restrictions),
-                            affectedUserId);
-                }
-            } else {
-                mInjector.binderWithCleanCallingIdentity(() -> {
-                    mUserManager.setApplicationRestrictions(packageName, restrictions,
-                            caller.getUserHandle());
-                });
-            }
+            mInjector.binderWithCleanCallingIdentity(() -> {
+                mUserManager.setApplicationRestrictions(packageName, restrictions,
+                        caller.getUserHandle());
+            });
         }
 
         DevicePolicyEventLogger
@@ -11953,31 +11929,6 @@
                 .write();
     }
 
-    /**
-     * Set app restrictions in user manager for DPC callers only to keep backwards compatibility
-     * for the old getApplicationRestrictions API.
-     */
-    private void setBackwardsCompatibleAppRestrictions(
-            CallerIdentity caller, String packageName, Bundle restrictions, UserHandle userHandle) {
-        if ((caller.hasAdminComponent() && (isProfileOwner(caller) || isDefaultDeviceOwner(caller)))
-                || (caller.hasPackage() && isCallerDelegate(caller, DELEGATION_APP_RESTRICTIONS))) {
-            Bundle restrictionsToApply = restrictions == null || restrictions.isEmpty()
-                    ? getAppRestrictionsSetByAnyAdmin(packageName, userHandle)
-                    : restrictions;
-            mInjector.binderWithCleanCallingIdentity(() -> {
-                mUserManager.setApplicationRestrictions(packageName, restrictionsToApply,
-                        userHandle);
-            });
-        } else {
-            // Notify package of changes via an intent - only sent to explicitly registered
-            // receivers. Sending here because For DPCs, this is being sent in UMS.
-            final Intent changeIntent = new Intent(Intent.ACTION_APPLICATION_RESTRICTIONS_CHANGED);
-            changeIntent.setPackage(packageName);
-            changeIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
-            mContext.sendBroadcastAsUser(changeIntent, userHandle);
-        }
-    }
-
     private Bundle getAppRestrictionsSetByAnyAdmin(String packageName, UserHandle userHandle) {
         LinkedHashMap<EnforcingAdmin, PolicyValue<Bundle>> policies =
                 mDevicePolicyEngine.getLocalPoliciesSetByAdmins(
@@ -13257,68 +13208,47 @@
             String packageName, boolean parent) {
         final CallerIdentity caller = getCallerIdentity(who, callerPackage);
 
-        // IMPORTANT: The code behind the if branch is OUTDATED and requires additional work before
-        // enabling the feature flag below.
-        // TODO(b/369141952): Update DPM.getApplicationRestrictions coexistence code
-        if (Flags.setApplicationRestrictionsCoexistence()) {
-            EnforcingAdmin enforcingAdmin = enforceCanQueryAndGetEnforcingAdmin(
-                    who,
-                    MANAGE_DEVICE_POLICY_APP_RESTRICTIONS,
-                    caller.getPackageName(),
-                    caller.getUserId()
-            );
-
+        final boolean isRoleHolder;
+        if (who != null) {
+            // Caller is DO or PO. They cannot call this on parent
+            Preconditions.checkCallAuthorization(!parent
+                    && (isProfileOwner(caller) || isDefaultDeviceOwner(caller)));
+            // Caller has opted to be treated as DPC (by passing a non-null who), so don't
+            // consider it as the DMRH, even if the caller is both the DPC and the DMRH.
+            isRoleHolder = false;
+        } else {
+            // Caller is delegates or the DMRH. Only DMRH can call this on parent
+            isRoleHolder = isCallerDevicePolicyManagementRoleHolder(caller);
+            if (parent) {
+                Preconditions.checkCallAuthorization(isRoleHolder);
+                Preconditions.checkState(isOrganizationOwnedDeviceWithManagedProfile(),
+                        "Role Holder can only operate parent app restriction on COPE devices");
+            } else {
+                Preconditions.checkCallAuthorization(isRoleHolder
+                        || isCallerDelegate(caller, DELEGATION_APP_RESTRICTIONS));
+            }
+        }
+        if (isRoleHolder) {
+            EnforcingAdmin enforcingAdmin = getEnforcingAdminForCaller(/* who */ null,
+                    caller.getPackageName());
+            int affectedUserId = parent
+                    ? getProfileParentId(caller.getUserId()) : caller.getUserId();
             LinkedHashMap<EnforcingAdmin, PolicyValue<Bundle>> policies =
                     mDevicePolicyEngine.getLocalPoliciesSetByAdmins(
                             PolicyDefinition.APPLICATION_RESTRICTIONS(packageName),
-                            caller.getUserId());
-            if (policies.isEmpty() || !policies.containsKey(enforcingAdmin)) {
+                            affectedUserId);
+            if (!policies.containsKey(enforcingAdmin)) {
                 return Bundle.EMPTY;
             }
             return policies.get(enforcingAdmin).getValue();
         } else {
-            final boolean isRoleHolder;
-            if (who != null) {
-                // Caller is DO or PO. They cannot call this on parent
-                Preconditions.checkCallAuthorization(!parent
-                        && (isProfileOwner(caller) || isDefaultDeviceOwner(caller)));
-                // Caller has opted to be treated as DPC (by passing a non-null who), so don't
-                // consider it as the DMRH, even if the caller is both the DPC and the DMRH.
-                isRoleHolder = false;
-            } else {
-                // Caller is delegates or the DMRH. Only DMRH can call this on parent
-                isRoleHolder = isCallerDevicePolicyManagementRoleHolder(caller);
-                if (parent) {
-                    Preconditions.checkCallAuthorization(isRoleHolder);
-                    Preconditions.checkState(isOrganizationOwnedDeviceWithManagedProfile(),
-                            "Role Holder can only operate parent app restriction on COPE devices");
-                } else {
-                    Preconditions.checkCallAuthorization(isRoleHolder
-                            || isCallerDelegate(caller, DELEGATION_APP_RESTRICTIONS));
-                }
-            }
-            if (isRoleHolder) {
-                EnforcingAdmin enforcingAdmin = getEnforcingAdminForCaller(/* who */ null,
-                        caller.getPackageName());
-                int affectedUserId = parent
-                        ? getProfileParentId(caller.getUserId()) : caller.getUserId();
-                LinkedHashMap<EnforcingAdmin, PolicyValue<Bundle>> policies =
-                        mDevicePolicyEngine.getLocalPoliciesSetByAdmins(
-                                PolicyDefinition.APPLICATION_RESTRICTIONS(packageName),
-                                affectedUserId);
-                if (!policies.containsKey(enforcingAdmin)) {
-                    return Bundle.EMPTY;
-                }
-                return policies.get(enforcingAdmin).getValue();
-            } else {
-                return mInjector.binderWithCleanCallingIdentity(() -> {
-                    Bundle bundle = mUserManager.getApplicationRestrictions(packageName,
-                            caller.getUserHandle());
-                    // if no restrictions were saved, mUserManager.getApplicationRestrictions
-                    // returns null, but DPM method should return an empty Bundle as per JavaDoc
-                    return bundle != null ? bundle : Bundle.EMPTY;
-                });
-            }
+            return mInjector.binderWithCleanCallingIdentity(() -> {
+                Bundle bundle = mUserManager.getApplicationRestrictions(packageName,
+                        caller.getUserHandle());
+                // if no restrictions were saved, mUserManager.getApplicationRestrictions
+                // returns null, but DPM method should return an empty Bundle as per JavaDoc
+                return bundle != null ? bundle : Bundle.EMPTY;
+            });
         }
     }
 
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 7ea1dcd..b9727f9 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -159,7 +159,7 @@
 import com.android.server.contextualsearch.ContextualSearchManagerService;
 import com.android.server.coverage.CoverageService;
 import com.android.server.cpu.CpuMonitorService;
-import com.android.server.crashrecovery.CrashRecoveryModule;
+import com.android.server.crashrecovery.CrashRecoveryAdaptor;
 import com.android.server.credentials.CredentialManagerService;
 import com.android.server.criticalevents.CriticalEventLog;
 import com.android.server.devicepolicy.DevicePolicyManagerService;
@@ -1230,12 +1230,12 @@
 
         if (!Flags.refactorCrashrecovery()) {
             // Initialize RescueParty.
-            RescueParty.registerHealthObserver(mSystemContext);
+            CrashRecoveryAdaptor.rescuePartyRegisterHealthObserver(mSystemContext);
             if (!Flags.recoverabilityDetection()) {
                 // Now that we have the bare essentials of the OS up and running, take
                 // note that we just booted, which might send out a rescue party if
                 // we're stuck in a runtime restart loop.
-                PackageWatchdog.getInstance(mSystemContext).noteBoot();
+                CrashRecoveryAdaptor.packageWatchdogNoteBoot(mSystemContext);
             }
         }
 
@@ -1617,7 +1617,7 @@
             mSystemServiceManager.startService(ROLE_SERVICE_CLASS);
             t.traceEnd();
 
-            if (android.app.supervision.flags.Flags.supervisionApi()) {
+            if (!isWatch && android.app.supervision.flags.Flags.supervisionApi()) {
                 t.traceBegin("StartSupervisionService");
                 mSystemServiceManager.startService(SupervisionService.Lifecycle.class);
                 t.traceEnd();
@@ -2979,7 +2979,7 @@
 
         if (Flags.refactorCrashrecovery()) {
             t.traceBegin("StartCrashRecoveryModule");
-            mSystemServiceManager.startService(CrashRecoveryModule.Lifecycle.class);
+            CrashRecoveryAdaptor.initializeCrashrecoveryModuleService(mSystemServiceManager);
             t.traceEnd();
         } else {
             if (Flags.recoverabilityDetection()) {
@@ -2987,7 +2987,7 @@
                 // with package watchdog.
                 // Note that we just booted, which might send out a rescue party if we're stuck in a
                 // runtime restart loop.
-                PackageWatchdog.getInstance(mSystemContext).noteBoot();
+                CrashRecoveryAdaptor.packageWatchdogNoteBoot(mSystemContext);
             }
         }
 
diff --git a/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/InputMethodMenuControllerTest.java b/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/InputMethodMenuControllerTest.java
new file mode 100644
index 0000000..02dc86b
--- /dev/null
+++ b/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/InputMethodMenuControllerTest.java
@@ -0,0 +1,234 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.inputmethod;
+
+import static com.android.server.inputmethod.InputMethodMenuControllerNew.getMenuItems;
+import static com.android.server.inputmethod.InputMethodMenuControllerNew.getSelectedIndex;
+import static com.android.server.inputmethod.InputMethodSubtypeSwitchingControllerTest.addTestImeSubtypeListItems;
+import static com.android.server.inputmethod.InputMethodUtils.NOT_A_SUBTYPE_INDEX;
+
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import android.platform.test.annotations.RequiresFlagsEnabled;
+import android.platform.test.flag.junit.CheckFlagsRule;
+import android.platform.test.flag.junit.DeviceFlagsValueProvider;
+import android.view.inputmethod.Flags;
+
+import com.android.server.inputmethod.InputMethodMenuControllerNew.DividerItem;
+import com.android.server.inputmethod.InputMethodMenuControllerNew.HeaderItem;
+import com.android.server.inputmethod.InputMethodMenuControllerNew.SubtypeItem;
+import com.android.server.inputmethod.InputMethodSubtypeSwitchingController.ImeSubtypeListItem;
+
+import org.junit.Rule;
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@RequiresFlagsEnabled(Flags.FLAG_IME_SWITCHER_REVAMP)
+public class InputMethodMenuControllerTest {
+
+    @Rule
+    public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
+
+    /** Verifies that getMenuItems maintains the same order and information from the given items. */
+    @Test
+    public void testGetMenuItems() {
+        final var items = new ArrayList<ImeSubtypeListItem>();
+        addTestImeSubtypeListItems(items, "LatinIme", "LatinIme",
+                List.of("en", "fr"), true /* supportsSwitchingToNextInputMethod */);
+        addTestImeSubtypeListItems(items, "SimpleIme", "SimpleIme",
+                null, true /* supportsSwitchingToNextInputMethod */);
+
+        final var menuItems = getMenuItems(items);
+
+        int itemsIndex = 0;
+
+        for (int i = 0; i < menuItems.size(); i++) {
+            final var menuItem = menuItems.get(i);
+            if (menuItem instanceof SubtypeItem subtypeItem) {
+                final var item = items.get(itemsIndex);
+
+                assertWithMessage("IME name does not match").that(subtypeItem.mImeName)
+                        .isEqualTo(item.mImeName);
+                assertWithMessage("Subtype name does not match").that(subtypeItem.mSubtypeName)
+                        .isEqualTo(item.mSubtypeName);
+                assertWithMessage("InputMethodInfo does not match").that(subtypeItem.mImi)
+                        .isEqualTo(item.mImi);
+                assertWithMessage("Subtype index does not match").that(subtypeItem.mSubtypeIndex)
+                        .isEqualTo(item.mSubtypeIndex);
+
+                itemsIndex++;
+            }
+        }
+
+        assertWithMessage("Items list was not fully traversed").that(itemsIndex)
+                .isEqualTo(items.size());
+    }
+
+    /**
+     * Verifies that getMenuItems does not add a header or divider if all the items belong to
+     * a single input method.
+     */
+    @Test
+    public void testGetMenuItemsNoHeaderOrDividerForSingleInputMethod() {
+        final var items = new ArrayList<ImeSubtypeListItem>();
+        addTestImeSubtypeListItems(items, "LatinIme", "LatinIme",
+                List.of("en", "fr"), true /* supportsSwitchingToNextInputMethod */);
+
+        final var menuItems = getMenuItems(items);
+
+        assertThat(menuItems.stream()
+                .filter(item -> item instanceof HeaderItem || item instanceof DividerItem).toList())
+                .isEmpty();
+    }
+
+    /**
+     * Verifies that getMenuItems only adds headers for item groups with at least two items,
+     * or with a single item with a subtype name.
+     */
+    @Test
+    public void testGetMenuItemsHeaders() {
+        final var items = new ArrayList<ImeSubtypeListItem>();
+        addTestImeSubtypeListItems(items, "DefaultIme", "DefaultIme",
+                null, true /* supportsSwitchingToNextInputMethod */);
+        addTestImeSubtypeListItems(items, "LatinIme", "LatinIme",
+                List.of("en", "fr"), true /* supportsSwitchingToNextInputMethod */);
+        addTestImeSubtypeListItems(items, "ItalianIme", "ItalianIme",
+                List.of("it"), true /* supportsSwitchingToNextInputMethod */);
+        addTestImeSubtypeListItems(items, "SimpleIme", "SimpleIme",
+                null, true /* supportsSwitchingToNextInputMethod */);
+
+        final var menuItems = getMenuItems(items);
+
+        assertWithMessage("Must have menu items").that(menuItems).isNotEmpty();
+
+        final var headersAndDividers = menuItems.stream()
+                .filter(item -> item instanceof HeaderItem || item instanceof DividerItem)
+                .toList();
+
+        assertWithMessage("Must have header and divider items").that(headersAndDividers).hasSize(5);
+
+        assertWithMessage("First group has no header")
+                .that(menuItems.getFirst()).isInstanceOf(SubtypeItem.class);
+        assertWithMessage("Group with multiple items has divider")
+                .that(headersAndDividers.get(0)).isInstanceOf(DividerItem.class);
+        assertWithMessage("Group with multiple items has header")
+                .that(headersAndDividers.get(1)).isInstanceOf(HeaderItem.class);
+        assertWithMessage("Group with single item with subtype name has divider")
+                .that(headersAndDividers.get(2)).isInstanceOf(DividerItem.class);
+        assertWithMessage("Group with single item with subtype name has header")
+                .that(headersAndDividers.get(3)).isInstanceOf(HeaderItem.class);
+        assertWithMessage("Group with single item without subtype name has divider only")
+                .that(headersAndDividers.get(4)).isInstanceOf(DividerItem.class);
+    }
+
+    /** Verifies that getMenuItems adds a divider before every header except the first one. */
+    @Test
+    public void testGetMenuItemsDivider() {
+        final var items = new ArrayList<ImeSubtypeListItem>();
+        addTestImeSubtypeListItems(items, "LatinIme", "LatinIme",
+                List.of("en", "fr"), true /* supportsSwitchingToNextInputMethod */);
+        addTestImeSubtypeListItems(items, "ItalianIme", "ItalianIme",
+                List.of("it"), true /* supportsSwitchingToNextInputMethod */);
+        addTestImeSubtypeListItems(items, "SimpleIme", "SimpleIme",
+                null, true /* supportsSwitchingToNextInputMethod */);
+
+        final var menuItems = getMenuItems(items);
+
+        assertWithMessage("First item is a header")
+                .that(menuItems.getFirst()).isInstanceOf(HeaderItem.class);
+        assertWithMessage("Last item is a subtype")
+                .that(menuItems.getLast()).isInstanceOf(SubtypeItem.class);
+
+        for (int i = 0; i < menuItems.size(); i++) {
+            final var item = menuItems.get(i);
+            if (item instanceof HeaderItem && i > 0) {
+                final var prevItem = menuItems.get(i - 1);
+                assertWithMessage("The item before a header should be a divider")
+                        .that(prevItem).isInstanceOf(DividerItem.class);
+            } else if (item instanceof DividerItem && i < menuItems.size() - 1) {
+                final var nextItem = menuItems.get(i + 1);
+                assertWithMessage("The item after a divider should be a header or subtype")
+                        .that(nextItem instanceof HeaderItem || nextItem instanceof SubtypeItem)
+                        .isTrue();
+            }
+        }
+    }
+
+    /**
+     * Verifies that getSelectedIndex returns the matching item when the selected subtype is given.
+     */
+    @Test
+    public void testGetSelectedIndexWithSelectedSubtype() {
+        final var items = new ArrayList<ImeSubtypeListItem>();
+        addTestImeSubtypeListItems(items, "LatinIme", "LatinIme",
+                List.of("en", "fr"), true /* supportsSwitchingToNextInputMethod */);
+        addTestImeSubtypeListItems(items, "SimpleIme", "SimpleIme",
+                List.of("it", "jp", "pt"),  true /* supportsSwitchingToNextInputMethod */);
+
+        final var simpleImeId = items.get(2).mImi.getId();
+        final var menuItems = getMenuItems(items);
+
+        final int selectedIndex = getSelectedIndex(menuItems, simpleImeId, 1);
+        // Two headers + one divider + three items
+        assertThat(selectedIndex).isEqualTo(6);
+    }
+
+    /**
+     * Verifies that getSelectedIndex returns the first item of the selected input method,
+     * when no selected subtype is given.
+     */
+    @Test
+    public void testGetSelectedIndexWithoutSelectedSubtype() {
+        final var items = new ArrayList<ImeSubtypeListItem>();
+        addTestImeSubtypeListItems(items, "LatinIme", "LatinIme",
+                List.of("en", "fr"), true /* supportsSwitchingToNextInputMethod */);
+        addTestImeSubtypeListItems(items, "SimpleIme", "SimpleIme",
+                List.of("it", "jp", "pt"),  true /* supportsSwitchingToNextInputMethod */);
+
+        final var simpleImeId = items.get(2).mImi.getId();
+        final var menuItems = getMenuItems(items);
+
+        final int selectedIndex = getSelectedIndex(menuItems, simpleImeId, NOT_A_SUBTYPE_INDEX);
+
+        // Two headers + one divider + two items
+        assertThat(selectedIndex).isEqualTo(5);
+    }
+
+    /**
+     * Verifies that getSelectedIndex will return the item of the selected input method that has
+     * no subtype, when this is the first one reached, regardless of the given selected subtype.
+     */
+    @Test
+    public void getSelectedIndexNoSubtype() {
+        final var items = new ArrayList<ImeSubtypeListItem>();
+        addTestImeSubtypeListItems(items, "LatinIme", "LatinIme",
+                List.of("en", "fr"), true /* supportsSwitchingToNextInputMethod */);
+        addTestImeSubtypeListItems(items, "SimpleIme", "SimpleIme",
+                null,  true /* supportsSwitchingToNextInputMethod */);
+
+        final var simpleImeId = items.get(2).mImi.getId();
+        final var menuItems = getMenuItems(items);
+
+        final int selectedIndex = getSelectedIndex(menuItems, simpleImeId, 1);
+
+        // One header + one divider + two items
+        assertThat(selectedIndex).isEqualTo(4);
+    }
+}
diff --git a/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/InputMethodSubtypeSwitchingControllerTest.java b/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/InputMethodSubtypeSwitchingControllerTest.java
index 770451c..a804f24 100644
--- a/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/InputMethodSubtypeSwitchingControllerTest.java
+++ b/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/InputMethodSubtypeSwitchingControllerTest.java
@@ -75,7 +75,7 @@
                 .build();
     }
 
-    private static void addTestImeSubtypeListItems(@NonNull List<ImeSubtypeListItem> items,
+    static void addTestImeSubtypeListItems(@NonNull List<ImeSubtypeListItem> items,
             @NonNull String imeName, @NonNull String imeLabel,
             @Nullable List<String> subtypeLocales, boolean supportsSwitchingToNextInputMethod) {
         final ApplicationInfo ai = new ApplicationInfo();
diff --git a/services/tests/appfunctions/src/com/android/server/appfunctions/MetadataSyncAdapterTest.kt b/services/tests/appfunctions/src/com/android/server/appfunctions/MetadataSyncAdapterTest.kt
index bc64e15..96fb453 100644
--- a/services/tests/appfunctions/src/com/android/server/appfunctions/MetadataSyncAdapterTest.kt
+++ b/services/tests/appfunctions/src/com/android/server/appfunctions/MetadataSyncAdapterTest.kt
@@ -34,7 +34,6 @@
 import android.util.Log
 import androidx.test.platform.app.InstrumentationRegistry
 import com.android.internal.infra.AndroidFuture
-import com.android.server.appfunctions.FutureAppSearchSession.FutureSearchResults
 import com.google.common.truth.Truth.assertThat
 import java.util.concurrent.atomic.AtomicBoolean
 import org.junit.Test
@@ -392,6 +391,10 @@
                             return AndroidFuture.completedFuture(mutableListOf())
                         }
                     }
+
+                    override fun close() {
+                        Log.d("FakeRuntimeMetadataSearchSession", "Closing session")
+                    }
                 }
             return AndroidFuture.completedFuture(futureSearchResults)
         }
diff --git a/services/tests/displayservicetests/src/com/android/server/display/DisplayDeviceConfigTest.java b/services/tests/displayservicetests/src/com/android/server/display/DisplayDeviceConfigTest.java
index 3976ea4..2220f43 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/DisplayDeviceConfigTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayDeviceConfigTest.java
@@ -265,7 +265,7 @@
                 mDisplayDeviceConfig.getPowerThrottlingConfigData();
         assertNotNull(powerThrottlingConfigData);
         assertEquals(0.1f, powerThrottlingConfigData.brightnessLowestCapAllowed, SMALL_DELTA);
-        assertEquals(15f, powerThrottlingConfigData.customAnimationRateSec, SMALL_DELTA);
+        assertEquals(15f, powerThrottlingConfigData.customAnimationRate, SMALL_DELTA);
         assertEquals(20000, powerThrottlingConfigData.pollingWindowMaxMillis);
         assertEquals(10000, powerThrottlingConfigData.pollingWindowMinMillis);
     }
@@ -1299,7 +1299,7 @@
     private String getPowerThrottlingConfig() {
         return  "<powerThrottlingConfig >\n"
                 +       "<brightnessLowestCapAllowed>0.1</brightnessLowestCapAllowed>\n"
-                +       "<customAnimationRateSec>15</customAnimationRateSec>\n"
+                +       "<customAnimationRate>15</customAnimationRate>\n"
                 +       "<pollingWindowMaxMillis>20000</pollingWindowMaxMillis>\n"
                 +       "<pollingWindowMinMillis>10000</pollingWindowMinMillis>\n"
                 +       "<powerThrottlingMap>\n"
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 6093a67..3b5a386 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java
@@ -25,6 +25,7 @@
 import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY;
 import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP;
 import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_PRESENTATION;
+import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_TRUSTED;
 import static android.view.ContentRecordingSession.RECORD_CONTENT_DISPLAY;
 import static android.view.ContentRecordingSession.RECORD_CONTENT_TASK;
 import static android.view.Display.HdrCapabilities.HDR_TYPE_INVALID;
@@ -50,6 +51,7 @@
 import static org.mockito.ArgumentMatchers.anyLong;
 import static org.mockito.ArgumentMatchers.argThat;
 import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.isNull;
 import static org.mockito.ArgumentMatchers.nullable;
 import static org.mockito.Mockito.any;
 import static org.mockito.Mockito.atLeastOnce;
@@ -118,6 +120,7 @@
 import android.provider.Settings;
 import android.provider.Settings.SettingNotFoundException;
 import android.test.mock.MockContentResolver;
+import android.util.Slog;
 import android.util.SparseArray;
 import android.util.Spline;
 import android.view.ContentRecordingSession;
@@ -136,11 +139,14 @@
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.internal.R;
+import com.android.internal.app.IBatteryStats;
 import com.android.internal.util.test.FakeSettingsProvider;
 import com.android.internal.util.test.FakeSettingsProviderRule;
 import com.android.internal.util.test.LocalServiceKeeperRule;
 import com.android.modules.utils.testing.ExtendedMockitoRule;
+import com.android.server.LocalServices;
 import com.android.server.SystemService;
+import com.android.server.am.BatteryStatsService;
 import com.android.server.companion.virtual.VirtualDeviceManagerInternal;
 import com.android.server.display.DisplayManagerService.DeviceStateListener;
 import com.android.server.display.DisplayManagerService.SyncRoot;
@@ -151,6 +157,7 @@
 import com.android.server.display.notifications.DisplayNotificationManager;
 import com.android.server.input.InputManagerInternal;
 import com.android.server.lights.LightsManager;
+import com.android.server.policy.WindowManagerPolicy;
 import com.android.server.sensors.SensorManagerInternal;
 import com.android.server.wm.WindowManagerInternal;
 
@@ -374,6 +381,10 @@
     @Captor ArgumentCaptor<ContentRecordingSession> mContentRecordingSessionCaptor;
     @Mock DisplayManagerFlags mMockFlags;
 
+    @Mock WindowManagerPolicy mMockedWindowManagerPolicy;
+
+    @Mock IBatteryStats mMockedBatteryStats;
+
     @Rule
     public final ExtendedMockitoRule mExtendedMockitoRule =
             new ExtendedMockitoRule.Builder(this)
@@ -1067,9 +1078,9 @@
                 firstDisplayId);
     }
 
-    /** Tests that the virtual device is created in a device display group. */
+    /** Tests that a trusted virtual display is created in a device display group. */
     @Test
-    public void createVirtualDisplay_addsDisplaysToDeviceDisplayGroups() throws Exception {
+    public void createVirtualDisplay_addsTrustedDisplaysToDeviceDisplayGroups() throws Exception {
         DisplayManagerService displayManager = new DisplayManagerService(mContext, mBasicInjector);
         DisplayManagerInternal localService = displayManager.new LocalService();
 
@@ -1080,12 +1091,16 @@
         IVirtualDevice virtualDevice = mock(IVirtualDevice.class);
         when(virtualDevice.getDeviceId()).thenReturn(1);
         when(mIVirtualDeviceManager.isValidVirtualDeviceId(1)).thenReturn(true);
+
+        when(mContext.checkCallingPermission(ADD_TRUSTED_DISPLAY))
+                .thenReturn(PackageManager.PERMISSION_GRANTED);
+
         // Create a first virtual display. A display group should be created for this display on the
         // virtual device.
         final VirtualDisplayConfig.Builder builder1 =
                 new VirtualDisplayConfig.Builder(VIRTUAL_DISPLAY_NAME, 600, 800, 320)
-                        .setUniqueId("uniqueId --- device display group 1");
-
+                        .setUniqueId("uniqueId --- device display group")
+                        .setFlags(VIRTUAL_DISPLAY_FLAG_TRUSTED);
         int displayId1 =
                 localService.createVirtualDisplay(
                         builder1.build(),
@@ -1096,12 +1111,14 @@
         verify(mMockProjectionService, never()).setContentRecordingSession(any(),
                 nullable(IMediaProjection.class));
         int displayGroupId1 = localService.getDisplayInfo(displayId1).displayGroupId;
+        assertNotEquals(displayGroupId1, Display.DEFAULT_DISPLAY_GROUP);
 
         // Create a second virtual display. This should be added to the previously created display
         // group.
         final VirtualDisplayConfig.Builder builder2 =
                 new VirtualDisplayConfig.Builder(VIRTUAL_DISPLAY_NAME, 600, 800, 320)
-                        .setUniqueId("uniqueId --- device display group 1");
+                        .setUniqueId("uniqueId --- device display group")
+                        .setFlags(VIRTUAL_DISPLAY_FLAG_TRUSTED);
 
         int displayId2 =
                 localService.createVirtualDisplay(
@@ -1120,6 +1137,36 @@
                 displayGroupId2);
     }
 
+    /** Tests that an untrusted virtual display is created in the default display group. */
+    @Test
+    public void createVirtualDisplay_addsUntrustedDisplayToDefaultDisplayGroups() throws Exception {
+        DisplayManagerService displayManager = new DisplayManagerService(mContext, mBasicInjector);
+        DisplayManagerInternal localService = displayManager.new LocalService();
+
+        registerDefaultDisplays(displayManager);
+        when(mMockAppToken.asBinder()).thenReturn(mMockAppToken);
+
+        IVirtualDevice virtualDevice = mock(IVirtualDevice.class);
+        when(virtualDevice.getDeviceId()).thenReturn(1);
+        when(mIVirtualDeviceManager.isValidVirtualDeviceId(1)).thenReturn(true);
+        // Create the virtual display. It is untrusted, so it should go into the default group.
+        final VirtualDisplayConfig.Builder builder =
+                new VirtualDisplayConfig.Builder(VIRTUAL_DISPLAY_NAME, 600, 800, 320)
+                        .setUniqueId("uniqueId --- device display group");
+
+        int displayId =
+                localService.createVirtualDisplay(
+                        builder.build(),
+                        mMockAppToken /* callback */,
+                        virtualDevice /* virtualDeviceToken */,
+                        mock(DisplayWindowPolicyController.class),
+                        PACKAGE_NAME);
+        verify(mMockProjectionService, never()).setContentRecordingSession(any(),
+                nullable(IMediaProjection.class));
+        int displayGroupId = localService.getDisplayInfo(displayId).displayGroupId;
+        assertEquals(displayGroupId, Display.DEFAULT_DISPLAY_GROUP);
+    }
+
     /**
      * Tests that the virtual display is not added to the device display group when
      * VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP is set.
@@ -1137,11 +1184,15 @@
         when(virtualDevice.getDeviceId()).thenReturn(1);
         when(mIVirtualDeviceManager.isValidVirtualDeviceId(1)).thenReturn(true);
 
+        when(mContext.checkCallingPermission(ADD_TRUSTED_DISPLAY))
+                .thenReturn(PackageManager.PERMISSION_GRANTED);
+
         // Create a first virtual display. A display group should be created for this display on the
         // virtual device.
         final VirtualDisplayConfig.Builder builder1 =
                 new VirtualDisplayConfig.Builder(VIRTUAL_DISPLAY_NAME, 600, 800, 320)
-                        .setUniqueId("uniqueId --- device display group");
+                        .setUniqueId("uniqueId --- device display group")
+                        .setFlags(VIRTUAL_DISPLAY_FLAG_TRUSTED);
 
         int displayId1 =
                 localService.createVirtualDisplay(
@@ -1153,12 +1204,14 @@
         verify(mMockProjectionService, never()).setContentRecordingSession(any(),
                 nullable(IMediaProjection.class));
         int displayGroupId1 = localService.getDisplayInfo(displayId1).displayGroupId;
+        assertNotEquals(displayGroupId1, Display.DEFAULT_DISPLAY_GROUP);
 
         // Create a second virtual display. With the flag VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP,
         // the display should not be added to the previously created display group.
         final VirtualDisplayConfig.Builder builder2 =
                 new VirtualDisplayConfig.Builder(VIRTUAL_DISPLAY_NAME, 600, 800, 320)
-                        .setFlags(VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP)
+                        .setFlags(VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP
+                                | VIRTUAL_DISPLAY_FLAG_TRUSTED)
                         .setUniqueId("uniqueId --- own display group");
 
         when(mIVirtualDeviceManager.isValidVirtualDeviceId(1)).thenReturn(true);
@@ -1173,6 +1226,7 @@
         verify(mMockProjectionService, never()).setContentRecordingSession(any(),
                 nullable(IMediaProjection.class));
         int displayGroupId2 = localService.getDisplayInfo(displayId2).displayGroupId;
+        assertNotEquals(displayGroupId2, Display.DEFAULT_DISPLAY_GROUP);
 
         assertNotEquals(
                 "Display 1 should be in the device display group and display 2 in its own display"
@@ -1207,7 +1261,8 @@
         final VirtualDisplayConfig deviceDisplayGroupDisplayConfig =
                 new VirtualDisplayConfig.Builder(VIRTUAL_DISPLAY_NAME, 600, 800, 320)
                         .setUniqueId("uniqueId --- device display group 1")
-                        .setFlags(VIRTUAL_DISPLAY_FLAG_ALWAYS_UNLOCKED)
+                        .setFlags(VIRTUAL_DISPLAY_FLAG_ALWAYS_UNLOCKED
+                                | VIRTUAL_DISPLAY_FLAG_TRUSTED)
                         .build();
 
         int deviceDisplayGroupDisplayId =
@@ -1234,6 +1289,7 @@
                         .setUniqueId("uniqueId --- own display group 1")
                         .setFlags(
                                 VIRTUAL_DISPLAY_FLAG_ALWAYS_UNLOCKED
+                                        | VIRTUAL_DISPLAY_FLAG_TRUSTED
                                         | VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP)
                         .build();
 
@@ -1851,7 +1907,7 @@
 
     /**
      * Tests that specifying VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP is allowed when the permission
-     * ADD_TRUSTED_DISPLAY is granted.
+     * ADD_TRUSTED_DISPLAY is granted and that display is not in the default display group.
      */
     @Test
     public void testOwnDisplayGroup_allowCreationWithAddTrustedDisplayPermission()
@@ -1880,6 +1936,9 @@
         DisplayDeviceInfo ddi = displayManager.getDisplayDeviceInfoInternal(displayId);
         assertNotNull(ddi);
         assertNotEquals(0, ddi.flags & DisplayDeviceInfo.FLAG_OWN_DISPLAY_GROUP);
+
+        int displayGroupId = bs.getDisplayInfo(displayId).displayGroupId;
+        assertNotEquals(displayGroupId, Display.DEFAULT_DISPLAY_GROUP);
     }
 
     /**
@@ -1914,11 +1973,11 @@
     }
 
     /**
-     * Tests that specifying VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP is allowed when called with
-     * a virtual device, even if ADD_TRUSTED_DISPLAY is not granted.
+     * Tests that specifying VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP is not allowed when called with
+     * a virtual device, if ADD_TRUSTED_DISPLAY is not granted.
      */
     @Test
-    public void testOwnDisplayGroup_allowCreationWithVirtualDevice() throws Exception {
+    public void testOwnDisplayGroup_disallowCreationWithVirtualDevice() throws Exception {
         DisplayManagerService displayManager =
                 new DisplayManagerService(mContext, mBasicInjector);
         DisplayManagerInternal localService = displayManager.new LocalService();
@@ -1939,16 +1998,16 @@
         when(virtualDevice.getDeviceId()).thenReturn(1);
         when(mIVirtualDeviceManager.isValidVirtualDeviceId(1)).thenReturn(true);
 
-        int displayId = localService.createVirtualDisplay(builder.build(),
-                mMockAppToken /* callback */, virtualDevice /* virtualDeviceToken */,
-                mock(DisplayWindowPolicyController.class), PACKAGE_NAME);
-        verify(mMockProjectionService, never()).setContentRecordingSession(any(),
-                nullable(IMediaProjection.class));
-        performTraversalInternal(displayManager);
-        displayManager.getDisplayHandler().runWithScissors(() -> {}, 0 /* now */);
-        DisplayDeviceInfo ddi = displayManager.getDisplayDeviceInfoInternal(displayId);
-        assertNotNull(ddi);
-        assertNotEquals(0, ddi.flags & DisplayDeviceInfo.FLAG_OWN_DISPLAY_GROUP);
+        try {
+            localService.createVirtualDisplay(builder.build(),
+                    mMockAppToken /* callback */, virtualDevice /* virtualDeviceToken */,
+                    mock(DisplayWindowPolicyController.class), PACKAGE_NAME);
+            fail("Creating virtual display with VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP without "
+                    + "ADD_TRUSTED_DISPLAY permission should throw SecurityException even if "
+                    + "called with a virtual device.");
+        } catch (SecurityException e) {
+            // SecurityException is expected
+        }
     }
 
     /**
@@ -2710,6 +2769,78 @@
     }
 
     @Test
+    public void testConnectExternalDisplay_withDisplayManagement_allowsEnableAndDisableDisplay() {
+        when(mMockFlags.isConnectedDisplayManagementEnabled()).thenReturn(true);
+        when(mMockFlags.isApplyDisplayChangedDuringDisplayAddedEnabled()).thenReturn(true);
+        manageDisplaysPermission(/* granted= */ true);
+        LocalServices.addService(WindowManagerPolicy.class, mMockedWindowManagerPolicy);
+        BatteryStatsService.overrideService(mMockedBatteryStats);
+        DisplayManagerService displayManager = new DisplayManagerService(mContext, mBasicInjector);
+        DisplayManagerInternal localService = displayManager.new LocalService();
+        DisplayManagerService.BinderService bs = displayManager.new BinderService();
+        LogicalDisplayMapper logicalDisplayMapper = displayManager.getLogicalDisplayMapper();
+        FakeDisplayManagerCallback callback = new FakeDisplayManagerCallback();
+        bs.registerCallbackWithEventMask(callback, STANDARD_AND_CONNECTION_DISPLAY_EVENTS);
+        localService.registerDisplayGroupListener(callback);
+
+        // Create default display device
+        callback.expectsEvent(EVENT_DISPLAY_ADDED);
+        FakeDisplayDevice defaultDisplayDevice =
+                createFakeDisplayDevice(displayManager, new float[]{60f}, Display.TYPE_INTERNAL);
+        callback.waitForExpectedEvent();
+        LogicalDisplay defaultDisplay =
+                logicalDisplayMapper.getDisplayLocked(defaultDisplayDevice, false);
+        callback.clear();
+
+        // Create external display device
+        callback.expectsEvent(EVENT_DISPLAY_ADDED);
+        FakeDisplayDevice displayDevice =
+                createFakeDisplayDevice(displayManager, new float[]{60f}, new float[]{60f},
+                        Display.TYPE_EXTERNAL, callback);
+        callback.waitForExpectedEvent();
+        LogicalDisplay display =
+                logicalDisplayMapper.getDisplayLocked(displayDevice, /* includeDisabled= */ true);
+        assertThat(display.isEnabledLocked()).isTrue();
+        callback.clear();
+
+        callback.expectsEvent(FakeDisplayDevice.COMMITTED_DISPLAY_STATE_CHANGED);
+        initDisplayPowerController(localService);
+        // Initial power request, should have happened from PowerManagerService.
+        localService.requestPowerState(defaultDisplay.getDisplayInfoLocked().displayGroupId,
+                new DisplayManagerInternal.DisplayPowerRequest(),
+                /*waitForNegativeProximity=*/ false);
+        localService.requestPowerState(display.getDisplayInfoLocked().displayGroupId,
+                new DisplayManagerInternal.DisplayPowerRequest(),
+                /*waitForNegativeProximity=*/ false);
+        displayManager.onBootPhase(SystemService.PHASE_BOOT_COMPLETED);
+        callback.waitForExpectedEvent();
+
+        assertThat(displayDevice.getDisplayDeviceInfoLocked().committedState)
+                .isEqualTo(Display.STATE_OFF);
+        assertThat(display.isEnabledLocked()).isFalse();
+        assertThat(callback.receivedEvents()).containsExactly(EVENT_DISPLAY_CONNECTED,
+                EVENT_DISPLAY_REMOVED).inOrder();
+
+        int displayId = display.getDisplayIdLocked();
+        boolean enabled = display.isEnabledLocked();
+        assertThat(enabled).isFalse();
+
+        for (int i = 0; i < 9; i++) {
+            callback.expectsEvent(FakeDisplayDevice.COMMITTED_DISPLAY_STATE_CHANGED);
+            enabled = !enabled;
+            Slog.d("DisplayManagerServiceTest", "enabled=" + enabled);
+            displayManager.enableConnectedDisplay(displayId, enabled);
+            callback.waitForExpectedEvent();
+            assertThat(displayDevice.getDisplayDeviceInfoLocked().committedState)
+                    .isEqualTo(enabled ? Display.STATE_ON : Display.STATE_OFF);
+            assertThat(defaultDisplayDevice.getDisplayDeviceInfoLocked().committedState)
+                    .isEqualTo(Display.STATE_ON);
+        }
+        callback.expectsEvent(FakeDisplayDevice.COMMITTED_DISPLAY_STATE_CHANGED);
+        callback.waitForNonExpectedEvent();
+    }
+
+    @Test
     public void testConnectInternalDisplay_withDisplayManagement_shouldConnectAndAddDisplay() {
         when(mMockFlags.isConnectedDisplayManagementEnabled()).thenReturn(true);
         manageDisplaysPermission(/* granted= */ true);
@@ -2745,7 +2876,7 @@
         displayManager.setDisplayState(display.getDisplayIdLocked(), Display.STATE_ON);
 
         assertThat(displayDevice.getDisplayDeviceInfoLocked().committedState)
-                .isEqualTo(Display.STATE_ON);
+                .isEqualTo(Display.STATE_UNKNOWN);
 
         assertThat(displayManager.requestDisplayPower(display.getDisplayIdLocked(),
                 Display.STATE_OFF)).isTrue();
@@ -2778,7 +2909,7 @@
         var displayId = display.getDisplayIdLocked();
 
         assertThat(displayDevice.getDisplayDeviceInfoLocked().committedState)
-                .isEqualTo(Display.STATE_ON);
+                .isEqualTo(Display.STATE_UNKNOWN);
 
         assertThrows(SecurityException.class,
                 () -> bs.requestDisplayPower(displayId, Display.STATE_UNKNOWN));
@@ -3445,6 +3576,31 @@
         verify(dpc).onDisplayChanged(/* hbmMetadata= */ null, Layout.NO_LEAD_DISPLAY);
     }
 
+    @Test
+    public void testCreateAndReleaseVirtualDisplay_CalledWithTheSameUid() {
+        DisplayManagerService displayManager =
+                new DisplayManagerService(mContext, mShortMockedInjector);
+        registerDefaultDisplays(displayManager);
+        DisplayManagerService.BinderService bs = displayManager.new BinderService();
+        VirtualDisplayConfig config = mock(VirtualDisplayConfig.class);
+        Surface surface = mock(Surface.class);
+        when(config.getSurface()).thenReturn(surface);
+        int callingUid = Binder.getCallingUid();
+        IBinder binder = mock(IBinder.class);
+        when(mMockAppToken.asBinder()).thenReturn(binder);
+        String uniqueId = "123";
+        when(config.getUniqueId()).thenReturn(uniqueId);
+
+        bs.createVirtualDisplay(config, mMockAppToken, /* projection= */ null, PACKAGE_NAME);
+        verify(mMockVirtualDisplayAdapter).createVirtualDisplayLocked(eq(mMockAppToken),
+                /* projection= */ isNull(), eq(callingUid), eq(PACKAGE_NAME),
+                eq("virtual:" + PACKAGE_NAME + ":" + uniqueId), eq(surface), /* flags= */ anyInt(),
+                eq(config));
+
+        bs.releaseVirtualDisplay(mMockAppToken);
+        verify(mMockVirtualDisplayAdapter).releaseVirtualDisplayLocked(binder, callingUid);
+    }
+
     private void initDisplayPowerController(DisplayManagerInternal localService) {
         localService.initPowerManagement(new DisplayManagerInternal.DisplayPowerCallbacks() {
             @Override
@@ -3711,7 +3867,16 @@
                                                       float[] refreshRates,
                                                       float[] vsyncRates,
                                                       int displayType) {
+        return createFakeDisplayDevice(displayManager, refreshRates, vsyncRates, displayType, null);
+    }
+
+    private FakeDisplayDevice createFakeDisplayDevice(DisplayManagerService displayManager,
+                                                      float[] refreshRates,
+                                                      float[] vsyncRates,
+                                                      int displayType,
+                                                      FakeDisplayManagerCallback callback) {
         FakeDisplayDevice displayDevice = new FakeDisplayDevice();
+        displayDevice.setCallback(callback);
         DisplayDeviceInfo displayDeviceInfo = new DisplayDeviceInfo();
         int width = 100;
         int height = 200;
@@ -3721,6 +3886,7 @@
                     new Display.Mode(i + 1, width, height, refreshRates[i], vsyncRates[i],
                             new float[0], new int[0]);
         }
+        displayDeviceInfo.name = "" + displayType;
         displayDeviceInfo.modeId = 1;
         displayDeviceInfo.type = displayType;
         displayDeviceInfo.renderFrameRate = displayDeviceInfo.supportedModes[0].getRefreshRate();
@@ -3828,6 +3994,19 @@
             }
         }
 
+        void waitForNonExpectedEvent() {
+            waitForNonExpectedEvent(Duration.ofSeconds(1));
+        }
+
+        void waitForNonExpectedEvent(Duration timeout) {
+            try {
+                assertWithMessage("Non Expected '" + mExpectedEvent + "'")
+                        .that(mLatch.await(timeout.toMillis(), TimeUnit.MILLISECONDS)).isFalse();
+            } catch (InterruptedException ex) {
+                throw new AssertionError("Waiting for expected event interrupted", ex);
+            }
+        }
+
         private void eventSeen(String event) {
             if (event.equals(mExpectedEvent)) {
                 mLatch.countDown();
@@ -3898,8 +4077,10 @@
     }
 
     private class FakeDisplayDevice extends DisplayDevice {
+        static final String COMMITTED_DISPLAY_STATE_CHANGED = "requestDisplayStateLocked";
         private DisplayDeviceInfo mDisplayDeviceInfo;
         private Display.Mode mPreferredMode = new Display.Mode.Builder().build();
+        private FakeDisplayManagerCallback mCallback;
 
         FakeDisplayDevice() {
             super(mMockDisplayAdapter, /* displayToken= */ null, /* uniqueId= */ "", mContext);
@@ -3907,7 +4088,7 @@
 
         public void setDisplayDeviceInfo(DisplayDeviceInfo displayDeviceInfo) {
             mDisplayDeviceInfo = displayDeviceInfo;
-            mDisplayDeviceInfo.committedState = Display.STATE_ON;
+            mDisplayDeviceInfo.committedState = Display.STATE_UNKNOWN;
         }
 
         @Override
@@ -3944,7 +4125,23 @@
                 final float brightnessState,
                 final float sdrBrightnessState,
                 @Nullable DisplayOffloadSessionImpl displayOffloadSession) {
-            return () -> mDisplayDeviceInfo.committedState = state;
+            return () -> {
+                Slog.d("FakeDisplayDevice", mDisplayDeviceInfo.name
+                        + " new state=" + state);
+                if (state != mDisplayDeviceInfo.committedState) {
+                    Slog.d("FakeDisplayDevice", mDisplayDeviceInfo.name
+                            + " mDisplayDeviceInfo.committedState="
+                            + mDisplayDeviceInfo.committedState + " set to " + state);
+                    mDisplayDeviceInfo.committedState = state;
+                    if (mCallback != null) {
+                        mCallback.eventSeen(COMMITTED_DISPLAY_STATE_CHANGED);
+                    }
+                }
+            };
+        }
+
+        void setCallback(FakeDisplayManagerCallback callback) {
+            this.mCallback = callback;
         }
     }
 }
diff --git a/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java b/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java
index c70bf8a..01b2d3e 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java
@@ -35,6 +35,7 @@
 import static org.mockito.ArgumentMatchers.isA;
 import static org.mockito.Mockito.atLeastOnce;
 import static org.mockito.Mockito.clearInvocations;
+import static org.mockito.Mockito.description;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.reset;
@@ -2278,29 +2279,44 @@
             throws Exception {
         when(mDisplayManagerFlagsMock.isBatteryStatsEnabledForAllDisplays()).thenReturn(false);
 
-        verifyNoteScreenState(Display.DEFAULT_DISPLAY, /* expectNote= */ true);
+        verifyNoteScreenState(
+                Display.DEFAULT_DISPLAY, Display.TYPE_INTERNAL, /* expectNote= */ true);
     }
 
     @Test
     public void testBatteryStatNotes_enabledOnDefaultDisplayWhenEnabledOnOthers() throws Exception {
         when(mDisplayManagerFlagsMock.isBatteryStatsEnabledForAllDisplays()).thenReturn(true);
 
-        verifyNoteScreenState(Display.DEFAULT_DISPLAY, /* expectNote= */ true);
+        verifyNoteScreenState(
+                Display.DEFAULT_DISPLAY, Display.TYPE_INTERNAL, /* expectNote= */ true);
     }
 
     @Test
-    public void testBatteryStatNotes_flagGuardedOnNonDefaultDisplays() throws Exception {
+    public void testBatteryStatNotes_flagOff_disabledForNonDefaultDisplays() throws Exception {
         when(mDisplayManagerFlagsMock.isBatteryStatsEnabledForAllDisplays()).thenReturn(false);
 
-        verifyNoteScreenState(/* displayId= */ 2, /* expectNote= */ false);
-
-        when(mDisplayManagerFlagsMock.isBatteryStatsEnabledForAllDisplays()).thenReturn(true);
-
-        verifyNoteScreenState(/* displayId= */ 2, /* expectNote= */ true);
+        verifyNoteScreenState(/* displayId= */ 2, Display.TYPE_INTERNAL, /* expectNote= */ false);
     }
 
-    private void verifyNoteScreenState(int displayId, boolean expectNote) throws Exception {
-        mHolder = createDisplayPowerController(displayId, UNIQUE_ID);
+    @Test
+    public void testBatteryStatNotes_enabledOnlyOnInternalOrExternalDisplays() throws Exception {
+        when(mDisplayManagerFlagsMock.isBatteryStatsEnabledForAllDisplays()).thenReturn(true);
+
+        for (int displayType = 0; displayType < Display.TYPE_MAX; displayType++) {
+            boolean expectNote =
+                    (displayType == Display.TYPE_INTERNAL)
+                            || (displayType == Display.TYPE_EXTERNAL);
+            verifyNoteScreenState(/* displayId= */ 2, displayType, expectNote);
+        }
+    }
+
+    private void verifyNoteScreenState(int displayId, int displayDeviceType, boolean expectNote)
+            throws Exception {
+        clearInvocations(mMockBatteryStats);
+        DisplayDeviceInfo deviceInfo = new DisplayDeviceInfo();
+        deviceInfo.type = displayDeviceType;
+        deviceInfo.uniqueId = UNIQUE_ID;
+        mHolder = createDisplayPowerController(displayId, deviceInfo);
         DisplayPowerRequest dpr = new DisplayPowerRequest();
         dpr.policy = DisplayPowerRequest.POLICY_BRIGHT;
         when(mHolder.displayPowerState.getScreenState()).thenReturn(Display.STATE_ON);
@@ -2308,14 +2324,22 @@
         mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false);
         advanceTime(1); // Run updatePowerState
 
+        final String baseErrorMessage =
+                String.format("[display id=%d type=%d]", displayId, displayDeviceType);
+        final String errorMessage;
         if (expectNote) {
-            verify(mMockBatteryStats)
+            errorMessage = "Expected battery stats: " + baseErrorMessage;
+            verify(mMockBatteryStats, description(errorMessage))
                     .noteScreenState(
                             displayId, Display.STATE_ON, Display.STATE_REASON_DEFAULT_POLICY);
-            verify(mMockBatteryStats).noteScreenBrightness(eq(displayId), anyInt());
+            verify(mMockBatteryStats, description(errorMessage))
+                    .noteScreenBrightness(eq(displayId), anyInt());
         } else {
-            verify(mMockBatteryStats, never()).noteScreenState(anyInt(), anyInt(), anyInt());
-            verify(mMockBatteryStats, never()).noteScreenBrightness(anyInt(), anyInt());
+            errorMessage = "Expected no battery stats: " + baseErrorMessage;
+            verify(mMockBatteryStats, never().description(errorMessage))
+                    .noteScreenState(anyInt(), anyInt(), anyInt());
+            verify(mMockBatteryStats, never().description(errorMessage))
+                    .noteScreenBrightness(anyInt(), anyInt());
         }
     }
 
@@ -2350,17 +2374,16 @@
     private void setUpDisplay(int displayId, String uniqueId, LogicalDisplay logicalDisplayMock,
             DisplayDevice displayDeviceMock, DisplayDeviceConfig displayDeviceConfigMock,
             boolean isEnabled) {
-
-        setUpDisplay(displayId, uniqueId, logicalDisplayMock, displayDeviceMock,
+        DisplayDeviceInfo deviceInfo = new DisplayDeviceInfo();
+        deviceInfo.uniqueId = uniqueId;
+        setUpDisplay(displayId, deviceInfo, logicalDisplayMock, displayDeviceMock,
                 displayDeviceConfigMock, isEnabled, "display_name");
     }
 
-    private void setUpDisplay(int displayId, String uniqueId, LogicalDisplay logicalDisplayMock,
-            DisplayDevice displayDeviceMock, DisplayDeviceConfig displayDeviceConfigMock,
-            boolean isEnabled, String displayName) {
+    private void setUpDisplay(int displayId, DisplayDeviceInfo deviceInfo,
+            LogicalDisplay logicalDisplayMock, DisplayDevice displayDeviceMock,
+            DisplayDeviceConfig displayDeviceConfigMock, boolean isEnabled, String displayName) {
         DisplayInfo info = new DisplayInfo();
-        DisplayDeviceInfo deviceInfo = new DisplayDeviceInfo();
-        deviceInfo.uniqueId = uniqueId;
 
         when(logicalDisplayMock.getDisplayIdLocked()).thenReturn(displayId);
         when(logicalDisplayMock.getPrimaryDisplayDeviceLocked()).thenReturn(displayDeviceMock);
@@ -2368,7 +2391,7 @@
         when(logicalDisplayMock.isEnabledLocked()).thenReturn(isEnabled);
         when(logicalDisplayMock.isInTransitionLocked()).thenReturn(false);
         when(displayDeviceMock.getDisplayDeviceInfoLocked()).thenReturn(deviceInfo);
-        when(displayDeviceMock.getUniqueId()).thenReturn(uniqueId);
+        when(displayDeviceMock.getUniqueId()).thenReturn(deviceInfo.uniqueId);
         when(displayDeviceMock.getNameLocked()).thenReturn(displayName);
         when(displayDeviceMock.getDisplayDeviceConfig()).thenReturn(displayDeviceConfigMock);
         when(displayDeviceConfigMock.getProximitySensor()).thenReturn(
@@ -2415,6 +2438,12 @@
                 hysteresisLevels);
     }
 
+    private DisplayPowerControllerHolder createDisplayPowerController(
+            int displayId, DisplayDeviceInfo info) {
+        return createDisplayPowerController(
+                displayId, info, /* isEnabled= */ true, /* isAutoBrightnessAvailable= */ true);
+    }
+
     private DisplayPowerControllerHolder createDisplayPowerController(int displayId,
             String uniqueId) {
         return createDisplayPowerController(displayId, uniqueId, /* isEnabled= */ true);
@@ -2428,6 +2457,14 @@
 
     private DisplayPowerControllerHolder createDisplayPowerController(int displayId,
             String uniqueId, boolean isEnabled, boolean isAutoBrightnessAvailable) {
+        DisplayDeviceInfo deviceInfo = new DisplayDeviceInfo();
+        deviceInfo.uniqueId = uniqueId;
+        return createDisplayPowerController(
+                displayId, deviceInfo, isEnabled, isAutoBrightnessAvailable);
+    }
+
+    private DisplayPowerControllerHolder createDisplayPowerController(int displayId,
+            DisplayDeviceInfo deviceInfo, boolean isEnabled, boolean isAutoBrightnessAvailable) {
         final DisplayPowerState displayPowerState = mock(DisplayPowerState.class);
         final DualRampAnimator<DisplayPowerState> animator = mock(DualRampAnimator.class);
         final AutomaticBrightnessController automaticBrightnessController =
@@ -2469,7 +2506,7 @@
         when(config.getScreenBrightnessHysteresis()).thenReturn(hysteresisLevels);
         when(config.getScreenBrightnessIdleHysteresis()).thenReturn(hysteresisLevels);
 
-        setUpDisplay(displayId, uniqueId, display, device, config, isEnabled);
+        setUpDisplay(displayId, deviceInfo, display, device, config, isEnabled, "display_name");
         when(config.isAutoBrightnessAvailable()).thenReturn(isAutoBrightnessAvailable);
 
         final DisplayPowerController dpc = new DisplayPowerController(
diff --git a/services/tests/displayservicetests/src/com/android/server/display/DisplayTopologyTest.kt b/services/tests/displayservicetests/src/com/android/server/display/DisplayTopologyTest.kt
index 1fad14b..f3a8d841 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/DisplayTopologyTest.kt
+++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayTopologyTest.kt
@@ -16,6 +16,7 @@
 
 package com.android.server.display
 
+import android.view.Display
 import com.google.common.truth.Truth.assertThat
 import org.junit.Test
 
@@ -23,7 +24,7 @@
     private val topology = DisplayTopology()
 
     @Test
-    fun oneDisplay() {
+    fun addOneDisplay() {
         val displayId = 1
         val width = 800.0
         val height = 600.0
@@ -40,7 +41,7 @@
     }
 
     @Test
-    fun twoDisplays() {
+    fun addTwoDisplays() {
         val displayId1 = 1
         val width1 = 800.0
         val height1 = 600.0
@@ -71,7 +72,7 @@
     }
 
     @Test
-    fun manyDisplays() {
+    fun addManyDisplays() {
         val displayId1 = 1
         val width1 = 800.0
         val height1 = 600.0
@@ -118,4 +119,130 @@
             assertThat(display.mOffset).isEqualTo(0)
         }
     }
+
+    @Test
+    fun removeDisplays() {
+        val displayId1 = 1
+        val width1 = 800.0
+        val height1 = 600.0
+
+        val displayId2 = 2
+        val width2 = 1000.0
+        val height2 = 1500.0
+
+        topology.addDisplay(displayId1, width1, height1)
+        topology.addDisplay(displayId2, width2, height2)
+
+        val noOfDisplays = 30
+        for (i in 3..noOfDisplays) {
+            topology.addDisplay(/* displayId= */ i, width1, height1)
+        }
+
+        var removedDisplays = arrayOf(20)
+        topology.removeDisplay(20)
+
+        assertThat(topology.mPrimaryDisplayId).isEqualTo(displayId1)
+
+        var display1 = topology.mRoot!!
+        assertThat(display1.mDisplayId).isEqualTo(displayId1)
+        assertThat(display1.mWidth).isEqualTo(width1)
+        assertThat(display1.mHeight).isEqualTo(height1)
+        assertThat(display1.mChildren).hasSize(1)
+
+        var display2 = display1.mChildren[0]
+        assertThat(display2.mDisplayId).isEqualTo(displayId2)
+        assertThat(display2.mWidth).isEqualTo(width2)
+        assertThat(display2.mHeight).isEqualTo(height2)
+        assertThat(display2.mChildren).hasSize(1)
+        assertThat(display2.mPosition).isEqualTo(
+            DisplayTopology.TreeNode.Position.POSITION_TOP)
+        assertThat(display2.mOffset).isEqualTo(width1 / 2 - width2 / 2)
+
+        var display = display2
+        for (i in 3..noOfDisplays) {
+            if (i in removedDisplays) {
+                continue
+            }
+            display = display.mChildren[0]
+            assertThat(display.mDisplayId).isEqualTo(i)
+            assertThat(display.mWidth).isEqualTo(width1)
+            assertThat(display.mHeight).isEqualTo(height1)
+            // The last display should have no children
+            assertThat(display.mChildren).hasSize(if (i < noOfDisplays) 1 else 0)
+            assertThat(display.mPosition).isEqualTo(
+                DisplayTopology.TreeNode.Position.POSITION_RIGHT)
+            assertThat(display.mOffset).isEqualTo(0)
+        }
+
+        topology.removeDisplay(22)
+        removedDisplays += 22
+        topology.removeDisplay(23)
+        removedDisplays += 23
+        topology.removeDisplay(25)
+        removedDisplays += 25
+
+        assertThat(topology.mPrimaryDisplayId).isEqualTo(displayId1)
+
+        display1 = topology.mRoot!!
+        assertThat(display1.mDisplayId).isEqualTo(displayId1)
+        assertThat(display1.mWidth).isEqualTo(width1)
+        assertThat(display1.mHeight).isEqualTo(height1)
+        assertThat(display1.mChildren).hasSize(1)
+
+        display2 = display1.mChildren[0]
+        assertThat(display2.mDisplayId).isEqualTo(displayId2)
+        assertThat(display2.mWidth).isEqualTo(width2)
+        assertThat(display2.mHeight).isEqualTo(height2)
+        assertThat(display2.mChildren).hasSize(1)
+        assertThat(display2.mPosition).isEqualTo(
+            DisplayTopology.TreeNode.Position.POSITION_TOP)
+        assertThat(display2.mOffset).isEqualTo(width1 / 2 - width2 / 2)
+
+        display = display2
+        for (i in 3..noOfDisplays) {
+            if (i in removedDisplays) {
+                continue
+            }
+            display = display.mChildren[0]
+            assertThat(display.mDisplayId).isEqualTo(i)
+            assertThat(display.mWidth).isEqualTo(width1)
+            assertThat(display.mHeight).isEqualTo(height1)
+            // The last display should have no children
+            assertThat(display.mChildren).hasSize(if (i < noOfDisplays) 1 else 0)
+            assertThat(display.mPosition).isEqualTo(
+                DisplayTopology.TreeNode.Position.POSITION_RIGHT)
+            assertThat(display.mOffset).isEqualTo(0)
+        }
+    }
+
+    @Test
+    fun removeAllDisplays() {
+        val displayId = 1
+        val width = 800.0
+        val height = 600.0
+
+        topology.addDisplay(displayId, width, height)
+        topology.removeDisplay(displayId)
+
+        assertThat(topology.mPrimaryDisplayId).isEqualTo(Display.INVALID_DISPLAY)
+        assertThat(topology.mRoot).isNull()
+    }
+
+    @Test
+    fun removeDisplayThatDoesNotExist() {
+        val displayId = 1
+        val width = 800.0
+        val height = 600.0
+
+        topology.addDisplay(displayId, width, height)
+        topology.removeDisplay(3)
+
+        assertThat(topology.mPrimaryDisplayId).isEqualTo(displayId)
+
+        val display = topology.mRoot!!
+        assertThat(display.mDisplayId).isEqualTo(displayId)
+        assertThat(display.mWidth).isEqualTo(width)
+        assertThat(display.mHeight).isEqualTo(height)
+        assertThat(display.mChildren).isEmpty()
+    }
 }
\ No newline at end of file
diff --git a/services/tests/displayservicetests/src/com/android/server/display/ExternalDisplayPolicyTest.java b/services/tests/displayservicetests/src/com/android/server/display/ExternalDisplayPolicyTest.java
index f728168..782262d 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/ExternalDisplayPolicyTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/ExternalDisplayPolicyTest.java
@@ -18,6 +18,7 @@
 
 import static android.hardware.display.DisplayManagerGlobal.EVENT_DISPLAY_CONNECTED;
 import static android.view.Display.TYPE_EXTERNAL;
+import static android.view.Display.TYPE_INTERNAL;
 
 import static com.google.common.truth.Truth.assertThat;
 
@@ -36,6 +37,7 @@
 import android.os.IThermalService;
 import android.os.RemoteException;
 import android.os.Temperature;
+import android.view.Display;
 import android.view.DisplayInfo;
 
 import androidx.test.filters.SmallTest;
@@ -97,6 +99,8 @@
     @Mock
     private LogicalDisplay mMockedLogicalDisplay;
     @Mock
+    private LogicalDisplay mMockedDefaultDisplay;
+    @Mock
     private DisplayNotificationManager mMockedDisplayNotificationManager;
     @Mock
     private ExternalDisplayStatsService mMockedExternalDisplayStatsService;
@@ -141,6 +145,15 @@
         when(mMockedLogicalDisplay.getDisplayInfoLocked()).thenReturn(mockedLogicalDisplayInfo);
         when(mMockedLogicalDisplayMapper.getDisplayLocked(EXTERNAL_DISPLAY_ID)).thenReturn(
                 mMockedLogicalDisplay);
+
+        // Initialize default logical display
+        when(mMockedDefaultDisplay.getDisplayIdLocked()).thenReturn(Display.DEFAULT_DISPLAY);
+        when(mMockedDefaultDisplay.isEnabledLocked()).thenReturn(true);
+        final var mockedDefaultDisplayInfo = new DisplayInfo();
+        mockedDefaultDisplayInfo.type = TYPE_INTERNAL;
+        when(mMockedDefaultDisplay.getDisplayInfoLocked()).thenReturn(mockedDefaultDisplayInfo);
+        when(mMockedLogicalDisplayMapper.getDisplayLocked(Display.DEFAULT_DISPLAY)).thenReturn(
+                mMockedDefaultDisplay);
     }
 
     @Test
@@ -293,6 +306,52 @@
         verify(mMockedLogicalDisplayMapper, never()).forEachLocked(any());
     }
 
+    @Test
+    public void testMirroringAlwaysConfirmedByUser_flagDisabled() {
+        when(mMockedFlags.isWaitingConfirmationBeforeMirroringEnabled()).thenReturn(false);
+        assertThat(mExternalDisplayPolicy.isDisplayReadyForMirroring(EXTERNAL_DISPLAY_ID)).isTrue();
+    }
+
+    @Test
+    public void testMirroringConfirmed_afterBootForEnabledDisplay() {
+        when(mMockedFlags.isWaitingConfirmationBeforeMirroringEnabled()).thenReturn(true);
+        mExternalDisplayPolicy.onBootCompleted();
+        assertThat(mExternalDisplayPolicy.isDisplayReadyForMirroring(EXTERNAL_DISPLAY_ID))
+                .isTrue();
+    }
+
+    @Test
+    public void testMirroringNotConfirmed_afterBootForDisabledDisplay() {
+        when(mMockedFlags.isWaitingConfirmationBeforeMirroringEnabled()).thenReturn(true);
+        mExternalDisplayPolicy.onBootCompleted();
+        when(mMockedLogicalDisplay.isEnabledLocked()).thenReturn(false);
+        assertThat(mExternalDisplayPolicy.isDisplayReadyForMirroring(EXTERNAL_DISPLAY_ID))
+                .isFalse();
+    }
+
+    @Test
+    public void testMirroringNeverConfirmed_forNonExternalDisplays() {
+        when(mMockedFlags.isWaitingConfirmationBeforeMirroringEnabled()).thenReturn(true);
+        mExternalDisplayPolicy.onBootCompleted();
+        assertThat(mExternalDisplayPolicy.isDisplayReadyForMirroring(Display.DEFAULT_DISPLAY))
+                .isFalse();
+    }
+
+    @Test
+    public void testMirroringNeverConfirmed_forNonExistingDisplays() {
+        when(mMockedFlags.isWaitingConfirmationBeforeMirroringEnabled()).thenReturn(true);
+        mExternalDisplayPolicy.onBootCompleted();
+        assertThat(mExternalDisplayPolicy.isDisplayReadyForMirroring(Display.INVALID_DISPLAY))
+                .isFalse();
+    }
+
+    @Test
+    public void testMirroringNeverConfirmed_duringBoot() {
+        when(mMockedFlags.isWaitingConfirmationBeforeMirroringEnabled()).thenReturn(true);
+        assertThat(mExternalDisplayPolicy.isDisplayReadyForMirroring(EXTERNAL_DISPLAY_ID))
+                .isFalse();
+    }
+
     private void setTemperature(final IThermalEventListener thermalEventListener,
             final List<Temperature> temperature) throws RemoteException {
         for (var t : temperature) {
diff --git a/services/tests/displayservicetests/src/com/android/server/display/LogicalDisplayMapperTest.java b/services/tests/displayservicetests/src/com/android/server/display/LogicalDisplayMapperTest.java
index 1729ad5..d831cf8 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/LogicalDisplayMapperTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/LogicalDisplayMapperTest.java
@@ -121,6 +121,8 @@
             Set.of(DeviceState.PROPERTY_POWER_CONFIGURATION_TRIGGER_WAKE), Collections.emptySet());
     private static final DeviceState DEVICE_STATE_OPEN = createDeviceState(2, "Two",
             Set.of(DeviceState.PROPERTY_POWER_CONFIGURATION_TRIGGER_WAKE), Collections.emptySet());
+    private static final DeviceState DEVICE_STATE_EMULATED = createDeviceState(3, "Three",
+            Set.of(DeviceState.PROPERTY_EMULATED_ONLY), Collections.emptySet());
     private static final int FLAG_GO_TO_SLEEP_ON_FOLD = 0;
     private static final int FLAG_GO_TO_SLEEP_FLAG_SOFT_SLEEP = 2;
     private static int sNextNonDefaultDisplayId = DEFAULT_DISPLAY + 1;
@@ -686,6 +688,14 @@
     }
 
     @Test
+    public void testDeviceShouldNotBeWokenWhenExitingEmulatedState() {
+        assertFalse(mLogicalDisplayMapper.shouldDeviceBeWoken(DEVICE_STATE_OPEN,
+                DEVICE_STATE_EMULATED,
+                /* isInteractive= */false,
+                /* isBootCompleted= */true));
+    }
+
+    @Test
     public void testDeviceShouldBePutToSleep() {
         assertTrue(mLogicalDisplayMapper.shouldDeviceBePutToSleep(DEVICE_STATE_CLOSED,
                 DEVICE_STATE_OPEN,
diff --git a/services/tests/displayservicetests/src/com/android/server/display/PersistentDataStoreTest.java b/services/tests/displayservicetests/src/com/android/server/display/PersistentDataStoreTest.java
index 5676a38..6d14065 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/PersistentDataStoreTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/PersistentDataStoreTest.java
@@ -459,7 +459,6 @@
         ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
         newInjector.setReadStream(bais);
         newDataStore.loadIfNeeded();
-        assertNotNull(newDataStore.getUserPreferredRefreshRate(testDisplayDevice));
         assertEquals(85.3f, mDataStore.getUserPreferredRefreshRate(testDisplayDevice), 01.f);
         assertEquals(85.3f, newDataStore.getUserPreferredRefreshRate(testDisplayDevice), 0.1f);
     }
diff --git a/services/tests/displayservicetests/src/com/android/server/display/VirtualDisplayAdapterTest.java b/services/tests/displayservicetests/src/com/android/server/display/VirtualDisplayAdapterTest.java
index 81e6cc3..3ac7fb0 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/VirtualDisplayAdapterTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/VirtualDisplayAdapterTest.java
@@ -21,71 +21,104 @@
 import static org.junit.Assert.assertTrue;
 import static org.mockito.Mockito.when;
 
-import android.content.Context;
 import android.hardware.display.IVirtualDisplayCallback;
 import android.hardware.display.VirtualDisplayConfig;
+import android.media.projection.IMediaProjection;
 import android.os.IBinder;
 import android.os.Process;
+import android.platform.test.flag.junit.CheckFlagsRule;
+import android.platform.test.flag.junit.DeviceFlagsValueProvider;
+import android.testing.TestableContext;
+import android.view.Surface;
 
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
+import androidx.test.platform.app.InstrumentationRegistry;
 
+import com.android.internal.R;
 import com.android.server.display.feature.DisplayManagerFlags;
 import com.android.server.testutils.TestHandler;
 
 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;
 
+import java.util.ArrayList;
+import java.util.List;
+
 @SmallTest
 @RunWith(AndroidJUnit4.class)
 public class VirtualDisplayAdapterTest {
 
-    @Mock
-    Context mContextMock;
+    private static final int MAX_DEVICES = 3;
+    private static final int MAX_DEVICES_PER_PACKAGE = 2;
+
+    @Rule
+    public final TestableContext mContext = new TestableContext(
+            InstrumentationRegistry.getInstrumentation().getContext());
 
     @Mock
-    VirtualDisplayAdapter.SurfaceControlDisplayFactory mMockSufaceControlDisplayFactory;
+    private VirtualDisplayAdapter.SurfaceControlDisplayFactory mMockSufaceControlDisplayFactory;
 
     @Mock
-    DisplayAdapter.Listener mMockListener;
+    private DisplayAdapter.Listener mMockListener;
 
     @Mock
-    IVirtualDisplayCallback mMockCallback;
+    private IVirtualDisplayCallback mMockCallback;
 
     @Mock
-    IBinder mMockBinder;
+    private IBinder mMockBinder;
+
+    @Mock
+    private IMediaProjection mMediaProjectionMock;
+
+    @Mock
+    private Surface mSurfaceMock;
+
+    @Mock
+    private VirtualDisplayConfig mVirtualDisplayConfigMock;
 
     private TestHandler mHandler;
 
-    private VirtualDisplayAdapter mVirtualDisplayAdapter;
-
     @Mock
     private DisplayManagerFlags mFeatureFlags;
 
+    private VirtualDisplayAdapter mAdapter;
+
+    @Rule
+    public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
 
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
+
+        mContext.getOrCreateTestableResources().addOverride(R.integer.config_virtualDisplayLimit,
+                MAX_DEVICES);
+        mContext.getOrCreateTestableResources().addOverride(
+                R.integer.config_virtualDisplayLimitPerPackage, MAX_DEVICES_PER_PACKAGE);
+
         mHandler = new TestHandler(null);
-        mVirtualDisplayAdapter = new VirtualDisplayAdapter(new DisplayManagerService.SyncRoot(),
-                mContextMock, mHandler, mMockListener, mMockSufaceControlDisplayFactory,
-                mFeatureFlags);
+        mAdapter = new VirtualDisplayAdapter(new DisplayManagerService.SyncRoot(), mContext,
+                mHandler, mMockListener, mMockSufaceControlDisplayFactory, mFeatureFlags);
 
         when(mMockCallback.asBinder()).thenReturn(mMockBinder);
     }
 
     @Test
-    public void testCreatesVirtualDisplay() {
+    public void testCreateAndReleaseVirtualDisplay() {
         VirtualDisplayConfig config = new VirtualDisplayConfig.Builder("test", /* width= */ 1,
                 /* height= */ 1, /* densityDpi= */ 1).build();
+        int ownerUid = 10;
 
-        DisplayDevice result = mVirtualDisplayAdapter.createVirtualDisplayLocked(mMockCallback,
-                /* projection= */ null, /* ownerUid= */ 10, /* packageName= */ "testpackage",
+        DisplayDevice result = mAdapter.createVirtualDisplayLocked(mMockCallback,
+                /* projection= */ null, ownerUid, /* packageName= */ "testpackage",
                 /* uniqueId= */ "uniqueId", /* surface= */ null, /* flags= */ 0, config);
+        assertNotNull(result);
 
+        result = mAdapter.releaseVirtualDisplayLocked(mMockBinder, ownerUid);
         assertNotNull(result);
     }
 
@@ -98,7 +131,7 @@
         final String displayUniqueId = VirtualDisplayAdapter.generateDisplayUniqueId(
                 packageName, Process.myUid(), config);
 
-        DisplayDevice result = mVirtualDisplayAdapter.createVirtualDisplayLocked(
+        DisplayDevice result = mAdapter.createVirtualDisplayLocked(
                 mMockCallback, /* projection= */ null, /* ownerUid= */ 10,
                 packageName, displayUniqueId, /* surface= */ null, /* flags= */ 0, config);
 
@@ -114,14 +147,194 @@
                 /* height= */ 1, /* densityDpi= */ 1).build();
         VirtualDisplayConfig config2 = new VirtualDisplayConfig.Builder("test2", /* width= */ 1,
                 /* height= */ 1, /* densityDpi= */ 1).build();
-        mVirtualDisplayAdapter.createVirtualDisplayLocked(mMockCallback, /* projection= */ null,
-                /* ownerUid= */ 10, /* packageName= */ "testpackage", /* uniqueId= */ "uniqueId1",
-                /* surface= */ null, /* flags= */ 0, config1);
 
-        DisplayDevice result = mVirtualDisplayAdapter.createVirtualDisplayLocked(mMockCallback,
+        DisplayDevice result = mAdapter.createVirtualDisplayLocked(mMockCallback,
+                /* projection= */ null, /* ownerUid= */ 10, /* packageName= */ "testpackage",
+                /* uniqueId= */ "uniqueId1", /* surface= */ null, /* flags= */ 0, config1);
+        assertNotNull(result);
+
+        result = mAdapter.createVirtualDisplayLocked(mMockCallback,
                 /* projection= */ null, /* ownerUid= */ 10, /* packageName= */ "testpackage",
                 /* uniqueId= */ "uniqueId2", /* surface= */ null, /* flags= */ 0, config2);
-
         assertNull(result);
     }
+
+    @Test
+    public void testCreateManyVirtualDisplays_LimitFlagDisabled() {
+        when(mFeatureFlags.isVirtualDisplayLimitEnabled()).thenReturn(false);
+
+        // Displays for the same package
+        for (int i = 0; i < MAX_DEVICES_PER_PACKAGE * 2; i++) {
+            // Same owner UID
+            IVirtualDisplayCallback callback = createCallback();
+            DisplayDevice device = mAdapter.createVirtualDisplayLocked(callback,
+                    mMediaProjectionMock, 1234, "test.package", "123",
+                    mSurfaceMock, /* flags= */ 0, mVirtualDisplayConfigMock);
+            assertNotNull(device);
+        }
+
+        // Displays for different packages
+        for (int i = 0; i < MAX_DEVICES * 2; i++) {
+            // Same owner UID
+            IVirtualDisplayCallback callback = createCallback();
+            DisplayDevice device = mAdapter.createVirtualDisplayLocked(callback,
+                    mMediaProjectionMock, 1234 + i, "test.package", "123",
+                    mSurfaceMock, /* flags= */ 0, mVirtualDisplayConfigMock);
+            assertNotNull(device);
+        }
+    }
+
+    @Test
+    public void testCreateVirtualDisplay_MaxDisplaysPerPackage() {
+        when(mFeatureFlags.isVirtualDisplayLimitEnabled()).thenReturn(true);
+        List<IVirtualDisplayCallback> callbacks = new ArrayList<>();
+        int ownerUid = 1234;
+
+        for (int i = 0; i < MAX_DEVICES_PER_PACKAGE * 2; i++) {
+            // Same owner UID
+            IVirtualDisplayCallback callback = createCallback();
+            DisplayDevice device = mAdapter.createVirtualDisplayLocked(callback,
+                    mMediaProjectionMock, ownerUid, "test.package", "123",
+                    mSurfaceMock, /* flags= */ 0, mVirtualDisplayConfigMock);
+            if (i < MAX_DEVICES_PER_PACKAGE) {
+                assertNotNull(device);
+                callbacks.add(callback);
+            } else {
+                assertNull(device);
+            }
+        }
+
+        // Release one display
+        DisplayDevice device = mAdapter.releaseVirtualDisplayLocked(callbacks.get(0).asBinder(),
+                ownerUid);
+        assertNotNull(device);
+        callbacks.remove(0);
+
+        // We should be able to create another display
+        IVirtualDisplayCallback callback = createCallback();
+        device = mAdapter.createVirtualDisplayLocked(callback, mMediaProjectionMock, ownerUid,
+                "test.package", "123", mSurfaceMock, /* flags= */ 0,
+                mVirtualDisplayConfigMock);
+        assertNotNull(device);
+        callbacks.add(callback);
+
+        // But only one
+        callback = createCallback();
+        device = mAdapter.createVirtualDisplayLocked(callback, mMediaProjectionMock, ownerUid,
+                "test.package", "123", mSurfaceMock, /* flags= */ 0,
+                mVirtualDisplayConfigMock);
+        assertNull(device);
+
+        // Release all the displays
+        for (IVirtualDisplayCallback cb : callbacks) {
+            device = mAdapter.releaseVirtualDisplayLocked(cb.asBinder(), ownerUid);
+            assertNotNull(device);
+        }
+        callbacks.clear();
+
+        // We should be able to create the max number of displays again
+        for (int i = 0; i < MAX_DEVICES_PER_PACKAGE * 2; i++) {
+            // Same owner UID
+            callback = createCallback();
+            device = mAdapter.createVirtualDisplayLocked(callback, mMediaProjectionMock, ownerUid,
+                    "test.package", "123", mSurfaceMock, /* flags= */ 0,
+                    mVirtualDisplayConfigMock);
+            if (i < MAX_DEVICES_PER_PACKAGE) {
+                assertNotNull(device);
+                callbacks.add(callback);
+            } else {
+                assertNull(device);
+            }
+        }
+
+        // We should be able to create a display for a different package
+        callback = createCallback();
+        device = mAdapter.createVirtualDisplayLocked(callback, mMediaProjectionMock, ownerUid + 1,
+                "test.package", "123", mSurfaceMock, /* flags= */ 0,
+                mVirtualDisplayConfigMock);
+        assertNotNull(device);
+        callbacks.add(callback);
+    }
+
+    @Test
+    public void testCreateVirtualDisplay_MaxDisplays() {
+        when(mFeatureFlags.isVirtualDisplayLimitEnabled()).thenReturn(true);
+        List<IVirtualDisplayCallback> callbacks = new ArrayList<>();
+        int firstOwnerUid = 1000;
+
+        for (int i = 0; i < MAX_DEVICES * 2; i++) {
+            // Different owner UID
+            IVirtualDisplayCallback callback = createCallback();
+            DisplayDevice device = mAdapter.createVirtualDisplayLocked(callback,
+                    mMediaProjectionMock, firstOwnerUid + i, "test.package",
+                    "123", mSurfaceMock, /* flags= */ 0, mVirtualDisplayConfigMock);
+            if (i < MAX_DEVICES) {
+                assertNotNull(device);
+                callbacks.add(callback);
+            } else {
+                assertNull(device);
+            }
+        }
+
+        // Release one display
+        DisplayDevice device = mAdapter.releaseVirtualDisplayLocked(callbacks.get(0).asBinder(),
+                firstOwnerUid);
+        assertNotNull(device);
+        callbacks.remove(0);
+
+        // We should be able to create another display
+        IVirtualDisplayCallback callback = createCallback();
+        device = mAdapter.createVirtualDisplayLocked(callback, mMediaProjectionMock,
+                firstOwnerUid, "test.package", "123", mSurfaceMock, /* flags= */ 0,
+                mVirtualDisplayConfigMock);
+        assertNotNull(device);
+        callbacks.add(callback);
+
+        // But only one
+        callback = createCallback();
+        device = mAdapter.createVirtualDisplayLocked(callback, mMediaProjectionMock,
+                firstOwnerUid, "test.package", "123", mSurfaceMock, /* flags= */ 0,
+                mVirtualDisplayConfigMock);
+        assertNull(device);
+
+        // Release all the displays
+        for (int i = 0; i < callbacks.size(); i++) {
+            device = mAdapter.releaseVirtualDisplayLocked(callbacks.get(i).asBinder(),
+                    firstOwnerUid + i);
+            assertNotNull(device);
+        }
+        callbacks.clear();
+
+        // We should be able to create the max number of displays again
+        for (int i = 0; i < MAX_DEVICES * 2; i++) {
+            // Different owner UID
+            callback = createCallback();
+            device = mAdapter.createVirtualDisplayLocked(callback, mMediaProjectionMock,
+                    firstOwnerUid + i, "test.package", "123", mSurfaceMock,
+                    /* flags= */ 0, mVirtualDisplayConfigMock);
+            if (i < MAX_DEVICES) {
+                assertNotNull(device);
+                callbacks.add(callback);
+            } else {
+                assertNull(device);
+            }
+        }
+    }
+
+    private IVirtualDisplayCallback createCallback() {
+        return new IVirtualDisplayCallback.Stub() {
+
+            @Override
+            public void onPaused() {
+            }
+
+            @Override
+            public void onResumed() {
+            }
+
+            @Override
+            public void onStopped() {
+            }
+        };
+    }
 }
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 d91f154..58f0ab4 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
@@ -1872,6 +1872,60 @@
     }
 
     @Test
+    public void testPeakRefreshRate_notAppliedToExternalDisplays() {
+        when(mDisplayManagerFlags.isBackUpSmoothDisplayAndForcePeakRefreshRateEnabled())
+                .thenReturn(true);
+        mInjector.mDisplayInfo.type = Display.TYPE_EXTERNAL;
+        DisplayModeDirector director =
+                new DisplayModeDirector(mContext, mHandler, mInjector,
+                        mDisplayManagerFlags, mDisplayDeviceConfigProvider);
+        director.getBrightnessObserver().setDefaultDisplayState(Display.STATE_ON);
+        director.getDisplayObserver().onDisplayAdded(DISPLAY_ID);
+        director.getDisplayObserver().onDisplayAdded(DISPLAY_ID_2);
+
+        Display.Mode[] modes1 = new Display.Mode[] {
+                new Display.Mode(/* modeId= */ 1, /* width= */ 1280, /* height= */ 720,
+                        /* refreshRate= */ 60),
+                new Display.Mode(/* modeId= */ 2, /* width= */ 1280, /* height= */ 720,
+                        /* refreshRate= */ 130),
+        };
+        Display.Mode[] modes2 = new Display.Mode[] {
+                new Display.Mode(/* modeId= */ 1, /* width= */ 1280, /* height= */ 720,
+                        /* refreshRate= */ 60),
+                new Display.Mode(/* modeId= */ 2, /* width= */ 1280, /* height= */ 720,
+                        /* refreshRate= */ 140),
+        };
+        SparseArray<Display.Mode[]> supportedModesByDisplay = new SparseArray<>();
+        supportedModesByDisplay.put(DISPLAY_ID, modes1);
+        supportedModesByDisplay.put(DISPLAY_ID_2, modes2);
+
+        Sensor lightSensor = createLightSensor();
+        SensorManager sensorManager = createMockSensorManager(lightSensor);
+        director.start(sensorManager);
+        director.injectSupportedModesByDisplay(supportedModesByDisplay);
+
+        // Disable Smooth Display
+        setPeakRefreshRate(RefreshRateSettingsUtils.DEFAULT_REFRESH_RATE);
+
+        Vote vote1 = director.getVote(DISPLAY_ID,
+                Vote.PRIORITY_USER_SETTING_PEAK_RENDER_FRAME_RATE);
+        Vote vote2 = director.getVote(DISPLAY_ID_2,
+                Vote.PRIORITY_USER_SETTING_PEAK_RENDER_FRAME_RATE);
+        assertThat(vote1).isNull();
+        assertThat(vote2).isNull();
+
+        // Enable Smooth Display
+        setPeakRefreshRate(Float.POSITIVE_INFINITY);
+
+        vote1 = director.getVote(DISPLAY_ID,
+                Vote.PRIORITY_USER_SETTING_PEAK_RENDER_FRAME_RATE);
+        vote2 = director.getVote(DISPLAY_ID_2,
+                Vote.PRIORITY_USER_SETTING_PEAK_RENDER_FRAME_RATE);
+        assertThat(vote1).isNull();
+        assertThat(vote2).isNull();
+    }
+
+    @Test
     public void testPeakRefreshRate_DisplayChanged() {
         when(mDisplayManagerFlags.isBackUpSmoothDisplayAndForcePeakRefreshRateEnabled())
                 .thenReturn(true);
@@ -1968,8 +2022,9 @@
     @Test
     @Parameters({
         "true, true, 60",
-        "false, true, 50",
-        "true, false, 50"
+        "false, true, 60",
+        "true, false, 50",
+        "false, false, 50"
     })
     public void testExternalDisplayMaxRefreshRate(boolean isRefreshRateSynchronizationEnabled,
             boolean isExternalDisplay, float expectedMaxRenderFrameRate) {
@@ -3810,6 +3865,7 @@
                 SensorManagerInternal sensorManagerInternal) {
             mDeviceConfig = new FakeDeviceConfig();
             mDisplayInfo = new DisplayInfo();
+            mDisplayInfo.type = Display.TYPE_INTERNAL;
             mDisplayInfo.defaultModeId = MODE_ID;
             mDisplayInfo.supportedModes = new Display.Mode[] {new Display.Mode(MODE_ID,
                     800, 600, /* refreshRate= */ 60)};
@@ -3856,6 +3912,7 @@
         @Override
         public boolean getDisplayInfo(int displayId, DisplayInfo displayInfo) {
             displayInfo.copyFrom(mDisplayInfo);
+            displayInfo.displayId = displayId;
             return mDisplayInfoValid;
         }
 
diff --git a/services/tests/displayservicetests/src/com/android/server/display/mode/DisplayObserverTest.java b/services/tests/displayservicetests/src/com/android/server/display/mode/DisplayObserverTest.java
index 5e240cf..e3f150e 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/mode/DisplayObserverTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/mode/DisplayObserverTest.java
@@ -189,6 +189,7 @@
     @Test
     public void testExternalDisplay_voteUserPreferredMode() {
         when(mDisplayManagerFlags.isUserPreferredModeVoteEnabled()).thenReturn(true);
+        when(mDisplayManagerFlags.isUserRefreshRateForExternalDisplayEnabled()).thenReturn(false);
         var preferredMode = mExternalDisplayModes[5];
         mExternalDisplayUserPreferredModeId = preferredMode.getModeId();
         var expectedVote = Vote.forSize(
@@ -229,6 +230,108 @@
                 .isEqualTo(null);
     }
 
+    /** Vote for user preferred mode */
+    @Test
+    public void testDefaultDisplay_voteUserPreferredMode() {
+        when(mDisplayManagerFlags.isUserPreferredModeVoteEnabled()).thenReturn(true);
+        when(mDisplayManagerFlags.isUserRefreshRateForExternalDisplayEnabled()).thenReturn(true);
+        var preferredMode = mInternalDisplayModes[5];
+        mInternalDisplayUserPreferredModeId = preferredMode.getModeId();
+        var expectedVote = Vote.forSize(
+                        preferredMode.getPhysicalWidth(),
+                        preferredMode.getPhysicalHeight());
+        init();
+        assertThat(getVote(DEFAULT_DISPLAY, PRIORITY_USER_SETTING_DISPLAY_PREFERRED_SIZE))
+                .isEqualTo(null);
+        mObserver.onDisplayAdded(EXTERNAL_DISPLAY);
+        mObserver.onDisplayAdded(DEFAULT_DISPLAY);
+        assertThat(getVote(EXTERNAL_DISPLAY, PRIORITY_USER_SETTING_DISPLAY_PREFERRED_SIZE))
+                .isEqualTo(null);
+        assertThat(getVote(DEFAULT_DISPLAY, PRIORITY_USER_SETTING_DISPLAY_PREFERRED_SIZE))
+                .isEqualTo(expectedVote);
+
+        mInternalDisplayUserPreferredModeId = INVALID_MODE_ID;
+        mObserver.onDisplayChanged(EXTERNAL_DISPLAY);
+        mObserver.onDisplayChanged(DEFAULT_DISPLAY);
+        assertThat(getVote(DEFAULT_DISPLAY, PRIORITY_USER_SETTING_DISPLAY_PREFERRED_SIZE))
+                .isEqualTo(null);
+        assertThat(getVote(EXTERNAL_DISPLAY, PRIORITY_USER_SETTING_DISPLAY_PREFERRED_SIZE))
+                .isEqualTo(null);
+
+        preferredMode = mInternalDisplayModes[4];
+        mInternalDisplayUserPreferredModeId = preferredMode.getModeId();
+        expectedVote = Vote.forSize(
+                        preferredMode.getPhysicalWidth(),
+                        preferredMode.getPhysicalHeight());
+        mObserver.onDisplayChanged(EXTERNAL_DISPLAY);
+        mObserver.onDisplayChanged(DEFAULT_DISPLAY);
+        assertThat(getVote(DEFAULT_DISPLAY, PRIORITY_USER_SETTING_DISPLAY_PREFERRED_SIZE))
+                .isEqualTo(expectedVote);
+        assertThat(getVote(EXTERNAL_DISPLAY, PRIORITY_USER_SETTING_DISPLAY_PREFERRED_SIZE))
+                .isEqualTo(null);
+
+        // Testing that the vote is removed.
+        mObserver.onDisplayRemoved(EXTERNAL_DISPLAY);
+        assertThat(getVote(DEFAULT_DISPLAY, PRIORITY_USER_SETTING_DISPLAY_PREFERRED_SIZE))
+                .isEqualTo(expectedVote);
+        assertThat(getVote(EXTERNAL_DISPLAY, PRIORITY_USER_SETTING_DISPLAY_PREFERRED_SIZE))
+                .isEqualTo(null);
+    }
+
+    /** Vote for user preferred mode with refresh rate, synchronization vote must be disabled */
+    @Test
+    public void testExternalDisplay_voteUserPreferredMode_withRefreshRate() {
+        when(mDisplayManagerFlags.isUserPreferredModeVoteEnabled()).thenReturn(true);
+        when(mDisplayManagerFlags.isDisplaysRefreshRatesSynchronizationEnabled()).thenReturn(false);
+        when(mDisplayManagerFlags.isUserRefreshRateForExternalDisplayEnabled()).thenReturn(true);
+        var preferredMode = mExternalDisplayModes[5];
+        mExternalDisplayUserPreferredModeId = preferredMode.getModeId();
+        var expectedVote = Vote.forSizeAndPhysicalRefreshRatesRange(
+                        preferredMode.getPhysicalWidth(),
+                        preferredMode.getPhysicalHeight(),
+                        preferredMode.getPhysicalWidth(),
+                        preferredMode.getPhysicalHeight(),
+                        preferredMode.getRefreshRate(),
+                        preferredMode.getRefreshRate());
+        init();
+        assertThat(getVote(EXTERNAL_DISPLAY, PRIORITY_USER_SETTING_DISPLAY_PREFERRED_SIZE))
+                .isEqualTo(null);
+        mObserver.onDisplayAdded(EXTERNAL_DISPLAY);
+        assertThat(getVote(DEFAULT_DISPLAY, PRIORITY_USER_SETTING_DISPLAY_PREFERRED_SIZE))
+                .isEqualTo(null);
+        assertThat(getVote(EXTERNAL_DISPLAY, PRIORITY_USER_SETTING_DISPLAY_PREFERRED_SIZE))
+                .isEqualTo(expectedVote);
+
+        mExternalDisplayUserPreferredModeId = INVALID_MODE_ID;
+        mObserver.onDisplayChanged(EXTERNAL_DISPLAY);
+        assertThat(getVote(DEFAULT_DISPLAY, PRIORITY_USER_SETTING_DISPLAY_PREFERRED_SIZE))
+                .isEqualTo(null);
+        assertThat(getVote(EXTERNAL_DISPLAY, PRIORITY_USER_SETTING_DISPLAY_PREFERRED_SIZE))
+                .isEqualTo(null);
+
+        preferredMode = mExternalDisplayModes[4];
+        mExternalDisplayUserPreferredModeId = preferredMode.getModeId();
+        expectedVote = Vote.forSizeAndPhysicalRefreshRatesRange(
+                        preferredMode.getPhysicalWidth(),
+                        preferredMode.getPhysicalHeight(),
+                        preferredMode.getPhysicalWidth(),
+                        preferredMode.getPhysicalHeight(),
+                        preferredMode.getRefreshRate(),
+                        preferredMode.getRefreshRate());
+        mObserver.onDisplayChanged(EXTERNAL_DISPLAY);
+        assertThat(getVote(DEFAULT_DISPLAY, PRIORITY_USER_SETTING_DISPLAY_PREFERRED_SIZE))
+                .isEqualTo(null);
+        assertThat(getVote(EXTERNAL_DISPLAY, PRIORITY_USER_SETTING_DISPLAY_PREFERRED_SIZE))
+                .isEqualTo(expectedVote);
+
+        // Testing that the vote is removed.
+        mObserver.onDisplayRemoved(EXTERNAL_DISPLAY);
+        assertThat(getVote(DEFAULT_DISPLAY, PRIORITY_USER_SETTING_DISPLAY_PREFERRED_SIZE))
+                .isEqualTo(null);
+        assertThat(getVote(EXTERNAL_DISPLAY, PRIORITY_USER_SETTING_DISPLAY_PREFERRED_SIZE))
+                .isEqualTo(null);
+    }
+
     /** External display: Do not apply limit to user preferred mode */
     @Test
     public void testExternalDisplay_doNotApplyLimitToUserPreferredMode() {
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/ActivityManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/am/ActivityManagerServiceTest.java
index 809e13c..6ccc037 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/ActivityManagerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/ActivityManagerServiceTest.java
@@ -29,6 +29,7 @@
 import static android.app.ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND;
 import static android.app.ActivityManager.PROCESS_STATE_UNKNOWN;
 import static android.content.ContentResolver.SCHEME_CONTENT;
+import static android.content.Intent.FILL_IN_ACTION;
 import static android.os.PowerExemptionManager.REASON_DENIED;
 import static android.os.UserHandle.USER_ALL;
 import static android.util.DebugUtils.valueToString;
@@ -1300,6 +1301,45 @@
                 .containsExactly(new Pair<>(USER_ID, 42));
     }
 
+    @Test
+    @RequiresFlagsEnabled(android.security.Flags.FLAG_PREVENT_INTENT_REDIRECT)
+    public void testAddCreatorToken() {
+        Intent intent = new Intent();
+        Intent extraIntent = new Intent("EXTRA_INTENT_ACTION");
+        intent.putExtra("EXTRA_INTENT0", extraIntent);
+
+        intent.collectExtraIntentKeys();
+        mAms.addCreatorToken(intent);
+
+        ActivityManagerService.IntentCreatorToken token =
+                (ActivityManagerService.IntentCreatorToken) extraIntent.getCreatorToken();
+        assertThat(token).isNotNull();
+        assertThat(token.getCreatorUid()).isEqualTo(mInjector.getCallingUid());
+    }
+
+    @Test
+    @RequiresFlagsEnabled(android.security.Flags.FLAG_PREVENT_INTENT_REDIRECT)
+    public void testAddCreatorTokenForFillingIntent() {
+        Intent intent = new Intent();
+        Intent extraIntent = new Intent("EXTRA_INTENT_ACTION");
+        intent.putExtra("EXTRA_INTENT0", extraIntent);
+        Intent fillinIntent = new Intent();
+        Intent fillinExtraIntent = new Intent("FILLIN_EXTRA_INTENT_ACTION");
+        fillinIntent.putExtra("FILLIN_EXTRA_INTENT0", fillinExtraIntent);
+
+        fillinIntent.collectExtraIntentKeys();
+        intent.fillIn(fillinIntent, FILL_IN_ACTION);
+
+        mAms.addCreatorToken(fillinIntent);
+
+        fillinExtraIntent = intent.getParcelableExtra("FILLIN_EXTRA_INTENT0", Intent.class);
+
+        ActivityManagerService.IntentCreatorToken token =
+                (ActivityManagerService.IntentCreatorToken) fillinExtraIntent.getCreatorToken();
+        assertThat(token).isNotNull();
+        assertThat(token.getCreatorUid()).isEqualTo(mInjector.getCallingUid());
+    }
+
     private void verifyWaitingForNetworkStateUpdate(long curProcStateSeq,
             long lastNetworkUpdatedProcStateSeq,
             final long procStateSeqToWait, boolean expectWait) throws Exception {
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java b/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
index 2107406..7dbd057 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
@@ -171,6 +171,8 @@
     private static int sUiTierSize = 5;
 
     private Context mContext;
+    private ProcessStateController mProcessStateController;
+    private ActiveUids mActiveUids;
     private PackageManagerInternal mPackageManagerInternal;
     private ActivityManagerService mService;
     private OomAdjusterInjector mInjector = new OomAdjusterInjector();
@@ -229,15 +231,19 @@
         doCallRealMethod().when(mService).enqueueOomAdjTargetLocked(any(ProcessRecord.class));
         doCallRealMethod().when(mService).updateOomAdjPendingTargetsLocked(OOM_ADJ_REASON_ACTIVITY);
         setFieldValue(AppProfiler.class, profiler, "mProfilerLock", new Object());
+
         doNothing().when(pr).enqueueProcessChangeItemLocked(anyInt(), anyInt(), anyInt(),
                 anyInt());
         doNothing().when(pr).enqueueProcessChangeItemLocked(anyInt(), anyInt(), anyInt(),
                 anyBoolean());
-        mService.mOomAdjuster = mService.mConstants.ENABLE_NEW_OOMADJ
-                ? new OomAdjusterModernImpl(mService, mService.mProcessList,
-                        new ActiveUids(mService, false), mInjector)
-                : new OomAdjuster(mService, mService.mProcessList, new ActiveUids(mService, false),
-                        mInjector);
+        mActiveUids = new ActiveUids(mService, false);
+        mProcessStateController = new ProcessStateController.Builder(mService,
+                mService.mProcessList, mActiveUids)
+                .useModernOomAdjuster(mService.mConstants.ENABLE_NEW_OOMADJ)
+                .setOomAdjusterInjector(mInjector)
+                .build();
+        mService.mProcessStateController = mProcessStateController;
+        mService.mOomAdjuster = mService.mProcessStateController.getOomAdjuster();
         mService.mOomAdjuster.mAdjSeq = 10000;
         mService.mWakefulness = new AtomicInteger(PowerManagerInternal.WAKEFULNESS_AWAKE);
         mSetFlagsRule.enableFlags(Flags.FLAG_NEW_FGS_RESTRICTION_LOGIC);
@@ -246,8 +252,8 @@
     @SuppressWarnings("GuardedBy")
     @After
     public void tearDown() {
-        mService.mOomAdjuster.resetInternal();
-        mService.mOomAdjuster.mActiveUids.clear();
+        mProcessStateController.getOomAdjuster().resetInternal();
+        mActiveUids.clear();
         LocalServices.removeServiceForTest(PackageManagerInternal.class);
         mInjector.reset();
     }
@@ -293,7 +299,7 @@
     private void updateOomAdj(ProcessRecord... apps) {
         if (apps.length == 0) {
             updateProcessRecordNodes(mService.mProcessList.getLruProcessesLOSP());
-            mService.mOomAdjuster.updateOomAdjLocked(OOM_ADJ_REASON_NONE);
+            mProcessStateController.runFullUpdate(OOM_ADJ_REASON_NONE);
         } else {
             updateProcessRecordNodes(Arrays.asList(apps));
             if (apps.length == 1) {
@@ -301,10 +307,10 @@
                 if (!mService.mProcessList.getLruProcessesLOSP().contains(app)) {
                     mService.mProcessList.getLruProcessesLOSP().add(app);
                 }
-                mService.mOomAdjuster.updateOomAdjLocked(apps[0], OOM_ADJ_REASON_NONE);
+                mProcessStateController.runUpdate(apps[0], OOM_ADJ_REASON_NONE);
             } else {
                 setProcessesToLru(apps);
-                mService.mOomAdjuster.updateOomAdjLocked(OOM_ADJ_REASON_NONE);
+                mProcessStateController.runFullUpdate(OOM_ADJ_REASON_NONE);
                 mService.mProcessList.getLruProcessesLOSP().clear();
             }
         }
@@ -318,9 +324,9 @@
     private void updateOomAdjPending(ProcessRecord... apps) {
         setProcessesToLru(apps);
         for (ProcessRecord app : apps) {
-            mService.mOomAdjuster.enqueueOomAdjTargetLocked(app);
+            mProcessStateController.enqueueUpdateTarget(app);
         }
-        mService.mOomAdjuster.updateOomAdjPendingTargetsLocked(OOM_ADJ_REASON_NONE);
+        mProcessStateController.runPendingUpdate(OOM_ADJ_REASON_NONE);
         mService.mProcessList.getLruProcessesLOSP().clear();
     }
 
@@ -341,11 +347,10 @@
     public void testUpdateOomAdj_DoOne_Persistent_TopUi_Sleeping() {
         ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
                 MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
-        app.mState.setMaxAdj(PERSISTENT_PROC_ADJ);
-        app.mState.setHasTopUi(true);
-        mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_ASLEEP);
+        mProcessStateController.setMaxAdj(app, PERSISTENT_PROC_ADJ);
+        mProcessStateController.setHasTopUi(app, true);
+        setWakefulness(PowerManagerInternal.WAKEFULNESS_ASLEEP);
         updateOomAdj(app);
-        mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
 
         assertProcStates(app, PROCESS_STATE_BOUND_FOREGROUND_SERVICE, PERSISTENT_PROC_ADJ,
                 SCHED_GROUP_RESTRICTED);
@@ -357,9 +362,9 @@
     public void testUpdateOomAdj_DoOne_Persistent_TopUi_Awake() {
         ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
                 MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
-        app.mState.setMaxAdj(PERSISTENT_PROC_ADJ);
-        app.mState.setHasTopUi(true);
-        mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+        mProcessStateController.setMaxAdj(app, PERSISTENT_PROC_ADJ);
+        mProcessStateController.setHasTopUi(app, true);
+        setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
         updateOomAdj(app);
 
         assertProcStates(app, PROCESS_STATE_PERSISTENT_UI, PERSISTENT_PROC_ADJ,
@@ -371,9 +376,9 @@
     public void testUpdateOomAdj_DoOne_Persistent_TopApp() {
         ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
                 MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
-        app.mState.setMaxAdj(PERSISTENT_PROC_ADJ);
+        mProcessStateController.setMaxAdj(app, PERSISTENT_PROC_ADJ);
         doReturn(app).when(mService).getTopApp();
-        mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+        setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
         updateOomAdj(app);
         doReturn(null).when(mService).getTopApp();
 
@@ -388,7 +393,7 @@
                 MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
         doReturn(PROCESS_STATE_TOP).when(mService.mAtmInternal).getTopProcessState();
         doReturn(app).when(mService).getTopApp();
-        mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+        setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
         updateOomAdj(app);
         doReturn(null).when(mService).getTopApp();
 
@@ -401,8 +406,8 @@
         ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
                 MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
         doReturn(PROCESS_STATE_TOP_SLEEPING).when(mService.mAtmInternal).getTopProcessState();
-        app.mState.setRunningRemoteAnimation(true);
-        mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+        mProcessStateController.setRunningRemoteAnimation(app, true);
+        setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
         updateOomAdj(app);
         doReturn(PROCESS_STATE_TOP).when(mService.mAtmInternal).getTopProcessState();
 
@@ -415,7 +420,7 @@
         ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
                 MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
         doReturn(mock(ActiveInstrumentation.class)).when(app).getActiveInstrumentation();
-        mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+        setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
         updateOomAdj(app);
         doCallRealMethod().when(app).getActiveInstrumentation();
 
@@ -431,7 +436,7 @@
                 MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
         doReturn(true).when(mService).isReceivingBroadcastLocked(any(ProcessRecord.class),
                 any(int[].class));
-        mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+        setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
         updateOomAdj(app);
         doReturn(false).when(mService).isReceivingBroadcastLocked(any(ProcessRecord.class),
                 any(int[].class));
@@ -466,8 +471,8 @@
     public void testUpdateOomAdj_DoOne_ExecutingService() {
         ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
                 MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
-        app.mServices.startExecutingService(mock(ServiceRecord.class));
-        mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+        mProcessStateController.startExecutingService(app.mServices, mock(ServiceRecord.class));
+        setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
         updateOomAdj(app);
 
         assertProcStates(app, PROCESS_STATE_SERVICE, FOREGROUND_APP_ADJ, SCHED_GROUP_BACKGROUND);
@@ -480,11 +485,11 @@
                 MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
         doReturn(PROCESS_STATE_TOP_SLEEPING).when(mService.mAtmInternal).getTopProcessState();
         doReturn(app).when(mService).getTopApp();
-        mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_ASLEEP);
+        setWakefulness(PowerManagerInternal.WAKEFULNESS_ASLEEP);
         updateOomAdj(app);
         doReturn(null).when(mService).getTopApp();
         doReturn(PROCESS_STATE_TOP).when(mService.mAtmInternal).getTopProcessState();
-        mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+        setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
 
         assertProcStates(app, PROCESS_STATE_TOP_SLEEPING, FOREGROUND_APP_ADJ,
                 SCHED_GROUP_BACKGROUND);
@@ -498,7 +503,7 @@
         app.mState.setCurRawAdj(CACHED_APP_MIN_ADJ);
         app.mState.setCurAdj(CACHED_APP_MIN_ADJ);
         doReturn(null).when(mService).getTopApp();
-        mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+        setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
         updateOomAdj(app);
 
         final int expectedAdj = mService.mConstants.USE_TIERED_CACHED_ADJ
@@ -516,7 +521,7 @@
         doReturn(true).when(wpc).hasActivities();
         doReturn(WindowProcessController.ACTIVITY_STATE_FLAG_IS_VISIBLE)
                 .when(wpc).getActivityStateFlags();
-        mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+        setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
         updateOomAdj(app);
 
         assertProcStates(app, PROCESS_STATE_TOP, VISIBLE_APP_ADJ, SCHED_GROUP_DEFAULT);
@@ -555,7 +560,7 @@
         WindowProcessController wpc = app.getWindowProcessController();
         doReturn(true).when(wpc).hasRecentTasks();
         app.mState.setLastTopTime(SystemClock.uptimeMillis());
-        mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+        setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
         updateOomAdj(app);
         doCallRealMethod().when(wpc).hasRecentTasks();
 
@@ -567,9 +572,9 @@
     public void testUpdateOomAdj_DoOne_FgServiceLocation() {
         ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
                 MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
-        app.mServices.setHasForegroundServices(true, ServiceInfo.FOREGROUND_SERVICE_TYPE_LOCATION,
-                /* hasNoneType=*/false);
-        mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+        mProcessStateController.setHasForegroundServices(app.mServices, true,
+                ServiceInfo.FOREGROUND_SERVICE_TYPE_LOCATION, /* hasNoneType=*/false);
+        setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
         updateOomAdj(app);
 
         assertProcStates(app, PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
@@ -582,8 +587,9 @@
     public void testUpdateOomAdj_DoOne_FgService() {
         ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
                 MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
-        app.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
-        mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+        mProcessStateController.setHasForegroundServices(app.mServices, true, 0, /* hasNoneType=*/
+                true);
+        setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
         updateOomAdj(app);
 
         assertProcStates(app, PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
@@ -599,20 +605,20 @@
 
         ServiceRecord s = ServiceRecord.newEmptyInstanceForTest(mService);
         s.appInfo = new ApplicationInfo();
-        s.startRequested = true;
+        mProcessStateController.setStartRequested(s, true);
         s.isForeground = true;
         s.foregroundServiceType = FOREGROUND_SERVICE_TYPE_SHORT_SERVICE;
-        s.setShortFgsInfo(SystemClock.uptimeMillis());
+        mProcessStateController.setShortFgsInfo(s, SystemClock.uptimeMillis());
 
         // SHORT_SERVICE FGS will get IMP_FG and a slightly different recent-adjustment.
         {
             ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
                     MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
-            app.mServices.startService(s);
-            app.mServices.setHasForegroundServices(true,
+            mProcessStateController.startService(app.mServices, s);
+            mProcessStateController.setHasForegroundServices(app.mServices, true,
                     FOREGROUND_SERVICE_TYPE_SHORT_SERVICE, /* hasNoneType=*/false);
             app.mState.setLastTopTime(SystemClock.uptimeMillis());
-            mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+            setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
 
             updateOomAdj(app);
 
@@ -625,9 +631,9 @@
         {
             ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
                     MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
-            app.mServices.setHasForegroundServices(true,
+            mProcessStateController.setHasForegroundServices(app.mServices, true,
                     FOREGROUND_SERVICE_TYPE_SHORT_SERVICE, /* hasNoneType=*/false);
-            app.mServices.startService(s);
+            mProcessStateController.startService(app.mServices, s);
             app.mState.setLastTopTime(SystemClock.uptimeMillis()
                     - mService.mConstants.TOP_TO_FGS_GRACE_DURATION);
             mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
@@ -642,21 +648,21 @@
         // SHORT_SERVICE, timed out already.
         s = ServiceRecord.newEmptyInstanceForTest(mService);
         s.appInfo = new ApplicationInfo();
-        s.startRequested = true;
+        mProcessStateController.setStartRequested(s, true);
         s.isForeground = true;
         s.foregroundServiceType = FOREGROUND_SERVICE_TYPE_SHORT_SERVICE;
-        s.setShortFgsInfo(SystemClock.uptimeMillis()
+        mProcessStateController.setShortFgsInfo(s, SystemClock.uptimeMillis()
                 - mService.mConstants.mShortFgsTimeoutDuration
                 - mService.mConstants.mShortFgsProcStateExtraWaitDuration);
         {
             ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
                     MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
-            app.mServices.setHasForegroundServices(true,
+            mProcessStateController.setHasForegroundServices(app.mServices, true,
                     FOREGROUND_SERVICE_TYPE_SHORT_SERVICE, /* hasNoneType=*/false);
-            app.mServices.startService(s);
+            mProcessStateController.startService(app.mServices, s);
             app.mState.setLastTopTime(SystemClock.uptimeMillis()
                     - mService.mConstants.TOP_TO_FGS_GRACE_DURATION);
-            mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+            setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
 
             updateOomAdj(app);
 
@@ -671,8 +677,8 @@
     public void testUpdateOomAdj_DoOne_OverlayUi() {
         ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
                 MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
-        app.mState.setHasOverlayUi(true);
-        mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+        mProcessStateController.setHasOverlayUi(app, true);
+        setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
         updateOomAdj(app);
 
         assertProcStates(app, PROCESS_STATE_IMPORTANT_FOREGROUND, PERCEPTIBLE_APP_ADJ,
@@ -684,9 +690,10 @@
     public void testUpdateOomAdj_DoOne_PerceptibleRecent_FgService() {
         ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
                 MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
-        app.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
+        mProcessStateController.setHasForegroundServices(app.mServices, true, 0, /* hasNoneType=*/
+                true);
         app.mState.setLastTopTime(SystemClock.uptimeMillis());
-        mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+        setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
         updateOomAdj(app);
 
         assertProcStates(app, PROCESS_STATE_FOREGROUND_SERVICE,
@@ -699,7 +706,7 @@
         verify(mService.mHandler).sendEmptyMessageAtTime(
                 eq(FOLLOW_UP_OOMADJUSTER_UPDATE_MSG), followUpTimeCaptor.capture());
         mInjector.jumpUptimeAheadTo(followUpTimeCaptor.getValue());
-        mService.mOomAdjuster.updateOomAdjFollowUpTargetsLocked();
+        mProcessStateController.runFollowUpUpdate();
 
         assertProcStates(app, PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
                 SCHED_GROUP_DEFAULT, "fg-service");
@@ -722,9 +729,9 @@
             // Simulate the system starting and binding to a service in the app.
             ServiceRecord s = bindService(app, system,
                     null, null, Context.BIND_ALMOST_PERCEPTIBLE, mock(IBinder.class));
-            s.lastTopAlmostPerceptibleBindRequestUptimeMs = nowUptime;
+            mProcessStateController.setLastTopAlmostPerceptibleBindRequest(s, nowUptime);
             s.getConnections().clear();
-            app.mServices.updateHasTopStartedAlmostPerceptibleServices();
+            mProcessStateController.updateHasTopStartedAlmostPerceptibleServices(app.mServices);
             mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
             updateOomAdj(app);
 
@@ -736,7 +743,7 @@
             verify(mService.mHandler).sendEmptyMessageAtTime(
                     eq(FOLLOW_UP_OOMADJUSTER_UPDATE_MSG), followUpTimeCaptor.capture());
             mInjector.jumpUptimeAheadTo(followUpTimeCaptor.getValue());
-            mService.mOomAdjuster.updateOomAdjFollowUpTargetsLocked();
+            mProcessStateController.runFollowUpUpdate();
 
             final int expectedAdj = mService.mConstants.USE_TIERED_CACHED_ADJ
                     ? sFirstUiCachedAdj : sFirstCachedAdj;
@@ -758,15 +765,15 @@
             // Simulate the system starting and binding to a service in the app.
             ServiceRecord s = bindService(app, system,
                     null, null, Context.BIND_ALMOST_PERCEPTIBLE + 2, mock(IBinder.class));
-            s.lastTopAlmostPerceptibleBindRequestUptimeMs =
-                    nowUptime - 2 * mService.mConstants.mServiceBindAlmostPerceptibleTimeoutMs;
-            app.mServices.updateHasTopStartedAlmostPerceptibleServices();
-            mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+            mProcessStateController.setLastTopAlmostPerceptibleBindRequest(s,
+                    nowUptime - 2 * mService.mConstants.mServiceBindAlmostPerceptibleTimeoutMs);
+            mProcessStateController.updateHasTopStartedAlmostPerceptibleServices(app.mServices);
+            setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
             updateOomAdj(app);
 
             assertEquals(PERCEPTIBLE_RECENT_FOREGROUND_APP_ADJ + 2, app.mState.getSetAdj());
 
-            mService.mOomAdjuster.resetInternal();
+            mProcessStateController.getOomAdjuster().resetInternal();
         }
 
         // Out of grace period and no valid binding so no adjustment.
@@ -780,16 +787,16 @@
             // Simulate the system starting and binding to a service in the app.
             ServiceRecord s = bindService(app, system,
                     null, null, Context.BIND_ALMOST_PERCEPTIBLE, mock(IBinder.class));
-            s.lastTopAlmostPerceptibleBindRequestUptimeMs =
-                    nowUptime - 2 * mService.mConstants.mServiceBindAlmostPerceptibleTimeoutMs;
+            mProcessStateController.setLastTopAlmostPerceptibleBindRequest(s,
+                    nowUptime - 2 * mService.mConstants.mServiceBindAlmostPerceptibleTimeoutMs);
             s.getConnections().clear();
-            app.mServices.updateHasTopStartedAlmostPerceptibleServices();
-            mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+            mProcessStateController.updateHasTopStartedAlmostPerceptibleServices(app.mServices);
+            setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
             updateOomAdj(app);
 
             assertNotEquals(PERCEPTIBLE_RECENT_FOREGROUND_APP_ADJ + 2, app.mState.getSetAdj());
 
-            mService.mOomAdjuster.resetInternal();
+            mProcessStateController.getOomAdjuster().resetInternal();
         }
     }
 
@@ -800,12 +807,12 @@
                 MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
         ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
                 MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, true));
-        system.mState.setMaxAdj(PERSISTENT_PROC_ADJ);
-        system.mState.setHasTopUi(true);
+        mProcessStateController.setMaxAdj(system, PERSISTENT_PROC_ADJ);
+        mProcessStateController.setHasTopUi(system, true);
         // Simulate the system starting and binding to a service in the app.
         ServiceRecord s = bindService(app, system,
                 null, null, Context.BIND_ALMOST_PERCEPTIBLE, mock(IBinder.class));
-        mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+        setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
         updateOomAdj(system, app);
 
         assertProcStates(app, PROCESS_STATE_IMPORTANT_FOREGROUND,
@@ -817,8 +824,8 @@
     public void testUpdateOomAdj_DoOne_Toast() {
         ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
                 MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
-        app.mState.setForcingToImportant(new Object());
-        mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+        mProcessStateController.setForcingToImportant(app, new Object());
+        setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
         updateOomAdj(app);
 
         assertProcStates(app, PROCESS_STATE_TRANSIENT_BACKGROUND, PERCEPTIBLE_APP_ADJ,
@@ -832,7 +839,7 @@
                 MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
         WindowProcessController wpc = app.getWindowProcessController();
         doReturn(true).when(wpc).isHeavyWeightProcess();
-        mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+        setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
         updateOomAdj(app);
         doReturn(false).when(wpc).isHeavyWeightProcess();
 
@@ -847,7 +854,7 @@
                 MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
         WindowProcessController wpc = app.getWindowProcessController();
         doReturn(true).when(wpc).isHomeProcess();
-        mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+        setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
         updateOomAdj(app);
 
         assertProcStates(app, PROCESS_STATE_HOME, HOME_APP_ADJ, SCHED_GROUP_BACKGROUND);
@@ -861,7 +868,7 @@
         WindowProcessController wpc = app.getWindowProcessController();
         doReturn(true).when(wpc).isPreviousProcess();
         doReturn(true).when(wpc).hasActivities();
-        mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+        setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
         updateOomAdj(app);
 
         assertProcStates(app, PROCESS_STATE_LAST_ACTIVITY, PREVIOUS_APP_ADJ,
@@ -873,7 +880,7 @@
         verify(mService.mHandler).sendEmptyMessageAtTime(eq(FOLLOW_UP_OOMADJUSTER_UPDATE_MSG),
                 followUpTimeCaptor.capture());
         mInjector.jumpUptimeAheadTo(followUpTimeCaptor.getValue());
-        mService.mOomAdjuster.updateOomAdjFollowUpTargetsLocked();
+        mProcessStateController.runFollowUpUpdate();
 
         int expectedAdj = mService.mConstants.USE_TIERED_CACHED_ADJ
                 ? sFirstUiCachedAdj : CACHED_APP_MIN_ADJ;
@@ -896,9 +903,9 @@
             doReturn(true).when(wpc).isPreviousProcess();
             doReturn(true).when(wpc).hasActivities();
         }
-        mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+        setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
         setProcessesToLru(apps);
-        mService.mOomAdjuster.updateOomAdjLocked(OOM_ADJ_REASON_NONE);
+        mProcessStateController.runFullUpdate(OOM_ADJ_REASON_NONE);
 
         for (int i = 0; i < numberOfApps; i++) {
             assertProcStates(apps[i], PROCESS_STATE_LAST_ACTIVITY, PREVIOUS_APP_ADJ,
@@ -914,7 +921,7 @@
             mInjector.jumpUptimeAheadTo(followUpTimeCaptor.getValue());
         }
 
-        mService.mOomAdjuster.updateOomAdjFollowUpTargetsLocked();
+        mProcessStateController.runFollowUpUpdate();
 
         for (int i = 0; i < numberOfApps; i++) {
             final int mruIndex = numberOfApps - i - 1;
@@ -938,10 +945,8 @@
     public void testUpdateOomAdj_DoOne_Backup() {
         ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
                 MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
-        BackupRecord backupTarget = new BackupRecord(null, 0, 0, 0);
-        backupTarget.app = app;
-        doReturn(backupTarget).when(mService.mBackupTargets).get(anyInt());
-        mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+        setBackupTarget(app);
+        setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
         updateOomAdj(app);
         doReturn(null).when(mService.mBackupTargets).get(anyInt());
 
@@ -954,8 +959,8 @@
     public void testUpdateOomAdj_DoOne_ClientActivities() {
         ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
                 MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
-        app.mServices.setHasClientActivities(true);
-        mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+        mProcessStateController.setHasClientActivities(app.mServices, true);
+        setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
         updateOomAdj(app);
 
         assertEquals(PROCESS_STATE_CACHED_ACTIVITY_CLIENT, app.mState.getSetProcState());
@@ -966,8 +971,8 @@
     public void testUpdateOomAdj_DoOne_TreatLikeActivity() {
         ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
                 MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
-        app.mServices.setTreatLikeActivity(true);
-        mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+        mProcessStateController.setTreatLikeActivity(app.mServices, true);
+        setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
         updateOomAdj(app);
 
         assertEquals(PROCESS_STATE_CACHED_ACTIVITY, app.mState.getSetProcState());
@@ -981,10 +986,10 @@
         app.mState.setServiceB(true);
         ServiceRecord s = mock(ServiceRecord.class);
         doReturn(new ArrayMap<IBinder, ArrayList<ConnectionRecord>>()).when(s).getConnections();
-        s.startRequested = true;
-        s.lastActivity = SystemClock.uptimeMillis();
-        app.mServices.startService(s);
-        mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+        mProcessStateController.setStartRequested(s, true);
+        mProcessStateController.setServiceLastActivityTime(s, SystemClock.uptimeMillis());
+        mProcessStateController.startService(app.mServices, s);
+        setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
         updateOomAdj(app);
 
         assertProcStates(app, PROCESS_STATE_SERVICE, SERVICE_B_ADJ, SCHED_GROUP_BACKGROUND);
@@ -995,8 +1000,8 @@
     public void testUpdateOomAdj_DoOne_MaxAdj() {
         ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
                 MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
-        app.mState.setMaxAdj(PERCEPTIBLE_LOW_APP_ADJ);
-        mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+        mProcessStateController.setMaxAdj(app, PERCEPTIBLE_LOW_APP_ADJ);
+        setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
         updateOomAdj(app);
 
         assertProcStates(app, PROCESS_STATE_CACHED_EMPTY, PERCEPTIBLE_LOW_APP_ADJ,
@@ -1011,7 +1016,7 @@
         app.mState.setCurRawAdj(SERVICE_ADJ);
         app.mState.setCurAdj(SERVICE_ADJ);
         doReturn(null).when(mService).getTopApp();
-        mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+        setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
         updateOomAdj(app);
 
         assertTrue(ProcessList.CACHED_APP_MIN_ADJ <= app.mState.getSetAdj());
@@ -1025,10 +1030,10 @@
                 MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
         ServiceRecord s = mock(ServiceRecord.class);
         doReturn(new ArrayMap<IBinder, ArrayList<ConnectionRecord>>()).when(s).getConnections();
-        s.startRequested = true;
-        s.lastActivity = SystemClock.uptimeMillis();
-        app.mServices.startService(s);
-        mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+        mProcessStateController.setStartRequested(s, true);
+        mProcessStateController.setServiceLastActivityTime(s, SystemClock.uptimeMillis());
+        mProcessStateController.startService(app.mServices, s);
+        setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
         updateOomAdj(app);
 
         assertProcStates(app, PROCESS_STATE_SERVICE, SERVICE_ADJ, SCHED_GROUP_BACKGROUND);
@@ -1043,8 +1048,8 @@
                 MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
         ServiceRecord s = bindService(app, client, null, null, Context.BIND_WAIVE_PRIORITY,
                 mock(IBinder.class));
-        s.startRequested = true;
-        mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+        mProcessStateController.setStartRequested(s, true);
+        setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
         doReturn(PROCESS_STATE_TOP).when(mService.mAtmInternal).getTopProcessState();
         doReturn(client).when(mService).getTopApp();
         updateOomAdj(client, app);
@@ -1062,10 +1067,10 @@
                 MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
         ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
                 MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
-        client.mServices.setTreatLikeActivity(true);
+        mProcessStateController.setTreatLikeActivity(client.mServices, true);
         bindService(app, client, null, null, Context.BIND_WAIVE_PRIORITY
                 | Context.BIND_TREAT_LIKE_ACTIVITY, mock(IBinder.class));
-        mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+        setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
         updateOomAdj(client, app);
 
         assertEquals(PROCESS_STATE_CACHED_ACTIVITY, app.mState.getSetProcState());
@@ -1086,7 +1091,7 @@
                 mock(ActivityServiceConnectionsHolder.class));
         doReturn(client).when(mService).getTopApp();
         doReturn(true).when(cr.activity).isActivityVisible();
-        mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+        setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
         updateOomAdj(client, app);
 
         assertEquals(FOREGROUND_APP_ADJ, app.mState.getSetAdj());
@@ -1099,7 +1104,7 @@
         ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
                 MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
         bindService(app, app, null, null, 0, mock(IBinder.class));
-        mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+        setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
         updateOomAdj(app);
 
         final int expectedAdj = mService.mConstants.USE_TIERED_CACHED_ADJ
@@ -1114,9 +1119,9 @@
                 MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
         ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
                 MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
-        client.mServices.setTreatLikeActivity(true);
+        mProcessStateController.setTreatLikeActivity(client.mServices, true);
         bindService(app, client, null, null, 0, mock(IBinder.class));
-        mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+        setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
         updateOomAdj(client, app);
 
         assertEquals(PROCESS_STATE_CACHED_EMPTY, app.mState.getSetProcState());
@@ -1137,7 +1142,7 @@
                 mock(IBinder.class));
         doReturn(PROCESS_STATE_TOP).when(mService.mAtmInternal).getTopProcessState();
         doReturn(client).when(mService).getTopApp();
-        mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+        setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
         updateOomAdj(client, app);
         doReturn(null).when(mService).getTopApp();
 
@@ -1152,9 +1157,9 @@
         ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
                 MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
         bindService(app, client, null, null, Context.BIND_FOREGROUND_SERVICE, mock(IBinder.class));
-        client.mState.setMaxAdj(PERSISTENT_PROC_ADJ);
-        client.mState.setHasTopUi(true);
-        mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+        mProcessStateController.setMaxAdj(client, PERSISTENT_PROC_ADJ);
+        mProcessStateController.setHasTopUi(client, true);
+        setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
         updateOomAdj(client, app);
 
         assertProcStates(app, PROCESS_STATE_BOUND_FOREGROUND_SERVICE, VISIBLE_APP_ADJ,
@@ -1170,8 +1175,8 @@
         ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
                 MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
         bindService(app, client, null, null, Context.BIND_IMPORTANT, mock(IBinder.class));
-        client.mServices.startExecutingService(mock(ServiceRecord.class));
-        mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+        mProcessStateController.startExecutingService(client.mServices, mock(ServiceRecord.class));
+        setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
         updateOomAdj(client, app);
 
         assertEquals(FOREGROUND_APP_ADJ, app.mState.getSetAdj());
@@ -1188,7 +1193,7 @@
         bindService(app, client, null, null, 0, mock(IBinder.class));
         doReturn(PROCESS_STATE_TOP).when(mService.mAtmInternal).getTopProcessState();
         doReturn(client).when(mService).getTopApp();
-        mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+        setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
         updateOomAdj(client, app);
         doReturn(null).when(mService).getTopApp();
 
@@ -1203,8 +1208,8 @@
         ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
                 MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
         bindService(app, client, null, null, Context.BIND_FOREGROUND_SERVICE, mock(IBinder.class));
-        client.mState.setMaxAdj(PERSISTENT_PROC_ADJ);
-        mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+        mProcessStateController.setMaxAdj(client, PERSISTENT_PROC_ADJ);
+        setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
         updateOomAdj(client, app);
 
         assertEquals(PROCESS_STATE_BOUND_FOREGROUND_SERVICE, app.mState.getSetProcState());
@@ -1222,9 +1227,9 @@
                 MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
         bindService(app, client, null, null, Context.BIND_FOREGROUND_SERVICE, mock(IBinder.class));
         client.mState.setMaxAdj(PERSISTENT_PROC_ADJ);
-        mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_ASLEEP);
+        setWakefulness(PowerManagerInternal.WAKEFULNESS_ASLEEP);
         updateOomAdj(client, app);
-        mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+        setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
 
         assertProcStates(app, PROCESS_STATE_BOUND_FOREGROUND_SERVICE, VISIBLE_APP_ADJ,
                 SCHED_GROUP_RESTRICTED);
@@ -1240,8 +1245,8 @@
         ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
                 MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
         bindService(app, client, null, null, Context.BIND_NOT_FOREGROUND, mock(IBinder.class));
-        client.mState.setMaxAdj(PERSISTENT_PROC_ADJ);
-        mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+        mProcessStateController.setMaxAdj(client, PERSISTENT_PROC_ADJ);
+        setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
         updateOomAdj(client, app);
 
         assertEquals(PROCESS_STATE_TRANSIENT_BACKGROUND, app.mState.getSetProcState());
@@ -1256,8 +1261,9 @@
         ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
                 MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
         bindService(app, client, null, null, 0, mock(IBinder.class));
-        client.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
-        mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+        mProcessStateController.setHasForegroundServices(client.mServices, true,
+                0, /* hasNoneType=*/true);
+        setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
         updateOomAdj(client, app);
 
         assertEquals(PROCESS_STATE_FOREGROUND_SERVICE, client.mState.getSetProcState());
@@ -1279,16 +1285,16 @@
         // In order to trick OomAdjuster to think it has a short-service, we need this logic.
         ServiceRecord s = ServiceRecord.newEmptyInstanceForTest(mService);
         s.appInfo = new ApplicationInfo();
-        s.startRequested = true;
-        s.isForeground = true;
-        s.foregroundServiceType = FOREGROUND_SERVICE_TYPE_SHORT_SERVICE;
-        s.setShortFgsInfo(SystemClock.uptimeMillis());
-        client.mServices.startService(s);
+        mProcessStateController.setStartRequested(s, true);
+        mProcessStateController.setIsForegroundService(s, true);
+        mProcessStateController.setForegroundServiceType(s, FOREGROUND_SERVICE_TYPE_SHORT_SERVICE);
+        mProcessStateController.setShortFgsInfo(s, SystemClock.uptimeMillis());
+        mProcessStateController.startService(client.mServices, s);
         client.mState.setLastTopTime(SystemClock.uptimeMillis());
 
-        client.mServices.setHasForegroundServices(true, FOREGROUND_SERVICE_TYPE_SHORT_SERVICE,
-                /* hasNoneType=*/false);
-        mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+        mProcessStateController.setHasForegroundServices(client.mServices, true,
+                FOREGROUND_SERVICE_TYPE_SHORT_SERVICE, /* hasNoneType=*/false);
+        setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
         updateOomAdj(client, app);
 
         // Client only has a SHORT_FGS, so it doesn't have BFSL, and that's propagated.
@@ -1310,16 +1316,16 @@
         // In order to trick OomAdjuster to think it has a short-service, we need this logic.
         ServiceRecord s = ServiceRecord.newEmptyInstanceForTest(mService);
         s.appInfo = new ApplicationInfo();
-        s.startRequested = true;
-        s.isForeground = true;
-        s.foregroundServiceType = FOREGROUND_SERVICE_TYPE_SHORT_SERVICE;
-        s.setShortFgsInfo(SystemClock.uptimeMillis());
-        app2.mServices.startService(s);
+        mProcessStateController.setStartRequested(s, true);
+        mProcessStateController.setIsForegroundService(s, true);
+        mProcessStateController.setForegroundServiceType(s, FOREGROUND_SERVICE_TYPE_SHORT_SERVICE);
+        mProcessStateController.setShortFgsInfo(s, SystemClock.uptimeMillis());
+        mProcessStateController.startService(app2.mServices, s);
         app2.mState.setLastTopTime(SystemClock.uptimeMillis());
 
-        app2.mServices.setHasForegroundServices(true, FOREGROUND_SERVICE_TYPE_SHORT_SERVICE,
-                /* hasNoneType=*/false);
-        mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+        mProcessStateController.setHasForegroundServices(app2.mServices, true,
+                FOREGROUND_SERVICE_TYPE_SHORT_SERVICE, /* hasNoneType=*/false);
+        setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
         updateOomAdj(app2);
 
         // Client only has a SHORT_FGS, so it doesn't have BFSL, and that's propagated.
@@ -1331,7 +1337,7 @@
         // Persistent process
         ProcessRecord pers = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
                 MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
-        pers.mState.setMaxAdj(PERSISTENT_PROC_ADJ);
+        mProcessStateController.setMaxAdj(pers, PERSISTENT_PROC_ADJ);
 
         // app1, which is bound by pers (which makes it BFGS)
         ProcessRecord app1 = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
@@ -1358,18 +1364,16 @@
         ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
                 MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
         bindService(app, client, null, null, Context.BIND_ABOVE_CLIENT, mock(IBinder.class));
-        BackupRecord backupTarget = new BackupRecord(null, 0, 0, 0);
-        backupTarget.app = client;
-        doReturn(backupTarget).when(mService.mBackupTargets).get(anyInt());
-        mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+        setBackupTarget(client);
+        setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
         updateOomAdj(client, app);
 
-        doReturn(null).when(mService.mBackupTargets).get(anyInt());
+        mProcessStateController.stopBackupTarget(UserHandle.getUserId(MOCKAPP2_UID));
 
         assertEquals(BACKUP_APP_ADJ, app.mState.getSetAdj());
         assertNoBfsl(app);
 
-        client.mState.setMaxAdj(PERSISTENT_PROC_ADJ);
+        mProcessStateController.setMaxAdj(client, PERSISTENT_PROC_ADJ);
         updateOomAdj(client, app);
 
         assertEquals(PERSISTENT_SERVICE_ADJ, app.mState.getSetAdj());
@@ -1384,8 +1388,8 @@
         ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
                 MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
         bindService(app, client, null, null, Context.BIND_NOT_PERCEPTIBLE, mock(IBinder.class));
-        client.mState.setRunningRemoteAnimation(true);
-        mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+        mProcessStateController.setRunningRemoteAnimation(client, true);
+        setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
         updateOomAdj(client, app);
 
         assertEquals(PERCEPTIBLE_LOW_APP_ADJ, app.mState.getSetAdj());
@@ -1399,8 +1403,8 @@
         ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
                 MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
         bindService(app, client, null, null, Context.BIND_NOT_VISIBLE, mock(IBinder.class));
-        client.mState.setRunningRemoteAnimation(true);
-        mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+        mProcessStateController.setRunningRemoteAnimation(client, true);
+        setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
         updateOomAdj(client, app);
 
         assertEquals(PERCEPTIBLE_APP_ADJ, app.mState.getSetAdj());
@@ -1414,8 +1418,8 @@
         ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
                 MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
         bindService(app, client, null, null, 0, mock(IBinder.class));
-        client.mState.setHasOverlayUi(true);
-        mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+        mProcessStateController.setHasOverlayUi(client, true);
+        setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
         updateOomAdj(client, app);
 
         assertEquals(PERCEPTIBLE_APP_ADJ, app.mState.getSetAdj());
@@ -1432,13 +1436,13 @@
             bindService(app, client, null, null,
                     Context.BIND_ALMOST_PERCEPTIBLE | Context.BIND_NOT_FOREGROUND,
                     mock(IBinder.class));
-            client.mState.setMaxAdj(PERSISTENT_PROC_ADJ);
-            mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+            mProcessStateController.setMaxAdj(client, PERSISTENT_PROC_ADJ);
+            setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
             updateOomAdj(client, app);
 
             assertEquals(PERCEPTIBLE_MEDIUM_APP_ADJ + 2, app.mState.getSetAdj());
 
-            mService.mOomAdjuster.resetInternal();
+            mProcessStateController.getOomAdjuster().resetInternal();
         }
 
         {
@@ -1451,14 +1455,14 @@
             bindService(app, client, null, null,
                     Context.BIND_ALMOST_PERCEPTIBLE | Context.BIND_NOT_FOREGROUND,
                     mock(IBinder.class));
-            client.mState.setMaxAdj(PERSISTENT_PROC_ADJ);
-            mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+            mProcessStateController.setMaxAdj(client, PERSISTENT_PROC_ADJ);
+            setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
             updateOomAdj(client, app);
             doReturn(false).when(wpc).isHeavyWeightProcess();
 
             assertEquals(PERCEPTIBLE_MEDIUM_APP_ADJ + 2, app.mState.getSetAdj());
 
-            mService.mOomAdjuster.resetInternal();
+            mProcessStateController.getOomAdjuster().resetInternal();
         }
 
         {
@@ -1469,13 +1473,13 @@
             bindService(app, client, null, null,
                     Context.BIND_ALMOST_PERCEPTIBLE,
                     mock(IBinder.class));
-            client.mState.setMaxAdj(PERSISTENT_PROC_ADJ);
-            mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+            mProcessStateController.setMaxAdj(client, PERSISTENT_PROC_ADJ);
+            setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
             updateOomAdj(client, app);
 
             assertEquals(PERCEPTIBLE_APP_ADJ + 1, app.mState.getSetAdj());
 
-            mService.mOomAdjuster.resetInternal();
+            mProcessStateController.getOomAdjuster().resetInternal();
         }
 
         {
@@ -1488,14 +1492,14 @@
             bindService(app, client, null, null,
                     Context.BIND_ALMOST_PERCEPTIBLE,
                     mock(IBinder.class));
-            client.mState.setMaxAdj(PERSISTENT_PROC_ADJ);
-            mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+            mProcessStateController.setMaxAdj(client, PERSISTENT_PROC_ADJ);
+            setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
             updateOomAdj(client, app);
             doReturn(false).when(wpc).isHeavyWeightProcess();
 
             assertEquals(PERCEPTIBLE_APP_ADJ + 1, app.mState.getSetAdj());
 
-            mService.mOomAdjuster.resetInternal();
+            mProcessStateController.getOomAdjuster().resetInternal();
         }
     }
 
@@ -1507,8 +1511,8 @@
         ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
                 MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
         bindService(app, client, null, null, 0, mock(IBinder.class));
-        client.mState.setRunningRemoteAnimation(true);
-        mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+        mProcessStateController.setRunningRemoteAnimation(client, true);
+        setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
         updateOomAdj(client, app);
 
         assertEquals(VISIBLE_APP_ADJ, app.mState.getSetAdj());
@@ -1523,8 +1527,8 @@
                 MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
         bindService(app, client, null, null, Context.BIND_IMPORTANT_BACKGROUND,
                 mock(IBinder.class));
-        client.mState.setHasOverlayUi(true);
-        mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+        mProcessStateController.setHasOverlayUi(client, true);
+        setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
         updateOomAdj(client, app);
 
         assertEquals(PROCESS_STATE_IMPORTANT_BACKGROUND, app.mState.getSetProcState());
@@ -1536,7 +1540,8 @@
     public void testUpdateOomAdj_DoOne_Provider_Self() {
         ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
                 MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
-        bindProvider(app, app, null, null, false);
+        final ContentProviderRecord cpr = createContentProviderRecord(app, null, false);
+        bindProvider(app, cpr);
         updateOomAdj(app);
 
         final int expectedAdj = mService.mConstants.USE_TIERED_CACHED_ADJ
@@ -1551,9 +1556,10 @@
                 MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
         ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
                 MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
-        bindProvider(app, client, null, null, false);
-        client.mServices.setTreatLikeActivity(true);
-        mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+        final ContentProviderRecord cpr = createContentProviderRecord(app, null, false);
+        bindProvider(client, cpr);
+        mProcessStateController.setTreatLikeActivity(client.mServices, true);
+        setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
         updateOomAdj(app, client);
 
         final int expectedAdj = mService.mConstants.USE_TIERED_CACHED_ADJ
@@ -1568,10 +1574,11 @@
                 MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
         ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
                 MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
-        bindProvider(app, client, null, null, false);
+        final ContentProviderRecord cpr = createContentProviderRecord(app, null, false);
+        bindProvider(client, cpr);
         doReturn(PROCESS_STATE_TOP).when(mService.mAtmInternal).getTopProcessState();
         doReturn(client).when(mService).getTopApp();
-        mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+        setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
         updateOomAdj(client, app);
         doReturn(null).when(mService).getTopApp();
 
@@ -1585,9 +1592,10 @@
                 MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
         ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
                 MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
-        client.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
-        bindProvider(app, client, null, null, false);
-        mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+        mProcessStateController.setHasForegroundServices(client.mServices, true, 0, true);
+        final ContentProviderRecord cpr = createContentProviderRecord(app, null, false);
+        bindProvider(client, cpr);
+        setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
         updateOomAdj(client, app);
 
         assertProcStates(app, PROCESS_STATE_BOUND_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
@@ -1607,17 +1615,18 @@
         // In order to trick OomAdjuster to think it has a short-service, we need this logic.
         ServiceRecord s = ServiceRecord.newEmptyInstanceForTest(mService);
         s.appInfo = new ApplicationInfo();
-        s.startRequested = true;
+        mProcessStateController.setStartRequested(s, true);
         s.isForeground = true;
         s.foregroundServiceType = FOREGROUND_SERVICE_TYPE_SHORT_SERVICE;
-        s.setShortFgsInfo(SystemClock.uptimeMillis());
-        client.mServices.startService(s);
+        mProcessStateController.setShortFgsInfo(s, SystemClock.uptimeMillis());
+        mProcessStateController.startService(client.mServices, s);
         client.mState.setLastTopTime(SystemClock.uptimeMillis());
 
-        client.mServices.setHasForegroundServices(true, FOREGROUND_SERVICE_TYPE_SHORT_SERVICE,
-                /* hasNoneType=*/false);
-        bindProvider(app, client, null, null, false);
-        mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+        mProcessStateController.setHasForegroundServices(client.mServices, true,
+                FOREGROUND_SERVICE_TYPE_SHORT_SERVICE, false);
+        final ContentProviderRecord cpr = createContentProviderRecord(app, null, false);
+        bindProvider(client, cpr);
+        setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
         updateOomAdj(client, app);
 
         // Client only has a SHORT_FGS, so it doesn't have BFSL, and that's propagated.
@@ -1638,8 +1647,9 @@
                 MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
         ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
                 MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
-        bindProvider(app, client, null, null, true);
-        mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+        final ContentProviderRecord cpr = createContentProviderRecord(app, null, true);
+        bindProvider(client, cpr);
+        setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
         updateOomAdj(client, app);
 
         assertProcStates(app, PROCESS_STATE_IMPORTANT_FOREGROUND, FOREGROUND_APP_ADJ,
@@ -1651,9 +1661,24 @@
     public void testUpdateOomAdj_DoOne_Provider_Retention() {
         ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
                 MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
-        app.mProviders.setLastProviderTime(SystemClock.uptimeMillis());
-        mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
-        updateOomAdj(app);
+        ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
+                MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
+        final String providerName = "aProvider";
+        // Go through the motions of binding a provider
+        final ContentProviderRecord cpr = createContentProviderRecord(app, providerName, false);
+        final ContentProviderConnection conn = bindProvider(client, cpr);
+        doReturn(PROCESS_STATE_TOP).when(mService.mAtmInternal).getTopProcessState();
+        doReturn(client).when(mService).getTopApp();
+        setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
+        updateOomAdj(client, app);
+
+        assertProcStates(app, PROCESS_STATE_BOUND_TOP, FOREGROUND_APP_ADJ, SCHED_GROUP_DEFAULT);
+
+        unbindProvider(client, cpr, conn);
+        mProcessStateController.removePublishedProvider(app, providerName);
+        final long lastProviderTime = SystemClock.uptimeMillis();
+        mProcessStateController.setLastProviderTime(app, SystemClock.uptimeMillis());
+        updateOomAdj(client, app);
 
         assertProcStates(app, PROCESS_STATE_LAST_ACTIVITY, PREVIOUS_APP_ADJ,
                 SCHED_GROUP_BACKGROUND, "recent-provider");
@@ -1663,8 +1688,10 @@
         final ArgumentCaptor<Long> followUpTimeCaptor = ArgumentCaptor.forClass(Long.class);
         verify(mService.mHandler).sendEmptyMessageAtTime(eq(FOLLOW_UP_OOMADJUSTER_UPDATE_MSG),
                 followUpTimeCaptor.capture());
+
         mInjector.jumpUptimeAheadTo(followUpTimeCaptor.getValue());
-        mService.mOomAdjuster.updateOomAdjFollowUpTargetsLocked();
+        setProcessesToLru(client, app);
+        mProcessStateController.runFollowUpUpdate();
 
         final int expectedAdj = mService.mConstants.USE_TIERED_CACHED_ADJ
                 ? sFirstNonUiCachedAdj : sFirstCachedAdj;
@@ -1688,7 +1715,7 @@
         bindService(client, client2, null, null, 0, mock(IBinder.class));
         doReturn(PROCESS_STATE_TOP).when(mService.mAtmInternal).getTopProcessState();
         doReturn(client2).when(mService).getTopApp();
-        mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+        setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
         updateOomAdj(client, client2, app);
         doReturn(null).when(mService).getTopApp();
 
@@ -1707,8 +1734,8 @@
         ProcessRecord client2 = spy(makeDefaultProcessRecord(MOCKAPP3_PID, MOCKAPP3_UID,
                 MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false));
         bindService(app, client2, null, null, 0, mock(IBinder.class));
-        client2.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
-        mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+        mProcessStateController.setHasForegroundServices(client2.mServices, true, 0, true);
+        setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
         updateOomAdj(client, client2, app);
 
         assertProcStates(app, PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
@@ -1727,8 +1754,8 @@
         ProcessRecord client2 = spy(makeDefaultProcessRecord(MOCKAPP3_PID, MOCKAPP3_UID,
                 MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false));
         bindService(client, client2, null, null, 0, mock(IBinder.class));
-        client2.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
-        mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+        mProcessStateController.setHasForegroundServices(client2.mServices, true, 0, true);
+        setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
         updateOomAdj(client, client2, app);
 
         assertProcStates(app, PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
@@ -1747,13 +1774,13 @@
         ProcessRecord client2 = spy(makeDefaultProcessRecord(MOCKAPP3_PID, MOCKAPP3_UID,
                 MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false));
         bindService(client, client2, null, null, 0, mock(IBinder.class));
-        client2.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
+        mProcessStateController.setHasForegroundServices(client2.mServices, true, 0, true);
         bindService(client2, app, null, null, 0, mock(IBinder.class));
 
         // Note: We add processes to LRU but still call updateOomAdjLocked() with a specific
         // processes.
         setProcessesToLru(app, client, client2);
-        mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+        setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
         updateOomAdj(app);
 
         assertProcStates(app, PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
@@ -1766,8 +1793,8 @@
         assertBfsl(client);
         assertBfsl(client2);
 
-        client2.mServices.setHasForegroundServices(false, 0, /* hasNoneType=*/false);
-        mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+        mProcessStateController.setHasForegroundServices(client2.mServices, false, 0, false);
+        setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
         updateOomAdj(client2);
 
         assertEquals(PROCESS_STATE_CACHED_EMPTY, client2.mState.getSetProcState());
@@ -1790,8 +1817,8 @@
         ProcessRecord client2 = spy(makeDefaultProcessRecord(MOCKAPP3_PID, MOCKAPP3_UID,
                 MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false));
         bindService(client2, client, null, null, 0, mock(IBinder.class));
-        client.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
-        mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+        mProcessStateController.setHasForegroundServices(client.mServices, true, 0, true);
+        setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
         updateOomAdj(app, client, client2);
 
         assertProcStates(app, PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
@@ -1817,8 +1844,8 @@
                 MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false));
         bindService(client, client2, null, null, 0, mock(IBinder.class));
         bindService(client2, client, null, null, 0, mock(IBinder.class));
-        client.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
-        mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+        mProcessStateController.setHasForegroundServices(client.mServices, true, 0, true);
+        setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
         updateOomAdj(app, client, client2);
 
         assertProcStates(app, PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
@@ -1851,8 +1878,8 @@
                 MOCKAPP5_PROCESSNAME, MOCKAPP5_PACKAGENAME, false));
         bindService(client3, client4, null, null, 0, mock(IBinder.class));
         bindService(client4, client3, null, null, 0, mock(IBinder.class));
-        client.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
-        mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+        mProcessStateController.setHasForegroundServices(client.mServices, true, 0, true);
+        setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
         updateOomAdj(app, client, client2, client3, client4);
 
         assertProcStates(app, PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
@@ -1883,13 +1910,13 @@
         ProcessRecord client2 = spy(makeDefaultProcessRecord(MOCKAPP3_PID, MOCKAPP3_UID,
                 MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false));
         bindService(client, client2, null, null, 0, mock(IBinder.class));
-        client2.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
+        mProcessStateController.setHasForegroundServices(client2.mServices, true, 0, true);
         bindService(client2, app, null, null, 0, mock(IBinder.class));
         ProcessRecord client3 = spy(makeDefaultProcessRecord(MOCKAPP4_PID, MOCKAPP4_UID,
                 MOCKAPP4_PROCESSNAME, MOCKAPP4_PACKAGENAME, false));
-        client3.mState.setForcingToImportant(new Object());
+        mProcessStateController.setForcingToImportant(client3, new Object());
         bindService(app, client3, null, null, 0, mock(IBinder.class));
-        mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+        setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
         updateOomAdj(app, client, client2, client3);
 
         assertProcStates(app, PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
@@ -1913,9 +1940,9 @@
         doReturn(true).when(wpc).isHomeProcess();
         ProcessRecord client3 = spy(makeDefaultProcessRecord(MOCKAPP4_PID, MOCKAPP4_UID,
                 MOCKAPP4_PROCESSNAME, MOCKAPP4_PACKAGENAME, false));
-        client3.mState.setForcingToImportant(new Object());
+        mProcessStateController.setForcingToImportant(client3, new Object());
         bindService(app, client3, null, null, 0, mock(IBinder.class));
-        mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+        setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
         updateOomAdj(app, client, client2, client3);
 
         assertProcStates(app, PROCESS_STATE_TRANSIENT_BACKGROUND, PERCEPTIBLE_APP_ADJ,
@@ -1940,9 +1967,9 @@
                 MOCKAPP4_PROCESSNAME, MOCKAPP4_PACKAGENAME, false));
         ProcessRecord client4 = spy(makeDefaultProcessRecord(MOCKAPP5_PID, MOCKAPP5_UID,
                 MOCKAPP5_PROCESSNAME, MOCKAPP5_PACKAGENAME, false));
-        client4.mState.setForcingToImportant(new Object());
+        mProcessStateController.setForcingToImportant(client4, new Object());
         bindService(app, client4, null, null, 0, mock(IBinder.class));
-        mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+        setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
         updateOomAdj(app, client, client2, client3, client4);
 
         assertProcStates(app, PROCESS_STATE_TRANSIENT_BACKGROUND, PERCEPTIBLE_APP_ADJ,
@@ -1965,13 +1992,13 @@
         doReturn(true).when(wpc).isHomeProcess();
         ProcessRecord client3 = spy(makeDefaultProcessRecord(MOCKAPP4_PID, MOCKAPP4_UID,
                 MOCKAPP4_PROCESSNAME, MOCKAPP4_PACKAGENAME, false));
-        client3.mState.setForcingToImportant(new Object());
+        mProcessStateController.setForcingToImportant(client3, new Object());
         bindService(app, client3, null, null, 0, mock(IBinder.class));
         ProcessRecord client4 = spy(makeDefaultProcessRecord(MOCKAPP5_PID, MOCKAPP5_UID,
                 MOCKAPP5_PROCESSNAME, MOCKAPP5_PACKAGENAME, false));
-        client4.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
+        mProcessStateController.setHasForegroundServices(client4.mServices, true, 0, true);
         bindService(app, client4, null, null, 0, mock(IBinder.class));
-        mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+        setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
         updateOomAdj(app, client, client2, client3, client4);
 
         assertProcStates(app, PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
@@ -1992,12 +2019,12 @@
         ProcessRecord client2 = spy(makeDefaultProcessRecord(MOCKAPP3_PID, MOCKAPP3_UID,
                 MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false));
         bindService(app, client2, null, null, 0, mock(IBinder.class));
-        client2.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
+        mProcessStateController.setHasForegroundServices(client2.mServices, true, 0, true);
         ProcessRecord client3 = spy(makeDefaultProcessRecord(MOCKAPP4_PID, MOCKAPP4_UID,
                 MOCKAPP4_PROCESSNAME, MOCKAPP4_PACKAGENAME, false));
-        client3.mState.setForcingToImportant(new Object());
+        mProcessStateController.setForcingToImportant(client3, new Object());
         bindService(app, client3, null, null, 0, mock(IBinder.class));
-        mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+        setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
         updateOomAdj(client, client2, client3, app);
 
         assertProcStates(app, PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
@@ -2015,9 +2042,10 @@
         bindService(app, client, null, null, 0, mock(IBinder.class));
         ProcessRecord client2 = spy(makeDefaultProcessRecord(MOCKAPP3_PID, MOCKAPP3_UID,
                 MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false));
-        bindProvider(client, client2, null, null, false);
-        client2.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
-        mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+        final ContentProviderRecord cpr = createContentProviderRecord(client, null, false);
+        bindProvider(client2, cpr);
+        mProcessStateController.setHasForegroundServices(client2.mServices, true, 0, true);
+        setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
         updateOomAdj(client, client2, app);
 
         assertProcStates(app, PROCESS_STATE_BOUND_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
@@ -2035,10 +2063,11 @@
         bindService(app, client, null, null, 0, mock(IBinder.class));
         ProcessRecord client2 = spy(makeDefaultProcessRecord(MOCKAPP3_PID, MOCKAPP3_UID,
                 MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false));
-        bindProvider(client, client2, null, null, false);
-        client2.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
+        final ContentProviderRecord cpr = createContentProviderRecord(client, null, false);
+        bindProvider(client2, cpr);
+        mProcessStateController.setHasForegroundServices(client2.mServices, true, 0, true);
         bindService(client2, app, null, null, 0, mock(IBinder.class));
-        mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+        setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
         updateOomAdj(app, client, client2);
 
         assertProcStates(app, PROCESS_STATE_BOUND_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
@@ -2053,12 +2082,14 @@
                 MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
         ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
                 MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
-        bindProvider(app, client, null, null, false);
+        final ContentProviderRecord cpr = createContentProviderRecord(app, null, false);
+        bindProvider(client, cpr);
         ProcessRecord client2 = spy(makeDefaultProcessRecord(MOCKAPP3_PID, MOCKAPP3_UID,
                 MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false));
-        bindProvider(client, client2, null, null, false);
-        client2.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
-        mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+        final ContentProviderRecord cpr2 = createContentProviderRecord(client, null, false);
+        bindProvider(client2, cpr2);
+        mProcessStateController.setHasForegroundServices(client2.mServices, true, 0, true);
+        setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
         updateOomAdj(client, client2, app);
 
         assertProcStates(app, PROCESS_STATE_BOUND_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
@@ -2073,13 +2104,16 @@
                 MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
         ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
                 MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
-        bindProvider(app, client, null, null, false);
+        final ContentProviderRecord cpr = createContentProviderRecord(app, null, false);
+        bindProvider(client, cpr);
         ProcessRecord client2 = spy(makeDefaultProcessRecord(MOCKAPP3_PID, MOCKAPP3_UID,
                 MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false));
-        bindProvider(client, client2, null, null, false);
-        client2.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
-        bindProvider(client2, app, null, null, false);
-        mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+        final ContentProviderRecord cpr2 = createContentProviderRecord(client, null, false);
+        bindProvider(client2, cpr2);
+        mProcessStateController.setHasForegroundServices(client2.mServices, true, 0, true);
+        final ContentProviderRecord cpr3 = createContentProviderRecord(client2, null, false);
+        bindProvider(app, cpr3);
+        setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
         updateOomAdj(app, client, client2);
 
         assertProcStates(app, PROCESS_STATE_BOUND_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
@@ -2102,10 +2136,10 @@
                 mock(IBinder.class));
         bindService(app2, client2, null, null, Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE,
                 mock(IBinder.class));
-        client1.mState.setMaxAdj(PERSISTENT_PROC_ADJ);
-        client2.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
+        mProcessStateController.setMaxAdj(client1, PERSISTENT_PROC_ADJ);
+        mProcessStateController.setHasForegroundServices(client2.mServices, true, 0, true);
 
-        mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+        setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
         updateOomAdj(client1, client2, app1, app2);
 
         assertProcStates(app1, PROCESS_STATE_BOUND_FOREGROUND_SERVICE, VISIBLE_APP_ADJ,
@@ -2126,7 +2160,7 @@
         assertProcStates(app2, PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
                 SCHED_GROUP_DEFAULT);
 
-        mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_ASLEEP);
+        setWakefulness(PowerManagerInternal.WAKEFULNESS_ASLEEP);
         updateOomAdj(client1, client2, app1, app2);
         assertProcStates(app1, PROCESS_STATE_IMPORTANT_FOREGROUND, VISIBLE_APP_ADJ,
                 SCHED_GROUP_TOP_APP);
@@ -2136,7 +2170,7 @@
 
         bindService(client2, app1, null, null, 0, mock(IBinder.class));
         bindService(app1, client2, null, null, 0, mock(IBinder.class));
-        client2.mServices.setHasForegroundServices(false, 0, /* hasNoneType=*/false);
+        mProcessStateController.setHasForegroundServices(client2.mServices, false, 0, false);
         updateOomAdj(app1, client1, client2);
         assertProcStates(app1, PROCESS_STATE_IMPORTANT_FOREGROUND, VISIBLE_APP_ADJ,
                 SCHED_GROUP_TOP_APP);
@@ -2153,8 +2187,8 @@
                 MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false));
         final ProcessRecord client2 = spy(makeDefaultProcessRecord(MOCKAPP4_PID, MOCKAPP4_UID,
                 MOCKAPP4_PROCESSNAME, MOCKAPP4_PACKAGENAME, false));
-        client1.mState.setMaxAdj(PERSISTENT_PROC_ADJ);
-        client2.mState.setMaxAdj(PERSISTENT_PROC_ADJ);
+        mProcessStateController.setMaxAdj(client1, PERSISTENT_PROC_ADJ);
+        mProcessStateController.setMaxAdj(client2, PERSISTENT_PROC_ADJ);
 
         final ServiceRecord s1 = bindService(app1, client1, null, null,
                 Context.BIND_TREAT_LIKE_VISIBLE_FOREGROUND_SERVICE, mock(IBinder.class));
@@ -2178,10 +2212,10 @@
         s2.getConnections().clear();
         client1.mServices.removeAllConnections();
         client2.mServices.removeAllConnections();
-        client1.mState.setMaxAdj(UNKNOWN_ADJ);
-        client2.mState.setMaxAdj(UNKNOWN_ADJ);
-        client1.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
-        client2.mState.setHasOverlayUi(true);
+        mProcessStateController.setMaxAdj(client1, UNKNOWN_ADJ);
+        mProcessStateController.setMaxAdj(client2, UNKNOWN_ADJ);
+        mProcessStateController.setHasForegroundServices(client1.mServices, true, 0, true);
+        mProcessStateController.setHasOverlayUi(client2, true);
 
         bindService(app1, client1, null, s1, Context.BIND_TREAT_LIKE_VISIBLE_FOREGROUND_SERVICE,
                 mock(IBinder.class));
@@ -2196,10 +2230,10 @@
         assertProcStates(app2, PROCESS_STATE_IMPORTANT_FOREGROUND, PERCEPTIBLE_APP_ADJ,
                 SCHED_GROUP_DEFAULT);
 
-        client2.mState.setHasOverlayUi(false);
+        mProcessStateController.setHasOverlayUi(client2, false);
         doReturn(PROCESS_STATE_TOP).when(mService.mAtmInternal).getTopProcessState();
         doReturn(client2).when(mService).getTopApp();
-        mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+        setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
 
         updateOomAdj(client2, app2);
         assertProcStates(app2, PROCESS_STATE_BOUND_TOP, VISIBLE_APP_ADJ,
@@ -2213,10 +2247,10 @@
                 MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
         final ProcessRecord client1 = spy(makeDefaultProcessRecord(MOCKAPP3_PID, MOCKAPP3_UID,
                 MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false));
-        client1.mState.setMaxAdj(PERSISTENT_PROC_ADJ);
+        mProcessStateController.setMaxAdj(client1, PERSISTENT_PROC_ADJ);
 
-        app1.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
-        mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+        mProcessStateController.setHasForegroundServices(app1.mServices, true, 0, true);
+        setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
 
         bindService(app1, client1, null, null, Context.BIND_NOT_PERCEPTIBLE, mock(IBinder.class));
 
@@ -2234,10 +2268,10 @@
                 MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
         final ProcessRecord client1 = spy(makeDefaultProcessRecord(MOCKAPP3_PID, MOCKAPP3_UID,
                 MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false));
-        client1.mState.setMaxAdj(PERSISTENT_PROC_ADJ);
+        mProcessStateController.setMaxAdj(client1, PERSISTENT_PROC_ADJ);
 
-        app1.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
-        mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+        mProcessStateController.setHasForegroundServices(app1.mServices, true, 0, true);
+        setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
 
         bindService(app1, client1, null, null, Context.BIND_ALMOST_PERCEPTIBLE,
                 mock(IBinder.class));
@@ -2254,10 +2288,10 @@
     public void testUpdateOomAdj_DoOne_PendingFinishAttach() {
         ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
                 MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
-        app.setPendingFinishAttach(true);
+        mProcessStateController.setPendingFinishAttach(app, true);
         app.mState.setHasForegroundActivities(false);
 
-        mService.mOomAdjuster.setAttachingProcessStatesLSP(app);
+        mProcessStateController.setAttachingProcessStatesLSP(app);
         updateOomAdj(app);
 
         assertProcStates(app, PROCESS_STATE_CACHED_EMPTY, FOREGROUND_APP_ADJ,
@@ -2269,11 +2303,11 @@
     public void testUpdateOomAdj_DoOne_TopApp_PendingFinishAttach() {
         ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
                 MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
-        app.setPendingFinishAttach(true);
+        mProcessStateController.setPendingFinishAttach(app, true);
         app.mState.setHasForegroundActivities(true);
         doReturn(app).when(mService).getTopApp();
 
-        mService.mOomAdjuster.setAttachingProcessStatesLSP(app);
+        mProcessStateController.setAttachingProcessStatesLSP(app);
         updateOomAdj(app);
 
         assertProcStates(app, PROCESS_STATE_TOP, FOREGROUND_APP_ADJ,
@@ -2303,40 +2337,40 @@
         client1.setUidRecord(clientUidRecord);
         client2.setUidRecord(clientUidRecord);
 
-        client1.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
-        client2.mState.setForcingToImportant(new Object());
+        mProcessStateController.setHasForegroundServices(client1.mServices, true, 0, true);
+        mProcessStateController.setForcingToImportant(client2, new Object());
         setProcessesToLru(app1, app2, app3, client1, client2);
-        mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+        setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
 
         final ComponentName cn1 = ComponentName.unflattenFromString(
                 MOCKAPP_PACKAGENAME + "/.TestService");
         final ServiceRecord s1 = bindService(app1, client1, null, null, 0, mock(IBinder.class));
         setFieldValue(ServiceRecord.class, s1, "name", cn1);
-        s1.startRequested = true;
+        mProcessStateController.setStartRequested(s1, true);
 
         final ComponentName cn2 = ComponentName.unflattenFromString(
                 MOCKAPP2_PACKAGENAME + "/.TestService");
         final ServiceRecord s2 = bindService(app2, client2, null, null, 0, mock(IBinder.class));
         setFieldValue(ServiceRecord.class, s2, "name", cn2);
-        s2.startRequested = true;
+        mProcessStateController.setStartRequested(s2, true);
 
         final ComponentName cn3 = ComponentName.unflattenFromString(
                 MOCKAPP5_PACKAGENAME + "/.TestService");
         final ServiceRecord s3 = bindService(app3, client1, null, null, 0, mock(IBinder.class));
         setFieldValue(ServiceRecord.class, s3, "name", cn3);
-        s3.startRequested = true;
+        mProcessStateController.setStartRequested(s3, true);
 
         final ComponentName cn4 = ComponentName.unflattenFromString(
                 MOCKAPP3_PACKAGENAME + "/.TestService");
         final ServiceRecord c2s = makeServiceRecord(client2);
         setFieldValue(ServiceRecord.class, c2s, "name", cn4);
-        c2s.startRequested = true;
+        mProcessStateController.setStartRequested(c2s, true);
 
         try {
-            mService.mOomAdjuster.mActiveUids.put(MOCKAPP_UID, app1UidRecord);
-            mService.mOomAdjuster.mActiveUids.put(MOCKAPP2_UID, app2UidRecord);
-            mService.mOomAdjuster.mActiveUids.put(MOCKAPP5_UID, app3UidRecord);
-            mService.mOomAdjuster.mActiveUids.put(MOCKAPP3_UID, clientUidRecord);
+            mActiveUids.put(MOCKAPP_UID, app1UidRecord);
+            mActiveUids.put(MOCKAPP2_UID, app2UidRecord);
+            mActiveUids.put(MOCKAPP5_UID, app3UidRecord);
+            mActiveUids.put(MOCKAPP3_UID, clientUidRecord);
 
             setServiceMap(s1, MOCKAPP_UID, cn1);
             setServiceMap(s2, MOCKAPP2_UID, cn2);
@@ -2354,8 +2388,8 @@
             assertEquals(PROCESS_STATE_TRANSIENT_BACKGROUND, app2.mState.getSetProcState());
             assertEquals(PROCESS_STATE_TRANSIENT_BACKGROUND, client2.mState.getSetProcState());
 
-            client1.mServices.setHasForegroundServices(false, 0, /* hasNoneType=*/false);
-            client2.mState.setForcingToImportant(null);
+            mProcessStateController.setHasForegroundServices(client1.mServices, false, 0, false);
+            mProcessStateController.setForcingToImportant(client2, null);
             app1UidRecord.reset();
             app2UidRecord.reset();
             app3UidRecord.reset();
@@ -2379,7 +2413,7 @@
                     .getAppStartModeLOSP(anyInt(), any(String.class), anyInt(),
                             anyInt(), anyBoolean(), anyBoolean(), anyBoolean());
             mService.mServices.mServiceMap.clear();
-            mService.mOomAdjuster.mActiveUids.clear();
+            mActiveUids.clear();
         }
     }
 
@@ -2388,12 +2422,13 @@
     public void testUpdateOomAdj_DoAll_Unbound() {
         ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
                 MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
-        app.mState.setForcingToImportant(new Object());
         ProcessRecord app2 = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
                 MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
-        app2.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
 
-        mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+        mProcessStateController.setForcingToImportant(app, new Object());
+        mProcessStateController.setHasForegroundServices(app2.mServices, true, 0, /* hasNoneType=*/
+                true);
+        setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
         updateOomAdj(app, app2);
 
         assertProcStates(app, PROCESS_STATE_TRANSIENT_BACKGROUND, PERCEPTIBLE_APP_ADJ,
@@ -2408,12 +2443,14 @@
     public void testUpdateOomAdj_DoAll_BoundFgService() {
         ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
                 MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
-        app.mState.setForcingToImportant(new Object());
         ProcessRecord app2 = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
                 MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
-        app2.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
+
+        mProcessStateController.setForcingToImportant(app, new Object());
+        mProcessStateController.setHasForegroundServices(app2.mServices, true, 0, /* hasNoneType=*/
+                true);
         bindService(app, app2, null, null, 0, mock(IBinder.class));
-        mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+        setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
         updateOomAdj(app, app2);
 
         assertProcStates(app, PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
@@ -2435,9 +2472,9 @@
         ProcessRecord app3 = spy(makeDefaultProcessRecord(MOCKAPP3_PID, MOCKAPP3_UID,
                 MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false));
         bindService(app2, app3, null, null, 0, mock(IBinder.class));
-        app3.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
+        mProcessStateController.setHasForegroundServices(app3.mServices, true, 0, true);
         bindService(app3, app, null, null, 0, mock(IBinder.class));
-        mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+        setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
         updateOomAdj(app, app2, app3);
 
         assertProcStates(app, PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
@@ -2476,13 +2513,13 @@
         doReturn(true).when(wpc).isHomeProcess();
         ProcessRecord app4 = spy(makeDefaultProcessRecord(MOCKAPP4_PID, MOCKAPP4_UID,
                 MOCKAPP4_PROCESSNAME, MOCKAPP4_PACKAGENAME, false));
-        app4.mState.setHasOverlayUi(true);
+        mProcessStateController.setHasOverlayUi(app4, true);
         bindService(app, app4, null, s, 0, mock(IBinder.class));
         ProcessRecord app5 = spy(makeDefaultProcessRecord(MOCKAPP5_PID, MOCKAPP5_UID,
                 MOCKAPP5_PROCESSNAME, MOCKAPP5_PACKAGENAME, false));
-        app5.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
+        mProcessStateController.setHasForegroundServices(app5.mServices, true, 0, true);
         bindService(app, app5, null, s, 0, mock(IBinder.class));
-        mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+        setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
         updateOomAdj(app, app2, app3, app4, app5);
 
         assertProcStates(app, PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
@@ -2518,13 +2555,13 @@
         doReturn(true).when(wpc).isHomeProcess();
         ProcessRecord app4 = spy(makeDefaultProcessRecord(MOCKAPP4_PID, MOCKAPP4_UID,
                 MOCKAPP4_PROCESSNAME, MOCKAPP4_PACKAGENAME, false));
-        app4.mState.setHasOverlayUi(true);
+        mProcessStateController.setHasOverlayUi(app4, true);
         bindService(app, app4, null, s, 0, mock(IBinder.class));
         ProcessRecord app5 = spy(makeDefaultProcessRecord(MOCKAPP5_PID, MOCKAPP5_UID,
                 MOCKAPP5_PROCESSNAME, MOCKAPP5_PACKAGENAME, false));
-        app5.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
+        mProcessStateController.setHasForegroundServices(app5.mServices, true, 0, true);
         bindService(app, app5, null, s, 0, mock(IBinder.class));
-        mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+        setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
         updateOomAdj(app5, app4, app3, app2, app);
 
         assertProcStates(app, PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
@@ -2560,13 +2597,13 @@
         doReturn(true).when(wpc).isHomeProcess();
         ProcessRecord app4 = spy(makeDefaultProcessRecord(MOCKAPP4_PID, MOCKAPP4_UID,
                 MOCKAPP4_PROCESSNAME, MOCKAPP4_PACKAGENAME, false));
-        app4.mState.setHasOverlayUi(true);
+        mProcessStateController.setHasOverlayUi(app4, true);
         bindService(app, app4, null, s, 0, mock(IBinder.class));
         ProcessRecord app5 = spy(makeDefaultProcessRecord(MOCKAPP5_PID, MOCKAPP5_UID,
                 MOCKAPP5_PROCESSNAME, MOCKAPP5_PACKAGENAME, false));
-        app5.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
+        mProcessStateController.setHasForegroundServices(app5.mServices, true, 0, true);
         bindService(app, app5, null, s, 0, mock(IBinder.class));
-        mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+        setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
         updateOomAdj(app3, app4, app2, app, app5);
 
         assertProcStates(app, PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
@@ -2603,10 +2640,10 @@
                 mock(IBinder.class));
         ProcessRecord client3 = spy(makeDefaultProcessRecord(MOCKAPP4_PID, MOCKAPP4_UID,
                 MOCKAPP4_PROCESSNAME, MOCKAPP4_PACKAGENAME, false));
-        client3.mState.setMaxAdj(PERSISTENT_PROC_ADJ);
+        mProcessStateController.setMaxAdj(client3, PERSISTENT_PROC_ADJ);
         bindService(app, client3, null, null, Context.BIND_INCLUDE_CAPABILITIES,
                 mock(IBinder.class));
-        mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+        setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
         updateOomAdj(app, client, client2, client3);
 
         final int expected = PROCESS_CAPABILITY_ALL & ~PROCESS_CAPABILITY_BFSL;
@@ -2622,22 +2659,25 @@
                 MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
         ProcessRecord app2 = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
                 MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
-        ContentProviderRecord cr = bindProvider(app, app2, null, null, false);
+        final ContentProviderRecord cpr = createContentProviderRecord(app, null, false);
+        bindProvider(app2, cpr);
         ProcessRecord app3 = spy(makeDefaultProcessRecord(MOCKAPP3_PID, MOCKAPP3_UID,
                 MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false));
-        bindProvider(app2, app3, null, null, false);
-        bindProvider(app3, app, null, null, false);
+        final ContentProviderRecord cpr2 = createContentProviderRecord(app2, null, false);
+        bindProvider(app3, cpr2);
+        final ContentProviderRecord cpr3 = createContentProviderRecord(app3, null, false);
+        bindProvider(app, cpr3);
         WindowProcessController wpc = app3.getWindowProcessController();
         doReturn(true).when(wpc).isHomeProcess();
         ProcessRecord app4 = spy(makeDefaultProcessRecord(MOCKAPP4_PID, MOCKAPP4_UID,
                 MOCKAPP4_PROCESSNAME, MOCKAPP4_PACKAGENAME, false));
-        app4.mState.setHasOverlayUi(true);
-        bindProvider(app, app4, cr, null, false);
+        mProcessStateController.setHasOverlayUi(app4, true);
+        bindProvider(app4, cpr);
         ProcessRecord app5 = spy(makeDefaultProcessRecord(MOCKAPP5_PID, MOCKAPP5_UID,
                 MOCKAPP5_PROCESSNAME, MOCKAPP5_PACKAGENAME, false));
-        app5.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
-        bindProvider(app, app5, cr, null, false);
-        mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+        mProcessStateController.setHasForegroundServices(app5.mServices, true, 0, true);
+        bindProvider(app5, cpr);
+        setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
         updateOomAdj(app, app2, app3, app4, app5);
 
         assertProcStates(app, PROCESS_STATE_BOUND_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
@@ -2666,22 +2706,22 @@
                 MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
         long now = SystemClock.uptimeMillis();
         ServiceRecord s = bindService(app, app2, null, null, 0, mock(IBinder.class));
-        s.startRequested = true;
-        s.lastActivity = now;
+        mProcessStateController.setStartRequested(s, true);
+        mProcessStateController.setServiceLastActivityTime(s, now);
         s = bindService(app2, app, null, null, 0, mock(IBinder.class));
-        s.startRequested = true;
-        s.lastActivity = now;
+        mProcessStateController.setStartRequested(s, true);
+        mProcessStateController.setServiceLastActivityTime(s, now);
         ProcessRecord app3 = spy(makeDefaultProcessRecord(MOCKAPP3_PID, MOCKAPP3_UID,
                 MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false));
         s = mock(ServiceRecord.class);
-        s.app = app3;
+        mProcessStateController.setHostProcess(s, app3);
         setFieldValue(ServiceRecord.class, s, "connections",
                 new ArrayMap<IBinder, ArrayList<ConnectionRecord>>());
-        app3.mServices.startService(s);
+        mProcessStateController.startService(app3.mServices, s);
         doCallRealMethod().when(s).getConnections();
-        s.startRequested = true;
-        s.lastActivity = now;
-        mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+        mProcessStateController.setStartRequested(s, true);
+        mProcessStateController.setServiceLastActivityTime(s, now);
+        setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
         mService.mOomAdjuster.mNumServiceProcs = 3;
         updateOomAdj(app3, app2, app);
 
@@ -2702,8 +2742,8 @@
 
         // cachedAdj1 and cachedAdj2 will be read if USE_TIERED_CACHED_ADJ is disabled. Otherwise,
         // sFirstUiCachedAdj and sFirstNonUiCachedAdj are used instead.
-        final int cachedAdj1 = CACHED_APP_MIN_ADJ + ProcessList.CACHED_APP_IMPORTANCE_LEVELS;
-        final int cachedAdj2 = cachedAdj1 + ProcessList.CACHED_APP_IMPORTANCE_LEVELS * 2;
+        final int cachedAdj1 = CACHED_APP_MIN_ADJ + CACHED_APP_IMPORTANCE_LEVELS;
+        final int cachedAdj2 = cachedAdj1 + CACHED_APP_IMPORTANCE_LEVELS * 2;
         doReturn(userOwner).when(mService.mUserController).getCurrentUserId();
 
         final ArrayList<ProcessRecord> lru = mService.mProcessList.getLruProcessesLOSP();
@@ -2723,11 +2763,11 @@
         ServiceRecord s = spy(new ServiceRecord(mService, cn, cn, null, 0, null,
                 si, false, null));
         doReturn(new ArrayMap<IBinder, ArrayList<ConnectionRecord>>()).when(s).getConnections();
-        s.startRequested = true;
-        s.lastActivity = now;
+        mProcessStateController.setStartRequested(s, true);
+        mProcessStateController.setServiceLastActivityTime(s, now);
 
-        app.mServices.startService(s);
-        app.mState.setHasShownUi(true);
+        mProcessStateController.startService(app.mServices, s);
+        mProcessStateController.setHasShownUi(app, true);
 
         final ServiceInfo si2 = mock(ServiceInfo.class);
         si2.applicationInfo = mock(ApplicationInfo.class);
@@ -2735,13 +2775,14 @@
         ServiceRecord s2 = spy(new ServiceRecord(mService, cn2, cn2, null, 0, null,
                 si2, false, null));
         doReturn(new ArrayMap<IBinder, ArrayList<ConnectionRecord>>()).when(s2).getConnections();
-        s2.startRequested = true;
-        s2.lastActivity = now - mService.mConstants.MAX_SERVICE_INACTIVITY - 1;
+        mProcessStateController.setStartRequested(s2, true);
+        mProcessStateController.setServiceLastActivityTime(s2,
+                now - mService.mConstants.MAX_SERVICE_INACTIVITY - 1);
 
-        app2.mServices.startService(s2);
-        app2.mState.setHasShownUi(false);
+        mProcessStateController.startService(app2.mServices, s2);
+        mProcessStateController.setHasShownUi(app2, false);
 
-        mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+        setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
         updateOomAdj();
 
         assertProcStates(app, PROCESS_STATE_SERVICE,
@@ -2754,7 +2795,7 @@
         app.mState.setSetProcState(PROCESS_STATE_NONEXISTENT);
         app.mState.setAdjType(null);
         app.mState.setSetAdj(UNKNOWN_ADJ);
-        app.mState.setHasShownUi(false);
+        mProcessStateController.setHasShownUi(app, false);
         updateOomAdj();
 
         assertProcStates(app, PROCESS_STATE_SERVICE, SERVICE_ADJ, SCHED_GROUP_BACKGROUND,
@@ -2763,27 +2804,28 @@
         app.mState.setSetProcState(PROCESS_STATE_NONEXISTENT);
         app.mState.setAdjType(null);
         app.mState.setSetAdj(UNKNOWN_ADJ);
-        s.lastActivity = now - mService.mConstants.MAX_SERVICE_INACTIVITY - 1;
+        mProcessStateController.setServiceLastActivityTime(s,
+                now - mService.mConstants.MAX_SERVICE_INACTIVITY - 1);
         updateOomAdj();
 
         assertProcStates(app, PROCESS_STATE_SERVICE,
                 mService.mConstants.USE_TIERED_CACHED_ADJ ? sFirstNonUiCachedAdj : cachedAdj1,
                 SCHED_GROUP_BACKGROUND, "cch-started-services", true);
 
-        app.mServices.stopService(s);
+        mProcessStateController.stopService(app.mServices, s);
         app.mState.setSetProcState(PROCESS_STATE_NONEXISTENT);
         app.mState.setAdjType(null);
         app.mState.setSetAdj(UNKNOWN_ADJ);
-        app.mState.setHasShownUi(true);
+        mProcessStateController.setHasShownUi(app, true);
         mService.mConstants.KEEP_WARMING_SERVICES.add(cn);
         mService.mConstants.KEEP_WARMING_SERVICES.add(cn2);
         s = spy(new ServiceRecord(mService, cn, cn, null, 0, null,
                 si, false, null));
         doReturn(new ArrayMap<IBinder, ArrayList<ConnectionRecord>>()).when(s).getConnections();
-        s.startRequested = true;
-        s.lastActivity = now;
+        mProcessStateController.setStartRequested(s, true);
+        mProcessStateController.setServiceLastActivityTime(s, now);
 
-        app.mServices.startService(s);
+        mProcessStateController.startService(app.mServices, s);
         updateOomAdj();
 
         assertProcStates(app, PROCESS_STATE_SERVICE, SERVICE_ADJ, SCHED_GROUP_BACKGROUND,
@@ -2795,8 +2837,9 @@
         app.mState.setSetProcState(PROCESS_STATE_NONEXISTENT);
         app.mState.setAdjType(null);
         app.mState.setSetAdj(UNKNOWN_ADJ);
-        app.mState.setHasShownUi(false);
-        s.lastActivity = now - mService.mConstants.MAX_SERVICE_INACTIVITY - 1;
+        mProcessStateController.setHasShownUi(app, false);
+        mProcessStateController.setServiceLastActivityTime(s,
+                now - mService.mConstants.MAX_SERVICE_INACTIVITY - 1);
         updateOomAdj();
 
         assertProcStates(app, PROCESS_STATE_SERVICE, SERVICE_ADJ, SCHED_GROUP_BACKGROUND,
@@ -2825,7 +2868,7 @@
                 MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, true));
         doReturn(PROCESS_STATE_TOP).when(mService.mAtmInternal).getTopProcessState();
         doReturn(app).when(mService).getTopApp();
-        mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+        setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
         updateOomAdj(app);
 
         assertEquals(FOREGROUND_APP_ADJ, app.mState.getSetAdj());
@@ -2847,7 +2890,7 @@
                 MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
         doReturn(PROCESS_STATE_TOP).when(mService.mAtmInternal).getTopProcessState();
         doReturn(app).when(mService).getTopApp();
-        mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+        setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
         updateOomAdj(app);
 
         assertEquals(FOREGROUND_APP_ADJ, app.mState.getSetAdj());
@@ -2873,14 +2916,14 @@
                 MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false));
         long now = SystemClock.uptimeMillis();
         ServiceRecord s = bindService(app, app2, null, null, 0, mock(IBinder.class));
-        s.startRequested = true;
-        s.lastActivity = now;
+        mProcessStateController.setStartRequested(s, true);
+        mProcessStateController.setServiceLastActivityTime(s, now);
         s = bindService(app2, app3, null, null, 0, mock(IBinder.class));
-        s.lastActivity = now;
+        mProcessStateController.setServiceLastActivityTime(s, now);
         s = bindService(app3, app2, null, null, 0, mock(IBinder.class));
-        s.lastActivity = now;
+        mProcessStateController.setServiceLastActivityTime(s, now);
 
-        mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+        setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
         mService.mOomAdjuster.mNumServiceProcs = 3;
         updateOomAdj(app, app2, app3);
 
@@ -2898,14 +2941,14 @@
                 MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
         doReturn(PROCESS_STATE_TOP).when(mService.mAtmInternal).getTopProcessState();
         doReturn(app).when(mService).getTopApp();
-        mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+        setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
         updateOomAdj(app);
 
         assertEquals(FOREGROUND_APP_ADJ, app.mState.getSetAdj());
 
         // Start binding to a service that isn't running yet.
         ServiceRecord sr = makeServiceRecord(app);
-        sr.app = null;
+        mProcessStateController.setHostProcess(sr, null);
         bindService(null, app, null, sr, Context.BIND_ABOVE_CLIENT, mock(IBinder.class));
 
         // Since sr.app is null, this service cannot be in the same process as the
@@ -2924,13 +2967,13 @@
 
         setProcessesToLru(app);
         ServiceRecord s = makeServiceRecord(app);
-        s.startRequested = true;
-        s.lastActivity = SystemClock.uptimeMillis();
-        mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+        mProcessStateController.setStartRequested(s, true);
+        mProcessStateController.setServiceLastActivityTime(s, SystemClock.uptimeMillis());
+        setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
         updateOomAdj();
         assertProcStates(app, PROCESS_STATE_SERVICE, SERVICE_ADJ, SCHED_GROUP_BACKGROUND);
 
-        app.mServices.stopService(s);
+        mProcessStateController.stopService(app.mServices, s);
         updateOomAdj();
         // isolated process should be killed immediately after service stop.
         verify(app).killLocked("isolated not needed", ApplicationExitInfo.REASON_OTHER,
@@ -2944,13 +2987,13 @@
                 MOCKAPP_ISOLATED_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
 
         ServiceRecord s = makeServiceRecord(app);
-        s.startRequested = true;
-        s.lastActivity = SystemClock.uptimeMillis();
-        mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+        mProcessStateController.setStartRequested(s, true);
+        mProcessStateController.setServiceLastActivityTime(s, SystemClock.uptimeMillis());
+        setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
         updateOomAdjPending(app);
         assertProcStates(app, PROCESS_STATE_SERVICE, SERVICE_ADJ, SCHED_GROUP_BACKGROUND);
 
-        app.mServices.stopService(s);
+        mProcessStateController.stopService(app.mServices, s);
         updateOomAdjPending(app);
         // isolated process should be killed immediately after service stop.
         verify(app).killLocked("isolated not needed", ApplicationExitInfo.REASON_OTHER,
@@ -2966,13 +3009,13 @@
 
         setProcessesToLru(app);
         ServiceRecord s = makeServiceRecord(app);
-        s.startRequested = true;
-        s.lastActivity = SystemClock.uptimeMillis();
-        mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+        mProcessStateController.setStartRequested(s, true);
+        mProcessStateController.setServiceLastActivityTime(s, SystemClock.uptimeMillis());
+        setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
         updateOomAdj();
         assertProcStates(app, PROCESS_STATE_SERVICE, SERVICE_ADJ, SCHED_GROUP_BACKGROUND);
 
-        app.mServices.stopService(s);
+        mProcessStateController.stopService(app.mServices, s);
         updateOomAdj();
         // isolated process with entry point should not be killed
         verify(app, never()).killLocked("isolated not needed", ApplicationExitInfo.REASON_OTHER,
@@ -2987,13 +3030,13 @@
         app.setIsolatedEntryPoint("test");
 
         ServiceRecord s = makeServiceRecord(app);
-        s.startRequested = true;
-        s.lastActivity = SystemClock.uptimeMillis();
-        mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+        mProcessStateController.setStartRequested(s, true);
+        mProcessStateController.setServiceLastActivityTime(s, SystemClock.uptimeMillis());
+        setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
         updateOomAdjPending(app);
         assertProcStates(app, PROCESS_STATE_SERVICE, SERVICE_ADJ, SCHED_GROUP_BACKGROUND);
 
-        app.mServices.stopService(s);
+        mProcessStateController.stopService(app.mServices, s);
         updateOomAdjPending(app);
         // isolated process with entry point should not be killed
         verify(app, never()).killLocked("isolated not needed", ApplicationExitInfo.REASON_OTHER,
@@ -3014,10 +3057,10 @@
 
         setProcessesToLru(sandboxService, client, attributedClient);
 
-        client.mState.setMaxAdj(PERSISTENT_PROC_ADJ);
-        attributedClient.mServices.setHasForegroundServices(true, 0, true);
+        mProcessStateController.setMaxAdj(client, PERSISTENT_PROC_ADJ);
+        mProcessStateController.setHasForegroundServices(attributedClient.mServices, true, 0, true);
         bindService(sandboxService, client, attributedClient, null, 0, mock(IBinder.class));
-        mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+        setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
         updateOomAdj();
         assertProcStates(client, PROCESS_STATE_PERSISTENT, PERSISTENT_PROC_ADJ,
                 SCHED_GROUP_DEFAULT);
@@ -3038,13 +3081,13 @@
 
         // App1 binds to app2 and gets temp allowlisted.
         bindService(app2, app, null, null, 0, mock(IBinder.class));
-        mService.mOomAdjuster.setUidTempAllowlistStateLSP(MOCKAPP_UID, true);
+        mProcessStateController.setUidTempAllowlistStateLSP(MOCKAPP_UID, true);
 
         assertEquals(true, app.getUidRecord().isSetAllowListed());
         assertEquals(true, app.mOptRecord.shouldNotFreeze());
         assertEquals(true, app2.mOptRecord.shouldNotFreeze());
 
-        mService.mOomAdjuster.setUidTempAllowlistStateLSP(MOCKAPP_UID, false);
+        mProcessStateController.setUidTempAllowlistStateLSP(MOCKAPP_UID, false);
         assertEquals(false, app.getUidRecord().isSetAllowListed());
         assertEquals(false, app.mOptRecord.shouldNotFreeze());
         assertEquals(false, app2.mOptRecord.shouldNotFreeze());
@@ -3064,8 +3107,8 @@
         // App1 and app2 both bind to app3 and get temp allowlisted.
         bindService(app3, app, null, null, 0, mock(IBinder.class));
         bindService(app3, app2, null, null, 0, mock(IBinder.class));
-        mService.mOomAdjuster.setUidTempAllowlistStateLSP(MOCKAPP_UID, true);
-        mService.mOomAdjuster.setUidTempAllowlistStateLSP(MOCKAPP2_UID, true);
+        mProcessStateController.setUidTempAllowlistStateLSP(MOCKAPP_UID, true);
+        mProcessStateController.setUidTempAllowlistStateLSP(MOCKAPP2_UID, true);
 
         assertEquals(true, app.getUidRecord().isSetAllowListed());
         assertEquals(true, app2.getUidRecord().isSetAllowListed());
@@ -3074,7 +3117,7 @@
         assertEquals(true, app3.mOptRecord.shouldNotFreeze());
 
         // Remove app1 from allowlist.
-        mService.mOomAdjuster.setUidTempAllowlistStateLSP(MOCKAPP_UID, false);
+        mProcessStateController.setUidTempAllowlistStateLSP(MOCKAPP_UID, false);
         assertEquals(false, app.getUidRecord().isSetAllowListed());
         assertEquals(true, app2.getUidRecord().isSetAllowListed());
         assertEquals(false, app.mOptRecord.shouldNotFreeze());
@@ -3082,7 +3125,7 @@
         assertEquals(true, app3.mOptRecord.shouldNotFreeze());
 
         // Now remove app2 from allowlist.
-        mService.mOomAdjuster.setUidTempAllowlistStateLSP(MOCKAPP2_UID, false);
+        mProcessStateController.setUidTempAllowlistStateLSP(MOCKAPP2_UID, false);
         assertEquals(false, app.getUidRecord().isSetAllowListed());
         assertEquals(false, app2.getUidRecord().isSetAllowListed());
         assertEquals(false, app.mOptRecord.shouldNotFreeze());
@@ -3098,9 +3141,9 @@
 
         setProcessesToLru(app);
         ServiceRecord s = makeServiceRecord(app);
-        s.startRequested = true;
-        s.lastActivity = SystemClock.uptimeMillis();
-        mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+        mProcessStateController.setStartRequested(s, true);
+        mProcessStateController.setServiceLastActivityTime(s, SystemClock.uptimeMillis());
+        setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
         updateOomAdj();
         assertProcStates(app, PROCESS_STATE_SERVICE, SERVICE_ADJ, SCHED_GROUP_BACKGROUND,
                 "started-services");
@@ -3111,7 +3154,7 @@
         verify(mService.mHandler).sendEmptyMessageAtTime(
                 eq(FOLLOW_UP_OOMADJUSTER_UPDATE_MSG), followUpTimeCaptor.capture());
         mInjector.jumpUptimeAheadTo(followUpTimeCaptor.getValue());
-        mService.mOomAdjuster.updateOomAdjFollowUpTargetsLocked();
+        mProcessStateController.runFollowUpUpdate();
 
         final int expectedAdj = mService.mConstants.USE_TIERED_CACHED_ADJ
                 ? sFirstNonUiCachedAdj : sFirstCachedAdj;
@@ -3131,9 +3174,9 @@
                 MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
         app1.mProviders.setLastProviderTime(SystemClock.uptimeMillis());
         app2.mProviders.setLastProviderTime(SystemClock.uptimeMillis() + 2000);
-        mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+        setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
         setProcessesToLru(app1, app2);
-        mService.mOomAdjuster.updateOomAdjLocked(OOM_ADJ_REASON_NONE);
+        mProcessStateController.runFullUpdate(OOM_ADJ_REASON_NONE);
 
         assertProcStates(app1, PROCESS_STATE_LAST_ACTIVITY, PREVIOUS_APP_ADJ,
                 SCHED_GROUP_BACKGROUND, "recent-provider");
@@ -3146,7 +3189,7 @@
         verify(mService.mHandler, atLeastOnce()).sendEmptyMessageAtTime(
                 eq(FOLLOW_UP_OOMADJUSTER_UPDATE_MSG), followUpTimeCaptor.capture());
         mInjector.jumpUptimeAheadTo(followUpTimeCaptor.getValue());
-        mService.mOomAdjuster.updateOomAdjFollowUpTargetsLocked();
+        mProcessStateController.runFollowUpUpdate();
 
         final int expectedAdj = mService.mConstants.USE_TIERED_CACHED_ADJ
                 ? sFirstNonUiCachedAdj : sFirstCachedAdj;
@@ -3156,7 +3199,7 @@
         verify(mService.mHandler, atLeastOnce()).sendEmptyMessageAtTime(
                 eq(FOLLOW_UP_OOMADJUSTER_UPDATE_MSG), followUpTimeCaptor.capture());
         mInjector.jumpUptimeAheadTo(followUpTimeCaptor.getValue());
-        mService.mOomAdjuster.updateOomAdjFollowUpTargetsLocked();
+        mProcessStateController.runFollowUpUpdate();
         assertProcStates(app2, PROCESS_STATE_CACHED_EMPTY, expectedAdj, SCHED_GROUP_BACKGROUND,
                 "cch-empty");
     }
@@ -3169,12 +3212,12 @@
 
     private ServiceRecord makeServiceRecord(ProcessRecord app) {
         final ServiceRecord record = mock(ServiceRecord.class);
-        record.app = app;
+        mProcessStateController.setHostProcess(record, app);
         setFieldValue(ServiceRecord.class, record, "connections",
                 new ArrayMap<IBinder, ArrayList<ConnectionRecord>>());
         doCallRealMethod().when(record).getConnections();
         setFieldValue(ServiceRecord.class, record, "packageName", app.info.packageName);
-        app.mServices.startService(record);
+        mProcessStateController.startService(app.mServices, record);
         record.appInfo = app.info;
         setFieldValue(ServiceRecord.class, record, "bindings", new ArrayMap<>());
         setFieldValue(ServiceRecord.class, record, "pendingStarts", new ArrayList<>());
@@ -3213,27 +3256,55 @@
         doCallRealMethod().when(record).addConnection(any(IBinder.class),
                 any(ConnectionRecord.class));
         record.addConnection(binder, cr);
-        client.mServices.addConnection(cr);
+        mProcessStateController.addConnection(client.mServices, cr);
         binding.connections.add(cr);
         doNothing().when(cr).trackProcState(anyInt(), anyInt());
         return record;
     }
 
-    private ContentProviderRecord bindProvider(ProcessRecord publisher, ProcessRecord client,
-            ContentProviderRecord record, String name, boolean hasExternalProviders) {
-        if (record == null) {
-            record = mock(ContentProviderRecord.class);
-            publisher.mProviders.installProvider(name, record);
-            record.proc = publisher;
-            setFieldValue(ContentProviderRecord.class, record, "connections",
-                    new ArrayList<ContentProviderConnection>());
-            doReturn(hasExternalProviders).when(record).hasExternalProcessHandles();
+    private void setWakefulness(int state) {
+        if (Flags.pushGlobalStateToOomadjuster()) {
+            mProcessStateController.setWakefulness(state);
+        } else {
+            mService.mWakefulness.set(state);
         }
+    }
+
+    @SuppressWarnings("GuardedBy")
+    private void setBackupTarget(ProcessRecord app) {
+        if (Flags.pushGlobalStateToOomadjuster()) {
+            mProcessStateController.setBackupTarget(app, app.userId);
+        } else {
+            BackupRecord backupTarget = new BackupRecord(null, 0, 0, 0);
+            backupTarget.app = app;
+            doReturn(backupTarget).when(mService.mBackupTargets).get(anyInt());
+        }
+    }
+
+    private ContentProviderRecord createContentProviderRecord(ProcessRecord publisher, String name,
+            boolean hasExternalProviders) {
+        ContentProviderRecord record = mock(ContentProviderRecord.class);
+        mProcessStateController.addPublishedProvider(publisher, name, record);
+        record.proc = publisher;
+        setFieldValue(ContentProviderRecord.class, record, "connections",
+                new ArrayList<ContentProviderConnection>());
+        doReturn(hasExternalProviders).when(record).hasExternalProcessHandles();
+        return record;
+    }
+
+    private ContentProviderConnection bindProvider(ProcessRecord client,
+            ContentProviderRecord record) {
         ContentProviderConnection conn = spy(new ContentProviderConnection(record, client,
                 client.info.packageName, UserHandle.getUserId(client.uid)));
         record.connections.add(conn);
-        client.mProviders.addProviderConnection(conn);
-        return record;
+        mProcessStateController.addProviderConnection(client, conn);
+        return conn;
+    }
+
+    private void unbindProvider(ProcessRecord client, ContentProviderRecord record,
+            ContentProviderConnection conn) {
+        record.connections.remove(conn);
+        mProcessStateController.removeProviderConnection(client, conn);
     }
 
     @SuppressWarnings("GuardedBy")
@@ -3405,10 +3476,10 @@
             }
             providers.setLastProviderTime(mLastProviderTime);
 
-            UidRecord uidRec = mService.mOomAdjuster.mActiveUids.get(mUid);
+            UidRecord uidRec = mActiveUids.get(mUid);
             if (uidRec == null) {
                 uidRec = new UidRecord(mUid, mService);
-                mService.mOomAdjuster.mActiveUids.put(mUid, uidRec);
+                mActiveUids.put(mUid, uidRec);
             }
             uidRec.addProcess(app);
             app.setUidRecord(uidRec);
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/ServiceBindingOomAdjPolicyTest.java b/services/tests/mockingservicestests/src/com/android/server/am/ServiceBindingOomAdjPolicyTest.java
index 1ff4a27..59302ee 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/ServiceBindingOomAdjPolicyTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/ServiceBindingOomAdjPolicyTest.java
@@ -50,7 +50,6 @@
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 
-import android.app.IApplicationThread;
 import android.app.IServiceConnection;
 import android.app.usage.UsageStatsManagerInternal;
 import android.content.ComponentName;
@@ -169,6 +168,7 @@
         realAtm.initialize(null, null, mContext.getMainLooper());
         realAms.mActivityTaskManager = spy(realAtm);
         realAms.mAtmInternal = spy(realAms.mActivityTaskManager.getAtmInternal());
+        realAms.mProcessStateController = spy(realAms.mProcessStateController);
         realAms.mOomAdjuster = spy(realAms.mOomAdjuster);
         realAms.mOomAdjuster.mCachedAppOptimizer = spy(realAms.mOomAdjuster.mCachedAppOptimizer);
         realAms.mPackageManagerInt = mPackageManagerInt;
@@ -242,14 +242,14 @@
                 USER_SYSTEM              // userId
         ));
 
-        verify(mAms.mOomAdjuster, bindMode).updateOomAdjPendingTargetsLocked(anyInt());
-        clearInvocations(mAms.mOomAdjuster);
+        verify(mAms.mProcessStateController, bindMode).runPendingUpdate(anyInt());
+        clearInvocations(mAms.mProcessStateController);
 
         // Unbind the service.
         mAms.unbindService(serviceConnection);
 
-        verify(mAms.mOomAdjuster, unbindMode).updateOomAdjPendingTargetsLocked(anyInt());
-        clearInvocations(mAms.mOomAdjuster);
+        verify(mAms.mProcessStateController, unbindMode).runPendingUpdate(anyInt());
+        clearInvocations(mAms.mProcessStateController);
 
         removeProcessRecord(app);
     }
@@ -496,8 +496,8 @@
                 USER_SYSTEM            // userId
         ));
 
-        verify(mAms.mOomAdjuster, bindMode).updateOomAdjPendingTargetsLocked(anyInt());
-        clearInvocations(mAms.mOomAdjuster);
+        verify(mAms.mProcessStateController, bindMode).runPendingUpdate(anyInt());
+        clearInvocations(mAms.mProcessStateController);
 
         if (clientApp.isFreezable()) {
             verify(mAms.mOomAdjuster.mCachedAppOptimizer,
@@ -509,8 +509,8 @@
         // Unbind the service.
         mAms.unbindService(serviceConnection);
 
-        verify(mAms.mOomAdjuster, unbindMode).updateOomAdjPendingTargetsLocked(anyInt());
-        clearInvocations(mAms.mOomAdjuster);
+        verify(mAms.mProcessStateController, unbindMode).runPendingUpdate(anyInt());
+        clearInvocations(mAms.mProcessStateController);
 
         removeProcessRecord(clientApp);
         removeProcessRecord(serviceApp);
diff --git a/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsUidStateTrackerTest.java b/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsUidStateTrackerTest.java
index 1731590..026e72f 100644
--- a/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsUidStateTrackerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsUidStateTrackerTest.java
@@ -31,12 +31,14 @@
 import static android.app.AppOpsManager.UID_STATE_FOREGROUND_SERVICE;
 import static android.app.AppOpsManager.UID_STATE_MAX_LAST_NON_RESTRICTED;
 import static android.app.AppOpsManager.UID_STATE_TOP;
+import static android.permission.flags.Flags.delayUidStateChangesFromCapabilityUpdates;
 
 import static com.android.server.appop.AppOpsUidStateTracker.processStateToUidState;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeTrue;
 import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.eq;
@@ -325,6 +327,10 @@
                 .backgroundState()
                 .update();
 
+        assertEquals(MODE_IGNORED, mIntf.evalMode(UID, OP_RECORD_AUDIO, MODE_FOREGROUND));
+        assertEquals(MODE_IGNORED,
+                mIntf.evalMode(UID, OP_RECEIVE_EXPLICIT_USER_INTERACTION_AUDIO, MODE_FOREGROUND));
+
         procStateBuilder(UID)
                 .backgroundState()
                 .microphoneCapability()
@@ -342,10 +348,23 @@
                 .microphoneCapability()
                 .update();
 
+        assertEquals(MODE_ALLOWED, mIntf.evalMode(UID, OP_RECORD_AUDIO, MODE_FOREGROUND));
+        assertEquals(MODE_ALLOWED,
+                mIntf.evalMode(UID, OP_RECEIVE_EXPLICIT_USER_INTERACTION_AUDIO, MODE_FOREGROUND));
+
         procStateBuilder(UID)
                 .backgroundState()
                 .update();
 
+        if (delayUidStateChangesFromCapabilityUpdates()) {
+            mClock.advanceTime(mConstants.BG_STATE_SETTLE_TIME - 1);
+            assertEquals(MODE_ALLOWED, mIntf.evalMode(UID, OP_RECORD_AUDIO, MODE_FOREGROUND));
+            assertEquals(MODE_ALLOWED,
+                    mIntf.evalMode(UID, OP_RECEIVE_EXPLICIT_USER_INTERACTION_AUDIO,
+                            MODE_FOREGROUND));
+
+            mClock.advanceTime(1);
+        }
         assertEquals(MODE_IGNORED, mIntf.evalMode(UID, OP_RECORD_AUDIO, MODE_FOREGROUND));
         assertEquals(MODE_IGNORED,
                 mIntf.evalMode(UID, OP_RECEIVE_EXPLICIT_USER_INTERACTION_AUDIO, MODE_FOREGROUND));
@@ -357,6 +376,8 @@
                 .backgroundState()
                 .update();
 
+        assertEquals(MODE_IGNORED, mIntf.evalMode(UID, OP_CAMERA, MODE_FOREGROUND));
+
         procStateBuilder(UID)
                 .backgroundState()
                 .cameraCapability()
@@ -372,10 +393,18 @@
                 .cameraCapability()
                 .update();
 
+        assertEquals(MODE_ALLOWED, mIntf.evalMode(UID, OP_CAMERA, MODE_FOREGROUND));
+
         procStateBuilder(UID)
                 .backgroundState()
                 .update();
 
+        if (delayUidStateChangesFromCapabilityUpdates()) {
+            mClock.advanceTime(mConstants.BG_STATE_SETTLE_TIME - 1);
+            assertEquals(MODE_ALLOWED, mIntf.evalMode(UID, OP_CAMERA, MODE_FOREGROUND));
+
+            mClock.advanceTime(1);
+        }
         assertEquals(MODE_IGNORED, mIntf.evalMode(UID, OP_CAMERA, MODE_FOREGROUND));
     }
 
@@ -385,6 +414,9 @@
                 .backgroundState()
                 .update();
 
+        assertEquals(MODE_IGNORED, mIntf.evalMode(UID, OP_COARSE_LOCATION, MODE_FOREGROUND));
+        assertEquals(MODE_IGNORED, mIntf.evalMode(UID, OP_FINE_LOCATION, MODE_FOREGROUND));
+
         procStateBuilder(UID)
                 .backgroundState()
                 .locationCapability()
@@ -401,15 +433,55 @@
                 .locationCapability()
                 .update();
 
+        assertEquals(MODE_ALLOWED, mIntf.evalMode(UID, OP_COARSE_LOCATION, MODE_FOREGROUND));
+        assertEquals(MODE_ALLOWED, mIntf.evalMode(UID, OP_FINE_LOCATION, MODE_FOREGROUND));
+
         procStateBuilder(UID)
                 .backgroundState()
                 .update();
 
+        if (delayUidStateChangesFromCapabilityUpdates()) {
+            mClock.advanceTime(mConstants.BG_STATE_SETTLE_TIME - 1);
+            assertEquals(MODE_ALLOWED, mIntf.evalMode(UID, OP_COARSE_LOCATION, MODE_FOREGROUND));
+            assertEquals(MODE_ALLOWED, mIntf.evalMode(UID, OP_FINE_LOCATION, MODE_FOREGROUND));
+
+            mClock.advanceTime(1);
+        }
         assertEquals(MODE_IGNORED, mIntf.evalMode(UID, OP_COARSE_LOCATION, MODE_FOREGROUND));
         assertEquals(MODE_IGNORED, mIntf.evalMode(UID, OP_FINE_LOCATION, MODE_FOREGROUND));
     }
 
     @Test
+    public void testProcStateChangesAndStaysUnrestrictedAndCapabilityRemoved() {
+        assumeTrue(delayUidStateChangesFromCapabilityUpdates());
+
+        procStateBuilder(UID)
+                .topState()
+                .microphoneCapability()
+                .cameraCapability()
+                .locationCapability()
+                .update();
+
+        assertEquals(MODE_ALLOWED, mIntf.evalMode(UID, OP_RECORD_AUDIO, MODE_FOREGROUND));
+        assertEquals(MODE_ALLOWED, mIntf.evalMode(UID, OP_CAMERA, MODE_FOREGROUND));
+        assertEquals(MODE_ALLOWED, mIntf.evalMode(UID, OP_COARSE_LOCATION, MODE_FOREGROUND));
+
+        procStateBuilder(UID)
+                .foregroundState()
+                .update();
+
+        mClock.advanceTime(mConstants.TOP_STATE_SETTLE_TIME - 1);
+        assertEquals(MODE_ALLOWED, mIntf.evalMode(UID, OP_RECORD_AUDIO, MODE_FOREGROUND));
+        assertEquals(MODE_ALLOWED, mIntf.evalMode(UID, OP_CAMERA, MODE_FOREGROUND));
+        assertEquals(MODE_ALLOWED, mIntf.evalMode(UID, OP_COARSE_LOCATION, MODE_FOREGROUND));
+
+        mClock.advanceTime(1);
+        assertEquals(MODE_IGNORED, mIntf.evalMode(UID, OP_RECORD_AUDIO, MODE_FOREGROUND));
+        assertEquals(MODE_IGNORED, mIntf.evalMode(UID, OP_CAMERA, MODE_FOREGROUND));
+        assertEquals(MODE_IGNORED, mIntf.evalMode(UID, OP_COARSE_LOCATION, MODE_FOREGROUND));
+    }
+
+    @Test
     public void testVisibleAppWidget() {
         procStateBuilder(UID)
                 .backgroundState()
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java
index 584fd62..31157f9 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java
@@ -25,6 +25,7 @@
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
 import static com.android.server.job.Flags.FLAG_COUNT_QUOTA_FIX;
+import static com.android.server.job.Flags.FLAG_ENFORCE_QUOTA_POLICY_TO_FGS_JOBS;
 import static com.android.server.job.JobSchedulerService.ACTIVE_INDEX;
 import static com.android.server.job.JobSchedulerService.EXEMPTED_INDEX;
 import static com.android.server.job.JobSchedulerService.FREQUENT_INDEX;
@@ -303,6 +304,12 @@
         }
     }
 
+    private int getProcessStateQuotaFreeThreshold() {
+        synchronized (mQuotaController.mLock) {
+            return mQuotaController.getProcessStateQuotaFreeThreshold();
+        }
+    }
+
     private void setProcessState(int procState) {
         setProcessState(procState, mSourceUid);
     }
@@ -315,7 +322,7 @@
             final boolean contained = foregroundUids.get(uid);
             mUidObserver.onUidStateChanged(uid, procState, 0,
                     ActivityManager.PROCESS_CAPABILITY_NONE);
-            if (procState <= ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE) {
+            if (procState <= getProcessStateQuotaFreeThreshold()) {
                 if (!contained) {
                     verify(foregroundUids, timeout(2 * SECOND_IN_MILLIS).times(1))
                             .put(eq(uid), eq(true));
@@ -938,19 +945,22 @@
     public void testGetExecutionStatsLocked_Values() {
         final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
         mQuotaController.saveTimingSession(0, "com.android.test",
-                createTimingSession(now - (23 * HOUR_IN_MILLIS), 10 * MINUTE_IN_MILLIS, 5), false);
+                createTimingSession(now - (mQcConstants.WINDOW_SIZE_RARE_MS - HOUR_IN_MILLIS),
+                        10 * MINUTE_IN_MILLIS, 5), false);
         mQuotaController.saveTimingSession(0, "com.android.test",
-                createTimingSession(now - (7 * HOUR_IN_MILLIS), 10 * MINUTE_IN_MILLIS, 5), false);
+                createTimingSession(now - (mQcConstants.WINDOW_SIZE_FREQUENT_MS - HOUR_IN_MILLIS),
+                        10 * MINUTE_IN_MILLIS, 5), false);
         mQuotaController.saveTimingSession(0, "com.android.test",
-                createTimingSession(now - (2 * HOUR_IN_MILLIS), 10 * MINUTE_IN_MILLIS, 5), false);
+                createTimingSession(now - mQcConstants.WINDOW_SIZE_WORKING_MS,
+                        10 * MINUTE_IN_MILLIS, 5), false);
         mQuotaController.saveTimingSession(0, "com.android.test",
                 createTimingSession(now - (6 * MINUTE_IN_MILLIS), 3 * MINUTE_IN_MILLIS, 5), false);
 
         ExecutionStats expectedStats = new ExecutionStats();
 
         // Active
-        expectedStats.allowedTimePerPeriodMs = 10 * MINUTE_IN_MILLIS;
-        expectedStats.windowSizeMs = 10 * MINUTE_IN_MILLIS;
+        expectedStats.allowedTimePerPeriodMs = mQcConstants.ALLOWED_TIME_PER_PERIOD_ACTIVE_MS;
+        expectedStats.windowSizeMs = mQcConstants.WINDOW_SIZE_ACTIVE_MS;
         expectedStats.jobCountLimit = mQcConstants.MAX_JOB_COUNT_ACTIVE;
         expectedStats.sessionCountLimit = mQcConstants.MAX_SESSION_COUNT_ACTIVE;
         expectedStats.expirationTimeElapsed = now + 4 * MINUTE_IN_MILLIS;
@@ -965,7 +975,7 @@
         }
 
         // Working
-        expectedStats.windowSizeMs = 2 * HOUR_IN_MILLIS;
+        expectedStats.windowSizeMs = mQcConstants.WINDOW_SIZE_WORKING_MS;
         expectedStats.jobCountLimit = mQcConstants.MAX_JOB_COUNT_WORKING;
         expectedStats.sessionCountLimit = mQcConstants.MAX_SESSION_COUNT_WORKING;
         expectedStats.expirationTimeElapsed = now;
@@ -982,7 +992,7 @@
         }
 
         // Frequent
-        expectedStats.windowSizeMs = 8 * HOUR_IN_MILLIS;
+        expectedStats.windowSizeMs = mQcConstants.WINDOW_SIZE_FREQUENT_MS;
         expectedStats.jobCountLimit = mQcConstants.MAX_JOB_COUNT_FREQUENT;
         expectedStats.sessionCountLimit = mQcConstants.MAX_SESSION_COUNT_FREQUENT;
         expectedStats.expirationTimeElapsed = now + HOUR_IN_MILLIS;
@@ -1000,7 +1010,7 @@
         }
 
         // Rare
-        expectedStats.windowSizeMs = 24 * HOUR_IN_MILLIS;
+        expectedStats.windowSizeMs = mQcConstants.WINDOW_SIZE_RARE_MS;
         expectedStats.jobCountLimit = mQcConstants.MAX_JOB_COUNT_RARE;
         expectedStats.sessionCountLimit = mQcConstants.MAX_SESSION_COUNT_RARE;
         expectedStats.expirationTimeElapsed = now + HOUR_IN_MILLIS;
@@ -1245,7 +1255,8 @@
         mQuotaController.saveTimingSession(0, "com.android.test",
                 createTimingSession(now - (7 * HOUR_IN_MILLIS), 10 * MINUTE_IN_MILLIS, 5), false);
         mQuotaController.saveTimingSession(0, "com.android.test",
-                createTimingSession(now - (2 * HOUR_IN_MILLIS), 10 * MINUTE_IN_MILLIS, 5), false);
+                createTimingSession(now - mQcConstants.WINDOW_SIZE_WORKING_MS,
+                        10 * MINUTE_IN_MILLIS, 5), false);
         mQuotaController.saveTimingSession(0, "com.android.test",
                 createTimingSession(now - (6 * MINUTE_IN_MILLIS), 3 * MINUTE_IN_MILLIS, 5), false);
         final ExecutionStats originalStatsActive;
@@ -1371,7 +1382,7 @@
         }
 
         setDischarging();
-        setProcessState(ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE);
+        setProcessState(getProcessStateQuotaFreeThreshold());
         synchronized (mQuotaController.mLock) {
             assertEquals(timeUntilQuotaConsumedMs,
                     mQuotaController.getMaxJobExecutionTimeMsLocked((job)));
@@ -1473,7 +1484,7 @@
         }
 
         setDischarging();
-        setProcessState(ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE);
+        setProcessState(getProcessStateQuotaFreeThreshold());
         synchronized (mQuotaController.mLock) {
             assertEquals(mQcConstants.EJ_LIMIT_WORKING_MS / 2,
                     mQuotaController.getMaxJobExecutionTimeMsLocked(job));
@@ -1505,7 +1516,7 @@
                 createTimingSession(sElapsedRealtimeClock.millis() - mQcConstants.EJ_WINDOW_SIZE_MS,
                         timeUsedMs, 5), true);
 
-        setProcessState(ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE);
+        setProcessState(getProcessStateQuotaFreeThreshold());
         synchronized (mQuotaController.mLock) {
             assertEquals(mQcConstants.EJ_LIMIT_WORKING_MS / 2,
                     mQuotaController.getMaxJobExecutionTimeMsLocked(job));
@@ -1651,7 +1662,7 @@
         // Close to boundary.
         mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
                 createTimingSession(now - (24 * HOUR_IN_MILLIS - MINUTE_IN_MILLIS),
-                        4 * HOUR_IN_MILLIS - 5 * MINUTE_IN_MILLIS, 5), false);
+                        mQcConstants.MAX_EXECUTION_TIME_MS - 5 * MINUTE_IN_MILLIS, 5), false);
 
         setStandbyBucket(WORKING_INDEX);
         synchronized (mQuotaController.mLock) {
@@ -1667,7 +1678,8 @@
         // Far from boundary.
         mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
                 createTimingSession(
-                        now - (20 * HOUR_IN_MILLIS), 4 * HOUR_IN_MILLIS - 3 * MINUTE_IN_MILLIS, 5),
+                        now - (20 * HOUR_IN_MILLIS),
+                        mQcConstants.MAX_EXECUTION_TIME_MS - 3 * MINUTE_IN_MILLIS, 5),
                 false);
 
         setStandbyBucket(WORKING_INDEX);
@@ -1694,11 +1706,12 @@
         mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
                 createTimingSession(
                         now - (24 * HOUR_IN_MILLIS + 11 * MINUTE_IN_MILLIS),
-                        4 * HOUR_IN_MILLIS,
+                        mQcConstants.MAX_EXECUTION_TIME_MS,
                         5), false);
         mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
                 createTimingSession(
-                        now - (8 * HOUR_IN_MILLIS + MINUTE_IN_MILLIS), 3 * MINUTE_IN_MILLIS, 5),
+                        now - (mQcConstants.WINDOW_SIZE_FREQUENT_MS + MINUTE_IN_MILLIS),
+                        3 * MINUTE_IN_MILLIS, 5),
                 false);
 
         synchronized (mQuotaController.mLock) {
@@ -1722,11 +1735,12 @@
         mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
                 createTimingSession(
                         now - (20 * HOUR_IN_MILLIS),
-                        3 * HOUR_IN_MILLIS + 48 * MINUTE_IN_MILLIS,
+                        mQcConstants.MAX_EXECUTION_TIME_MS - 12 * MINUTE_IN_MILLIS,
                         5), false);
         mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
                 createTimingSession(
-                        now - (8 * HOUR_IN_MILLIS + MINUTE_IN_MILLIS), 3 * MINUTE_IN_MILLIS, 5),
+                        now - (mQcConstants.WINDOW_SIZE_FREQUENT_MS + MINUTE_IN_MILLIS),
+                        3 * MINUTE_IN_MILLIS, 5),
                 false);
 
         synchronized (mQuotaController.mLock) {
@@ -2406,7 +2420,8 @@
 
         long now = JobSchedulerService.sElapsedRealtimeClock.millis();
         mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
-                createTimingSession(now - (HOUR_IN_MILLIS), 5 * MINUTE_IN_MILLIS, 10), false);
+                createTimingSession(now - (mQcConstants.WINDOW_SIZE_WORKING_MS - HOUR_IN_MILLIS),
+                        5 * MINUTE_IN_MILLIS, 10), false);
         final ExecutionStats stats;
         synchronized (mQuotaController.mLock) {
             stats = mQuotaController.getExecutionStatsLocked(
@@ -2492,7 +2507,8 @@
 
         long now = JobSchedulerService.sElapsedRealtimeClock.millis();
         mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
-                createTimingSession(now - (HOUR_IN_MILLIS), 5 * MINUTE_IN_MILLIS, 1), false);
+                createTimingSession(now - (mQcConstants.WINDOW_SIZE_WORKING_MS - HOUR_IN_MILLIS),
+                        5 * MINUTE_IN_MILLIS, 1), false);
         mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
                 createTimingSession(now - (30 * MINUTE_IN_MILLIS), MINUTE_IN_MILLIS, 1), false);
         final ExecutionStats stats;
@@ -2928,12 +2944,12 @@
                 anyInt(), anyLong(), anyLong(), eq(TAG_QUOTA_CHECK), any(), any(Handler.class));
 
         // Test with timing sessions in window but still in quota.
-        final long end = now - (2 * HOUR_IN_MILLIS - 5 * MINUTE_IN_MILLIS);
+        final long end = now - (mQcConstants.WINDOW_SIZE_WORKING_MS - 5 * MINUTE_IN_MILLIS);
         // Counting backwards, the quota will come back one minute before the end.
-        final long expectedAlarmTime =
-                end - MINUTE_IN_MILLIS + 2 * HOUR_IN_MILLIS + mQcConstants.IN_QUOTA_BUFFER_MS;
+        final long expectedAlarmTime = end - MINUTE_IN_MILLIS + mQcConstants.WINDOW_SIZE_WORKING_MS
+                + mQcConstants.IN_QUOTA_BUFFER_MS;
         mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
-                new TimingSession(now - 2 * HOUR_IN_MILLIS, end, 1), false);
+                new TimingSession(now - mQcConstants.WINDOW_SIZE_WORKING_MS, end, 1), false);
         synchronized (mQuotaController.mLock) {
             mQuotaController.maybeScheduleStartAlarmLocked(
                     SOURCE_USER_ID, SOURCE_PACKAGE, standbyBucket);
@@ -3000,7 +3016,8 @@
         // Test with timing sessions out of window.
         final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
         mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
-                createTimingSession(now - 10 * HOUR_IN_MILLIS, 5 * MINUTE_IN_MILLIS, 1), false);
+                createTimingSession(now - mQcConstants.WINDOW_SIZE_FREQUENT_MS
+                        - 2 * HOUR_IN_MILLIS, 5 * MINUTE_IN_MILLIS, 1), false);
         synchronized (mQuotaController.mLock) {
             mQuotaController.maybeScheduleStartAlarmLocked(
                     SOURCE_USER_ID, SOURCE_PACKAGE, standbyBucket);
@@ -3009,8 +3026,9 @@
                 anyInt(), anyLong(), anyLong(), eq(TAG_QUOTA_CHECK), any(), any(Handler.class));
 
         // Test with timing sessions in window but still in quota.
-        final long start = now - (6 * HOUR_IN_MILLIS);
-        final long expectedAlarmTime = start + 8 * HOUR_IN_MILLIS + mQcConstants.IN_QUOTA_BUFFER_MS;
+        final long start = now - (mQcConstants.WINDOW_SIZE_FREQUENT_MS - 2 * HOUR_IN_MILLIS);
+        final long expectedAlarmTime = start + mQcConstants.WINDOW_SIZE_FREQUENT_MS
+                + mQcConstants.IN_QUOTA_BUFFER_MS;
         mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
                 createTimingSession(start, 5 * MINUTE_IN_MILLIS, 1), false);
         synchronized (mQuotaController.mLock) {
@@ -3084,7 +3102,8 @@
         // Test with timing sessions out of window.
         final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
         mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
-                createTimingSession(now - 10 * HOUR_IN_MILLIS, 5 * MINUTE_IN_MILLIS, 1), false);
+                createTimingSession(now - mQcConstants.WINDOW_SIZE_FREQUENT_MS
+                                - 2 * HOUR_IN_MILLIS, 5 * MINUTE_IN_MILLIS, 1), false);
         synchronized (mQuotaController.mLock) {
             mQuotaController.maybeScheduleStartAlarmLocked(
                     SOURCE_USER_ID, SOURCE_PACKAGE, effectiveStandbyBucket);
@@ -3093,8 +3112,9 @@
                 anyInt(), anyLong(), anyLong(), eq(TAG_QUOTA_CHECK), any(), any(Handler.class));
 
         // Test with timing sessions in window but still in quota.
-        final long start = now - (6 * HOUR_IN_MILLIS);
-        final long expectedAlarmTime = start + 8 * HOUR_IN_MILLIS + mQcConstants.IN_QUOTA_BUFFER_MS;
+        final long start = now - (mQcConstants.WINDOW_SIZE_FREQUENT_MS - 2 * HOUR_IN_MILLIS);
+        final long expectedAlarmTime = start + mQcConstants.WINDOW_SIZE_FREQUENT_MS
+                + mQcConstants.IN_QUOTA_BUFFER_MS;
         mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
                 createTimingSession(start, 5 * MINUTE_IN_MILLIS, 1), false);
         synchronized (mQuotaController.mLock) {
@@ -3266,7 +3286,7 @@
 
         // And down from there.
         final long expectedWorkingAlarmTime =
-                outOfQuotaTime + (2 * HOUR_IN_MILLIS)
+                outOfQuotaTime + mQcConstants.WINDOW_SIZE_WORKING_MS
                         + mQcConstants.IN_QUOTA_BUFFER_MS;
         setStandbyBucket(WORKING_INDEX, jobStatus);
         synchronized (mQuotaController.mLock) {
@@ -3278,7 +3298,7 @@
                 eq(TAG_QUOTA_CHECK), any(), any(Handler.class));
 
         final long expectedFrequentAlarmTime =
-                outOfQuotaTime + (8 * HOUR_IN_MILLIS)
+                outOfQuotaTime + mQcConstants.WINDOW_SIZE_FREQUENT_MS
                         + mQcConstants.IN_QUOTA_BUFFER_MS;
         setStandbyBucket(FREQUENT_INDEX, jobStatus);
         synchronized (mQuotaController.mLock) {
@@ -3290,7 +3310,7 @@
                 eq(TAG_QUOTA_CHECK), any(), any(Handler.class));
 
         final long expectedRareAlarmTime =
-                outOfQuotaTime + (24 * HOUR_IN_MILLIS)
+                outOfQuotaTime + mQcConstants.WINDOW_SIZE_RARE_MS
                         + mQcConstants.IN_QUOTA_BUFFER_MS;
         setStandbyBucket(RARE_INDEX, jobStatus);
         synchronized (mQuotaController.mLock) {
@@ -3450,7 +3470,7 @@
         }
 
         final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
-        // Working set window size is 2 hours.
+        // Working set window size is configured with QcConstants.WINDOW_SIZE_WORKING_MS.
         final int standbyBucket = WORKING_INDEX;
         final long contributionMs = mQcConstants.IN_QUOTA_BUFFER_MS / 2;
         final long remainingTimeMs =
@@ -3459,13 +3479,14 @@
         // Session straddles edge of bucket window. Only the contribution should be counted towards
         // the quota.
         mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
-                createTimingSession(now - (2 * HOUR_IN_MILLIS + 3 * MINUTE_IN_MILLIS),
-                        3 * MINUTE_IN_MILLIS + contributionMs, 3), false);
+                createTimingSession(now - mQcConstants.WINDOW_SIZE_WORKING_MS
+                        - 3 * MINUTE_IN_MILLIS, 3 * MINUTE_IN_MILLIS + contributionMs,
+                        3), false);
         mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
                 createTimingSession(now - HOUR_IN_MILLIS, remainingTimeMs, 2), false);
         // Expected alarm time should be when the app will have QUOTA_BUFFER_MS time of quota, which
         // is 2 hours + (QUOTA_BUFFER_MS - contributionMs) after the start of the second session.
-        final long expectedAlarmTime = now - HOUR_IN_MILLIS + 2 * HOUR_IN_MILLIS
+        final long expectedAlarmTime = now - HOUR_IN_MILLIS + mQcConstants.WINDOW_SIZE_WORKING_MS
                 + (mQcConstants.IN_QUOTA_BUFFER_MS - contributionMs);
         synchronized (mQuotaController.mLock) {
             mQuotaController.maybeScheduleStartAlarmLocked(
@@ -4126,7 +4147,7 @@
         }
         advanceElapsedClock(5 * SECOND_IN_MILLIS);
         // Change to a state that should still be considered foreground.
-        setProcessState(ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE);
+        setProcessState(getProcessStateQuotaFreeThreshold());
         advanceElapsedClock(5 * SECOND_IN_MILLIS);
         synchronized (mQuotaController.mLock) {
             mQuotaController.maybeStopTrackingJobLocked(jobStatus, null);
@@ -4134,6 +4155,36 @@
         assertNull(mQuotaController.getTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE));
     }
 
+    /** Tests that Timers count FOREGROUND_SERVICE jobs. */
+    @Test
+    @RequiresFlagsEnabled(FLAG_ENFORCE_QUOTA_POLICY_TO_FGS_JOBS)
+    public void testTimerTracking_Fgs() {
+        setDischarging();
+
+        JobStatus jobStatus = createJobStatus("testTimerTracking_Fgs", 1);
+        setProcessState(ActivityManager.PROCESS_STATE_BOUND_TOP);
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.maybeStartTrackingJobLocked(jobStatus, null);
+        }
+
+        assertNull(mQuotaController.getTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE));
+
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.prepareForExecutionLocked(jobStatus);
+        }
+        advanceElapsedClock(5 * SECOND_IN_MILLIS);
+        // Change to FOREGROUND_SERVICE state that should count.
+        setProcessState(ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE);
+        long start = JobSchedulerService.sElapsedRealtimeClock.millis();
+        advanceElapsedClock(5 * SECOND_IN_MILLIS);
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.maybeStopTrackingJobLocked(jobStatus, null);
+        }
+        List<TimingSession> expected = new ArrayList<>();
+        expected.add(createTimingSession(start, 5 * SECOND_IN_MILLIS, 1));
+        assertEquals(expected, mQuotaController.getTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE));
+    }
+
     /**
      * Tests that Timers properly track sessions when switching between foreground and background
      * states.
@@ -4180,7 +4231,7 @@
         }
         advanceElapsedClock(10 * SECOND_IN_MILLIS);
         expected.add(createTimingSession(start, 10 * SECOND_IN_MILLIS, 1));
-        setProcessState(ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE);
+        setProcessState(getProcessStateQuotaFreeThreshold());
         synchronized (mQuotaController.mLock) {
             mQuotaController.prepareForExecutionLocked(jobFg3);
         }
@@ -4213,7 +4264,7 @@
         }
         advanceElapsedClock(10 * SECOND_IN_MILLIS);
         expected.add(createTimingSession(start, 10 * SECOND_IN_MILLIS, 1));
-        setProcessState(ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE);
+        setProcessState(getProcessStateQuotaFreeThreshold());
         synchronized (mQuotaController.mLock) {
             mQuotaController.prepareForExecutionLocked(jobFg3);
         }
@@ -4262,7 +4313,7 @@
         }
         assertEquals(0, stats.jobCountInRateLimitingWindow);
 
-        setProcessState(ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE);
+        setProcessState(getProcessStateQuotaFreeThreshold());
         synchronized (mQuotaController.mLock) {
             mQuotaController.prepareForExecutionLocked(jobFg1);
         }
@@ -4412,7 +4463,7 @@
             mQuotaController.maybeStopTrackingJobLocked(jobBg1, jobBg1);
         }
         advanceElapsedClock(5 * SECOND_IN_MILLIS);
-        setProcessState(ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE);
+        setProcessState(getProcessStateQuotaFreeThreshold());
         synchronized (mQuotaController.mLock) {
             mQuotaController.prepareForExecutionLocked(jobFg1);
         }
@@ -4625,7 +4676,7 @@
 
         // App still in foreground so everything should be in quota.
         advanceElapsedClock(20 * SECOND_IN_MILLIS);
-        setProcessState(ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE);
+        setProcessState(getProcessStateQuotaFreeThreshold());
         assertTrue(jobTop.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_QUOTA));
         assertTrue(jobFg.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_QUOTA));
         assertTrue(jobBg.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_QUOTA));
@@ -4697,7 +4748,7 @@
         // The package only has one second to run, but this session is at the edge of the rolling
         // window, so as the package "reaches its quota" it will have more to keep running.
         mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
-                createTimingSession(now - 2 * HOUR_IN_MILLIS,
+                createTimingSession(now - mQcConstants.WINDOW_SIZE_WORKING_MS,
                         10 * SECOND_IN_MILLIS - remainingTimeMs, 1), false);
         mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
                 createTimingSession(now - HOUR_IN_MILLIS,
@@ -5901,7 +5952,7 @@
         }
         advanceElapsedClock(10 * SECOND_IN_MILLIS);
         expected.add(createTimingSession(start, 10 * SECOND_IN_MILLIS, 1));
-        setProcessState(ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE);
+        setProcessState(getProcessStateQuotaFreeThreshold());
         synchronized (mQuotaController.mLock) {
             mQuotaController.prepareForExecutionLocked(jobFg3);
         }
@@ -5935,7 +5986,7 @@
         }
         advanceElapsedClock(10 * SECOND_IN_MILLIS);
         expected.add(createTimingSession(start, 10 * SECOND_IN_MILLIS, 1));
-        setProcessState(ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE);
+        setProcessState(getProcessStateQuotaFreeThreshold());
         synchronized (mQuotaController.mLock) {
             mQuotaController.prepareForExecutionLocked(jobFg3);
         }
@@ -6056,7 +6107,7 @@
             mQuotaController.maybeStopTrackingJobLocked(jobBg1, jobBg1);
         }
         advanceElapsedClock(5 * SECOND_IN_MILLIS);
-        setProcessState(ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE);
+        setProcessState(getProcessStateQuotaFreeThreshold());
         synchronized (mQuotaController.mLock) {
             mQuotaController.prepareForExecutionLocked(jobFg1);
         }
@@ -6534,7 +6585,7 @@
 
         // App still in foreground so everything should be in quota.
         advanceElapsedClock(20 * SECOND_IN_MILLIS);
-        setProcessState(ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE);
+        setProcessState(getProcessStateQuotaFreeThreshold());
         assertTrue(jobTop2.isExpeditedQuotaApproved());
         assertTrue(jobFg.isExpeditedQuotaApproved());
         assertTrue(jobBg.isExpeditedQuotaApproved());
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/ApexManagerTest.java b/services/tests/mockingservicestests/src/com/android/server/pm/ApexManagerTest.java
index d08cdc7..769f071 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/ApexManagerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/ApexManagerTest.java
@@ -265,19 +265,19 @@
     }
 
     @Test
-    public void testSubmitStagedSession_throwRunTimeException() throws RemoteException {
+    public void testSubmitStagedSession_throwPackageManagerExceptionOnRemoteException()
+             throws RemoteException {
         doThrow(RemoteException.class).when(mApexService).submitStagedSession(any(), any());
 
-        assertThrows(RuntimeException.class,
+        assertThrows(PackageManagerException.class,
                 () -> mApexManager.submitStagedSession(testParamsWithChildren()));
     }
 
     @Test
-    public void testGetStagedApexInfos_throwRunTimeException() throws RemoteException {
+    public void testGetStagedApexInfos_returnsEmptyOnRemoteException() throws RemoteException {
         doThrow(RemoteException.class).when(mApexService).getStagedApexInfos(any());
 
-        assertThrows(RuntimeException.class,
-                () -> mApexManager.getStagedApexInfos(testParamsWithChildren()));
+        assertThat(mApexManager.getStagedApexInfos(testParamsWithChildren())).hasLength(0);
     }
 
     @Test
@@ -298,10 +298,11 @@
     }
 
     @Test
-    public void testMarkStagedSessionReady_throwRunTimeException() throws RemoteException {
+    public void testMarkStagedSessionReady_throwPackageManagerExceptionOnRemoteException()
+            throws RemoteException {
         doThrow(RemoteException.class).when(mApexService).markStagedSessionReady(anyInt());
 
-        assertThrows(RuntimeException.class,
+        assertThrows(PackageManagerException.class,
                 () -> mApexManager.markStagedSessionReady(TEST_SESSION_ID));
     }
 
diff --git a/services/tests/mockingservicestests/src/com/android/server/wallpaper/WallpaperManagerServiceTests.java b/services/tests/mockingservicestests/src/com/android/server/wallpaper/WallpaperManagerServiceTests.java
index 9983fb4..c099517 100644
--- a/services/tests/mockingservicestests/src/com/android/server/wallpaper/WallpaperManagerServiceTests.java
+++ b/services/tests/mockingservicestests/src/com/android/server/wallpaper/WallpaperManagerServiceTests.java
@@ -506,6 +506,7 @@
     }
 
     @Test
+    @Ignore("b/372942682")
     public void testWallpaperManagerCallbackInRightOrder() throws RemoteException {
         WallpaperData wallpaper = new WallpaperData(USER_SYSTEM, FLAG_SYSTEM);
         wallpaper.primaryColors = new WallpaperColors(Color.valueOf(Color.RED),
diff --git a/services/tests/powerstatstests/Android.bp b/services/tests/powerstatstests/Android.bp
index d6ca10a..d9e071f 100644
--- a/services/tests/powerstatstests/Android.bp
+++ b/services/tests/powerstatstests/Android.bp
@@ -27,6 +27,9 @@
         "servicestests-utils",
         "platform-test-annotations",
         "flag-junit",
+        "statsdprotolite",
+        "StatsdTestUtils",
+        "platformprotoslite",
     ],
 
     libs: [
@@ -74,6 +77,10 @@
         "src/com/android/server/power/stats/format/*.java",
         "src/com/android/server/power/stats/processor/*.java",
     ],
+    // TODO(b/372292543): Enable this test.
+    exclude_srcs: [
+        "src/com/android/server/power/stats/WakelockStatsFrameworkEventsTest.java",
+    ],
     java_resources: [
         "res/xml/power_profile*.xml",
     ],
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsImplTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsImplTest.java
index c037f97..2408cc1 100644
--- a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsImplTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsImplTest.java
@@ -54,6 +54,8 @@
 import android.os.Parcel;
 import android.os.WakeLockStats;
 import android.os.WorkSource;
+import android.platform.test.annotations.EnableFlags;
+import android.platform.test.flag.junit.SetFlagsRule;
 import android.platform.test.ravenwood.RavenwoodRule;
 import android.util.SparseArray;
 import android.view.Display;
@@ -66,6 +68,7 @@
 import com.android.internal.os.KernelSingleUidTimeReader;
 import com.android.internal.os.LongArrayMultiStateCounter;
 import com.android.internal.os.PowerProfile;
+import com.android.server.power.feature.flags.Flags;
 
 import com.google.common.collect.ImmutableList;
 import com.google.common.truth.LongSubject;
@@ -86,11 +89,16 @@
 @RunWith(AndroidJUnit4.class)
 @SuppressWarnings("GuardedBy")
 public class BatteryStatsImplTest {
-    @Rule
+    @Rule(order = 0)
     public final RavenwoodRule mRavenwood = new RavenwoodRule.Builder()
             .setProvideMainThread(true)
+            .setSystemPropertyImmutable("persist.sys.com.android.server.power.feature.flags."
+                + "framework_wakelock_info-override", null)
             .build();
 
+    @Rule(order = 1)
+    public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+
     @Mock
     private KernelCpuUidFreqTimeReader mKernelUidCpuFreqTimeReader;
     @Mock
@@ -572,6 +580,7 @@
     }
 
     @Test
+    @EnableFlags(Flags.FLAG_FRAMEWORK_WAKELOCK_INFO)
     public void testGetWakeLockStats() {
         mBatteryStatsImpl.updateTimeBasesLocked(true, Display.STATE_OFF, 0, 0);
 
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsNoteTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsNoteTest.java
index 2ccb642..69579d6 100644
--- a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsNoteTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsNoteTest.java
@@ -91,9 +91,14 @@
 public class BatteryStatsNoteTest {
 
     @Rule
-    public final RavenwoodRule mRavenwood = new RavenwoodRule.Builder()
-            .setProvideMainThread(true)
-            .build();
+    public final RavenwoodRule mRavenwood =
+            new RavenwoodRule.Builder()
+                    .setProvideMainThread(true)
+                    .setSystemPropertyImmutable(
+                            "persist.sys.com.android.server.power.feature.flags."
+                                    + "framework_wakelock_info-override",
+                            null)
+                    .build();
 
     @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
 
@@ -192,6 +197,7 @@
      * Test BatteryStatsImpl.Uid.noteStartWakeLocked.
      */
     @Test
+    @EnableFlags(com.android.server.power.feature.flags.Flags.FLAG_FRAMEWORK_WAKELOCK_INFO)
     public void testNoteStartWakeLocked() throws Exception {
         final MockClock clocks = new MockClock(); // holds realtime and uptime in ms
         MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clocks);
@@ -222,6 +228,7 @@
      * Test BatteryStatsImpl.Uid.noteStartWakeLocked for an isolated uid.
      */
     @Test
+    @EnableFlags(com.android.server.power.feature.flags.Flags.FLAG_FRAMEWORK_WAKELOCK_INFO)
     public void testNoteStartWakeLocked_isolatedUid() throws Exception {
         final MockClock clocks = new MockClock(); // holds realtime and uptime in ms
         PowerStatsUidResolver uidResolver = new PowerStatsUidResolver();
@@ -264,6 +271,7 @@
      * isolated uid is removed from batterystats before the wakelock has been stopped.
      */
     @Test
+    @EnableFlags(com.android.server.power.feature.flags.Flags.FLAG_FRAMEWORK_WAKELOCK_INFO)
     public void testNoteStartWakeLocked_isolatedUidRace() throws Exception {
         final MockClock clocks = new MockClock(); // holds realtime and uptime in ms
         PowerStatsUidResolver uidResolver = new PowerStatsUidResolver();
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/WakelockPowerCalculatorTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/WakelockPowerCalculatorTest.java
index 5b7762d..9645e90 100644
--- a/services/tests/powerstatstests/src/com/android/server/power/stats/WakelockPowerCalculatorTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/WakelockPowerCalculatorTest.java
@@ -23,12 +23,15 @@
 import android.os.Process;
 import android.os.UidBatteryConsumer;
 import android.os.WorkSource;
+import android.platform.test.annotations.EnableFlags;
+import android.platform.test.flag.junit.SetFlagsRule;
 import android.platform.test.ravenwood.RavenwoodRule;
 
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.internal.os.PowerProfile;
+import com.android.server.power.feature.flags.Flags;
 
 import org.junit.Rule;
 import org.junit.Test;
@@ -38,20 +41,29 @@
 @SmallTest
 public class WakelockPowerCalculatorTest {
     @Rule(order = 0)
-    public final RavenwoodRule mRavenwood = new RavenwoodRule.Builder()
-            .setProvideMainThread(true)
-            .build();
+    public final RavenwoodRule mRavenwood =
+            new RavenwoodRule.Builder()
+                    .setProvideMainThread(true)
+                    .setSystemPropertyImmutable(
+                            "persist.sys.com.android.server.power.feature.flags."
+                                    + "framework_wakelock_info-override",
+                            null)
+                    .build();
+
+    @Rule(order = 1)
+    public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
 
     private static final double PRECISION = 0.00001;
 
     private static final int APP_UID = Process.FIRST_APPLICATION_UID + 42;
     private static final int APP_PID = 3145;
 
-    @Rule(order = 1)
-    public final BatteryUsageStatsRule mStatsRule = new BatteryUsageStatsRule()
-            .setAveragePower(PowerProfile.POWER_CPU_IDLE, 360.0);
+    @Rule(order = 2)
+    public final BatteryUsageStatsRule mStatsRule =
+            new BatteryUsageStatsRule().setAveragePower(PowerProfile.POWER_CPU_IDLE, 360.0);
 
     @Test
+    @EnableFlags(Flags.FLAG_FRAMEWORK_WAKELOCK_INFO)
     public void testTimerBasedModel() {
         mStatsRule.getUidStats(Process.ROOT_UID);
 
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/WakelockPowerStatsCollectorTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/WakelockPowerStatsCollectorTest.java
index dd5df76..cef3fdd 100644
--- a/services/tests/powerstatstests/src/com/android/server/power/stats/WakelockPowerStatsCollectorTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/WakelockPowerStatsCollectorTest.java
@@ -24,10 +24,14 @@
 
 import android.content.Context;
 import android.os.Process;
+import android.platform.test.annotations.DisableFlags;
+import android.platform.test.annotations.DisabledOnRavenwood;
+import android.platform.test.flag.junit.SetFlagsRule;
 import android.platform.test.ravenwood.RavenwoodConfig;
 import android.platform.test.ravenwood.RavenwoodConfig.Config;
 
 import com.android.internal.os.PowerStats;
+import com.android.server.power.feature.flags.Flags;
 import com.android.server.power.stats.format.WakelockPowerStatsLayout;
 
 import org.junit.Before;
@@ -37,11 +41,19 @@
 public class WakelockPowerStatsCollectorTest {
 
     @Config
-    public static final RavenwoodConfig sConfig = new RavenwoodConfig.Builder()
-            .setProvideMainThread(true)
-            .build();
+    public static final RavenwoodConfig sConfig =
+            new RavenwoodConfig.Builder()
+                    .setProvideMainThread(true)
+                    .setSystemPropertyImmutable(
+                            "persist.sys.com.android.server.power.feature.flags."
+                                    + "framework_wakelock_info-override",
+                            null)
+                    .build();
 
-    @Rule
+    @Rule(order = 0)
+    public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+
+    @Rule(order = 1)
     public final BatteryUsageStatsRule mStatsRule = new BatteryUsageStatsRule();
 
     private static final int APP_UID1 = Process.FIRST_APPLICATION_UID + 42;
@@ -63,6 +75,8 @@
     }
 
     @Test
+    @DisableFlags(Flags.FLAG_FRAMEWORK_WAKELOCK_INFO)
+    @DisabledOnRavenwood(reason = "b/372292543 temporary disable")
     public void collectStats() {
         PowerStatsCollector powerStatsCollector = mBatteryStats.getPowerStatsCollector(
                 POWER_COMPONENT_WAKELOCK);
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/WakelockStatsFrameworkEventsTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/WakelockStatsFrameworkEventsTest.java
new file mode 100644
index 0000000..cb644db
--- /dev/null
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/WakelockStatsFrameworkEventsTest.java
@@ -0,0 +1,433 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.power.stats;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.os.WakeLockLevelEnum;
+import android.util.StatsEvent;
+import android.util.StatsEventTestUtils;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.os.AtomsProto;
+import com.android.os.framework.FrameworkExtensionAtoms;
+import com.android.os.framework.FrameworkExtensionAtoms.FrameworkWakelockInfo;
+
+import com.google.protobuf.CodedInputStream;
+import com.google.protobuf.CodedOutputStream;
+import com.google.protobuf.ExtensionRegistryLite;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.util.ArrayList;
+import java.util.List;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class WakelockStatsFrameworkEventsTest {
+    private WakelockStatsFrameworkEvents mEvents;
+    private ExtensionRegistryLite mRegistry;
+
+    @Before
+    public void setup() {
+        mEvents = new WakelockStatsFrameworkEvents();
+        mRegistry = ExtensionRegistryLite.newInstance();
+        FrameworkExtensionAtoms.registerAllExtensions(mRegistry);
+    }
+
+    private static final int UID_1 = 1;
+    private static final int UID_2 = 2;
+
+    private static final String TAG_1 = "TAG1";
+    private static final String TAG_2 = "TAG2";
+
+    private static final WakeLockLevelEnum WAKELOCK_TYPE_1 = WakeLockLevelEnum.PARTIAL_WAKE_LOCK;
+    private static final WakeLockLevelEnum WAKELOCK_TYPE_2 = WakeLockLevelEnum.DOZE_WAKE_LOCK;
+
+    private static final long TS_1 = 1000;
+    private static final long TS_2 = 2000;
+    private static final long TS_3 = 3000;
+    private static final long TS_4 = 4000;
+    private static final long TS_5 = 5000;
+
+    // Assumes that mEvents is empty.
+    private void makeMetricsAlmostOverflow() throws Exception {
+        for (int i = 0; i < mEvents.SUMMARY_THRESHOLD - 1; i++) {
+            String tag = "forceOverflow" + i;
+            mEvents.noteStartWakeLock(UID_1, tag, WAKELOCK_TYPE_1.getNumber(), TS_1);
+            mEvents.noteStopWakeLock(UID_1, tag, WAKELOCK_TYPE_1.getNumber(), TS_2);
+        }
+
+        assertFalse("not overflow", mEvents.inOverflow());
+        ArrayList<FrameworkWakelockInfo> info = pullResults(TS_4);
+        FrameworkWakelockInfo notOverflowInfo =
+                info.stream()
+                        .filter(i -> i.getAttributionTag().equals(mEvents.OVERFLOW_TAG))
+                        .findFirst()
+                        .orElse(null);
+
+        assertEquals("not overflow", notOverflowInfo, null);
+
+        // Add one more to hit an overflow state.
+        String lastTag = "forceOverflowLast";
+        mEvents.noteStartWakeLock(UID_1, lastTag, WAKELOCK_TYPE_2.getNumber(), TS_1);
+        mEvents.noteStopWakeLock(UID_1, lastTag, WAKELOCK_TYPE_2.getNumber(), TS_2);
+
+        assertTrue("overflow", mEvents.inOverflow());
+        info = pullResults(TS_4);
+
+        FrameworkWakelockInfo tag1Info =
+                info.stream()
+                        .filter(i -> i.getAttributionTag().equals(lastTag))
+                        .findFirst()
+                        .orElse(null);
+
+        assertTrue("lastTag found", tag1Info != null);
+        assertEquals("uid", UID_1, tag1Info.getAttributionUid());
+        assertEquals("tag", lastTag, tag1Info.getAttributionTag());
+        assertEquals("type", WAKELOCK_TYPE_2, tag1Info.getType());
+        assertEquals("duration", TS_2 - TS_1, tag1Info.getUptimeMillis());
+        assertEquals("count", 1, tag1Info.getCompletedCount());
+    }
+
+    // Assumes that mEvents is empty.
+    private void makeMetricsAlmostHardCap() throws Exception {
+        for (int i = 0; i < mEvents.MAX_WAKELOCK_DIMENSIONS - 1; i++) {
+            mEvents.noteStartWakeLock(i /* uid */, TAG_1, WAKELOCK_TYPE_1.getNumber(), TS_1);
+            mEvents.noteStopWakeLock(i /* uid */, TAG_1, WAKELOCK_TYPE_1.getNumber(), TS_2);
+        }
+
+        assertFalse("not hard capped", mEvents.inHardCap());
+        ArrayList<FrameworkWakelockInfo> info = pullResults(TS_4);
+        FrameworkWakelockInfo notOverflowInfo =
+                info.stream()
+                        .filter(i -> i.getAttributionTag().equals(mEvents.HARD_CAP_TAG))
+                        .findFirst()
+                        .orElse(null);
+
+        assertEquals("not overflow", notOverflowInfo, null);
+
+        // Add one more to hit an hardcap state.
+        int hardCapUid = mEvents.MAX_WAKELOCK_DIMENSIONS;
+        mEvents.noteStartWakeLock(hardCapUid, TAG_2, WAKELOCK_TYPE_2.getNumber(), TS_1);
+        mEvents.noteStopWakeLock(hardCapUid, TAG_2, WAKELOCK_TYPE_2.getNumber(), TS_2);
+
+        assertTrue("hard capped", mEvents.inHardCap());
+        info = pullResults(TS_4);
+
+        FrameworkWakelockInfo tag2Info =
+                info.stream()
+                        .filter(i -> i.getAttributionUid() == hardCapUid)
+                        .findFirst()
+                        .orElse(null);
+
+        assertTrue("hardCapUid found", tag2Info != null);
+        assertEquals("uid", hardCapUid, tag2Info.getAttributionUid());
+        assertEquals("tag", mEvents.OVERFLOW_TAG, tag2Info.getAttributionTag());
+        assertEquals(
+                "type", WakeLockLevelEnum.forNumber(mEvents.OVERFLOW_LEVEL), tag2Info.getType());
+        assertEquals("duration", TS_2 - TS_1, tag2Info.getUptimeMillis());
+        assertEquals("count", 1, tag2Info.getCompletedCount());
+    }
+
+    private ArrayList<FrameworkWakelockInfo> pullResults(long timestamp) throws Exception {
+        ArrayList<FrameworkWakelockInfo> result = new ArrayList<>();
+        List<StatsEvent> events = mEvents.pullFrameworkWakelockInfoAtoms(timestamp);
+
+        for (StatsEvent e : events) {
+            // The returned atom does not have external extensions registered.
+            // So we serialize and then deserialize with extensions registered.
+            AtomsProto.Atom atom = StatsEventTestUtils.convertToAtom(e);
+
+            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+            CodedOutputStream codedos = CodedOutputStream.newInstance(outputStream);
+            atom.writeTo(codedos);
+            codedos.flush();
+
+            ByteArrayInputStream inputStream = new ByteArrayInputStream(outputStream.toByteArray());
+            CodedInputStream codedis = CodedInputStream.newInstance(inputStream);
+            AtomsProto.Atom atomWithExtensions = AtomsProto.Atom.parseFrom(codedis, mRegistry);
+
+            assertTrue(
+                    atomWithExtensions.hasExtension(FrameworkExtensionAtoms.frameworkWakelockInfo));
+            FrameworkWakelockInfo info =
+                    atomWithExtensions.getExtension(FrameworkExtensionAtoms.frameworkWakelockInfo);
+            result.add(info);
+        }
+
+        return result;
+    }
+
+    @Test
+    public void singleWakelock() throws Exception {
+        mEvents.noteStartWakeLock(UID_1, TAG_1, WAKELOCK_TYPE_1.getNumber(), TS_1);
+        mEvents.noteStopWakeLock(UID_1, TAG_1, WAKELOCK_TYPE_1.getNumber(), TS_2);
+
+        ArrayList<FrameworkWakelockInfo> info = pullResults(TS_3);
+
+        assertEquals("size", 1, info.size());
+        assertEquals("uid", UID_1, info.get(0).getAttributionUid());
+        assertEquals("tag", TAG_1, info.get(0).getAttributionTag());
+        assertEquals("type", WAKELOCK_TYPE_1, info.get(0).getType());
+        assertEquals("duration", TS_2 - TS_1, info.get(0).getUptimeMillis());
+        assertEquals("count", 1, info.get(0).getCompletedCount());
+    }
+
+    @Test
+    public void wakelockOpen() throws Exception {
+        mEvents.noteStartWakeLock(UID_1, TAG_1, WAKELOCK_TYPE_1.getNumber(), TS_1);
+
+        ArrayList<FrameworkWakelockInfo> info = pullResults(TS_3);
+
+        assertEquals("size", 1, info.size());
+        assertEquals("uid", UID_1, info.get(0).getAttributionUid());
+        assertEquals("tag", TAG_1, info.get(0).getAttributionTag());
+        assertEquals("type", WAKELOCK_TYPE_1, info.get(0).getType());
+        assertEquals("duration", TS_3 - TS_1, info.get(0).getUptimeMillis());
+        assertEquals("count", 0, info.get(0).getCompletedCount());
+    }
+
+    @Test
+    public void wakelockOpenOverlap() throws Exception {
+        mEvents.noteStartWakeLock(UID_1, TAG_1, WAKELOCK_TYPE_1.getNumber(), TS_1);
+        mEvents.noteStartWakeLock(UID_1, TAG_1, WAKELOCK_TYPE_1.getNumber(), TS_2);
+        mEvents.noteStopWakeLock(UID_1, TAG_1, WAKELOCK_TYPE_1.getNumber(), TS_3);
+
+        ArrayList<FrameworkWakelockInfo> info = pullResults(TS_4);
+
+        assertEquals("size", 1, info.size());
+        assertEquals("uid", UID_1, info.get(0).getAttributionUid());
+        assertEquals("tag", TAG_1, info.get(0).getAttributionTag());
+        assertEquals("type", WAKELOCK_TYPE_1, info.get(0).getType());
+        assertEquals("duration", TS_4 - TS_1, info.get(0).getUptimeMillis());
+        assertEquals("count", 0, info.get(0).getCompletedCount());
+    }
+
+    @Test
+    public void testOverflow() throws Exception {
+        makeMetricsAlmostOverflow();
+
+        // This one gets tagged as an overflow.
+        mEvents.noteStartWakeLock(UID_1, TAG_2, WAKELOCK_TYPE_2.getNumber(), TS_1);
+        mEvents.noteStopWakeLock(UID_1, TAG_2, WAKELOCK_TYPE_2.getNumber(), TS_2);
+
+        ArrayList<FrameworkWakelockInfo> info = pullResults(TS_4);
+        FrameworkWakelockInfo overflowInfo =
+                info.stream()
+                        .filter(i -> i.getAttributionTag().equals(mEvents.OVERFLOW_TAG))
+                        .findFirst()
+                        .orElse(null);
+
+        assertEquals("uid", UID_1, overflowInfo.getAttributionUid());
+        assertEquals(
+                "type",
+                WakeLockLevelEnum.forNumber(mEvents.OVERFLOW_LEVEL),
+                overflowInfo.getType());
+        assertEquals("duration", TS_2 - TS_1, overflowInfo.getUptimeMillis());
+        assertEquals("count", 1, overflowInfo.getCompletedCount());
+    }
+
+    @Test
+    public void testOverflowOpen() throws Exception {
+        makeMetricsAlmostOverflow();
+
+        // This is the open wakelock that overflows.
+        mEvents.noteStartWakeLock(UID_1, TAG_2, WAKELOCK_TYPE_2.getNumber(), TS_1);
+
+        ArrayList<FrameworkWakelockInfo> info = pullResults(TS_4);
+        FrameworkWakelockInfo overflowInfo =
+                info.stream()
+                        .filter(i -> i.getAttributionTag().equals(mEvents.OVERFLOW_TAG))
+                        .findFirst()
+                        .orElse(null);
+
+        assertEquals("uid", UID_1, overflowInfo.getAttributionUid());
+        assertEquals(
+                "type",
+                WakeLockLevelEnum.forNumber(mEvents.OVERFLOW_LEVEL),
+                overflowInfo.getType());
+        assertEquals("duration", (TS_4 - TS_1), overflowInfo.getUptimeMillis());
+        assertEquals("count", 0, overflowInfo.getCompletedCount());
+    }
+
+    @Test
+    public void testHardCap() throws Exception {
+        makeMetricsAlmostHardCap();
+
+        // This one gets tagged as a hard cap.
+        mEvents.noteStartWakeLock(UID_1, TAG_2, WAKELOCK_TYPE_2.getNumber(), TS_1);
+        mEvents.noteStopWakeLock(UID_1, TAG_2, WAKELOCK_TYPE_2.getNumber(), TS_2);
+
+        ArrayList<FrameworkWakelockInfo> info = pullResults(TS_4);
+        FrameworkWakelockInfo hardCapInfo =
+                info.stream()
+                        .filter(i -> i.getAttributionTag().equals(mEvents.HARD_CAP_TAG))
+                        .findFirst()
+                        .orElse(null);
+
+        assertEquals("uid", mEvents.HARD_CAP_UID, hardCapInfo.getAttributionUid());
+        assertEquals(
+                "type",
+                WakeLockLevelEnum.forNumber(mEvents.OVERFLOW_LEVEL),
+                hardCapInfo.getType());
+        assertEquals("duration", TS_2 - TS_1, hardCapInfo.getUptimeMillis());
+        assertEquals("count", 1, hardCapInfo.getCompletedCount());
+    }
+
+    @Test
+    public void testHardCapOpen() throws Exception {
+        makeMetricsAlmostHardCap();
+
+        // This is the open wakelock that overflows.
+        mEvents.noteStartWakeLock(UID_1, TAG_2, WAKELOCK_TYPE_2.getNumber(), TS_1);
+
+        ArrayList<FrameworkWakelockInfo> info = pullResults(TS_4);
+        FrameworkWakelockInfo hardCapInfo =
+                info.stream()
+                        .filter(i -> i.getAttributionTag().equals(mEvents.HARD_CAP_TAG))
+                        .findFirst()
+                        .orElse(null);
+
+        assertEquals("uid", mEvents.HARD_CAP_UID, hardCapInfo.getAttributionUid());
+        assertEquals(
+                "type",
+                WakeLockLevelEnum.forNumber(mEvents.OVERFLOW_LEVEL),
+                hardCapInfo.getType());
+        assertEquals("duration", (TS_4 - TS_1), hardCapInfo.getUptimeMillis());
+        assertEquals("count", 0, hardCapInfo.getCompletedCount());
+    }
+
+    @Test
+    public void overlappingWakelocks() throws Exception {
+        mEvents.noteStartWakeLock(UID_1, TAG_1, WAKELOCK_TYPE_1.getNumber(), TS_1);
+        mEvents.noteStartWakeLock(UID_1, TAG_1, WAKELOCK_TYPE_1.getNumber(), TS_2);
+        mEvents.noteStopWakeLock(UID_1, TAG_1, WAKELOCK_TYPE_1.getNumber(), TS_3);
+        mEvents.noteStopWakeLock(UID_1, TAG_1, WAKELOCK_TYPE_1.getNumber(), TS_4);
+
+        ArrayList<FrameworkWakelockInfo> info = pullResults(TS_5);
+
+        assertEquals("size", 1, info.size());
+        assertEquals("uid", UID_1, info.get(0).getAttributionUid());
+        assertEquals("tag", TAG_1, info.get(0).getAttributionTag());
+        assertEquals("type", WAKELOCK_TYPE_1, info.get(0).getType());
+        assertEquals("duration", TS_4 - TS_1, info.get(0).getUptimeMillis());
+        assertEquals("count", 1, info.get(0).getCompletedCount());
+    }
+
+    @Test
+    public void diffUid() throws Exception {
+        mEvents.noteStartWakeLock(UID_1, TAG_1, WAKELOCK_TYPE_1.getNumber(), TS_1);
+        mEvents.noteStartWakeLock(UID_2, TAG_1, WAKELOCK_TYPE_1.getNumber(), TS_2);
+        mEvents.noteStopWakeLock(UID_2, TAG_1, WAKELOCK_TYPE_1.getNumber(), TS_3);
+        mEvents.noteStopWakeLock(UID_1, TAG_1, WAKELOCK_TYPE_1.getNumber(), TS_4);
+
+        ArrayList<FrameworkWakelockInfo> info = pullResults(TS_5);
+        assertEquals("size", 2, info.size());
+
+        FrameworkWakelockInfo uid1Info =
+                info.stream().filter(i -> i.getAttributionUid() == UID_1).findFirst().orElse(null);
+
+        assertTrue("UID_1 found", uid1Info != null);
+        assertEquals("uid", UID_1, uid1Info.getAttributionUid());
+        assertEquals("tag", TAG_1, uid1Info.getAttributionTag());
+        assertEquals("type", WAKELOCK_TYPE_1, uid1Info.getType());
+        assertEquals("duration", TS_4 - TS_1, uid1Info.getUptimeMillis());
+        assertEquals("count", 1, uid1Info.getCompletedCount());
+
+        FrameworkWakelockInfo uid2Info =
+                info.stream().filter(i -> i.getAttributionUid() == UID_2).findFirst().orElse(null);
+        assertTrue("UID_2 found", uid2Info != null);
+        assertEquals("uid", UID_2, uid2Info.getAttributionUid());
+        assertEquals("tag", TAG_1, uid2Info.getAttributionTag());
+        assertEquals("type", WAKELOCK_TYPE_1, uid2Info.getType());
+        assertEquals("duration", TS_3 - TS_2, uid2Info.getUptimeMillis());
+        assertEquals("count", 1, uid2Info.getCompletedCount());
+    }
+
+    @Test
+    public void diffTag() throws Exception {
+        mEvents.noteStartWakeLock(UID_1, TAG_1, WAKELOCK_TYPE_1.getNumber(), TS_1);
+        mEvents.noteStartWakeLock(UID_1, TAG_2, WAKELOCK_TYPE_1.getNumber(), TS_2);
+        mEvents.noteStopWakeLock(UID_1, TAG_2, WAKELOCK_TYPE_1.getNumber(), TS_3);
+        mEvents.noteStopWakeLock(UID_1, TAG_1, WAKELOCK_TYPE_1.getNumber(), TS_4);
+
+        ArrayList<FrameworkWakelockInfo> info = pullResults(TS_5);
+        assertEquals("size", 2, info.size());
+
+        FrameworkWakelockInfo uid1Info =
+                info.stream()
+                        .filter(i -> i.getAttributionTag().equals(TAG_1))
+                        .findFirst()
+                        .orElse(null);
+
+        assertTrue("TAG_1 found", uid1Info != null);
+        assertEquals("uid", UID_1, uid1Info.getAttributionUid());
+        assertEquals("tag", TAG_1, uid1Info.getAttributionTag());
+        assertEquals("type", WAKELOCK_TYPE_1, uid1Info.getType());
+        assertEquals("duration", TS_4 - TS_1, uid1Info.getUptimeMillis());
+        assertEquals("count", 1, uid1Info.getCompletedCount());
+
+        FrameworkWakelockInfo uid2Info =
+                info.stream()
+                        .filter(i -> i.getAttributionTag().equals(TAG_2))
+                        .findFirst()
+                        .orElse(null);
+        assertTrue("TAG_2 found", uid2Info != null);
+        assertEquals("uid", UID_1, uid2Info.getAttributionUid());
+        assertEquals("tag", TAG_2, uid2Info.getAttributionTag());
+        assertEquals("type", WAKELOCK_TYPE_1, uid2Info.getType());
+        assertEquals("duration", TS_3 - TS_2, uid2Info.getUptimeMillis());
+        assertEquals("count", 1, uid2Info.getCompletedCount());
+    }
+
+    @Test
+    public void diffType() throws Exception {
+        mEvents.noteStartWakeLock(UID_1, TAG_1, WAKELOCK_TYPE_1.getNumber(), TS_1);
+        mEvents.noteStartWakeLock(UID_1, TAG_1, WAKELOCK_TYPE_2.getNumber(), TS_2);
+        mEvents.noteStopWakeLock(UID_1, TAG_1, WAKELOCK_TYPE_2.getNumber(), TS_3);
+        mEvents.noteStopWakeLock(UID_1, TAG_1, WAKELOCK_TYPE_1.getNumber(), TS_4);
+
+        ArrayList<FrameworkWakelockInfo> info = pullResults(TS_5);
+        assertEquals("size", 2, info.size());
+
+        FrameworkWakelockInfo uid1Info =
+                info.stream().filter(i -> i.getType() == WAKELOCK_TYPE_1).findFirst().orElse(null);
+
+        assertTrue("WAKELOCK_TYPE_1 found", uid1Info != null);
+        assertEquals("uid", UID_1, uid1Info.getAttributionUid());
+        assertEquals("tag", TAG_1, uid1Info.getAttributionTag());
+        assertEquals("type", WAKELOCK_TYPE_1, uid1Info.getType());
+        assertEquals("duration", TS_4 - TS_1, uid1Info.getUptimeMillis());
+        assertEquals("count", 1, uid1Info.getCompletedCount());
+
+        FrameworkWakelockInfo uid2Info =
+                info.stream().filter(i -> i.getType() == WAKELOCK_TYPE_2).findFirst().orElse(null);
+        assertTrue("WAKELOCK_TYPE_2 found", uid2Info != null);
+        assertEquals("uid", UID_1, uid2Info.getAttributionUid());
+        assertEquals("tag", TAG_1, uid2Info.getAttributionTag());
+        assertEquals("type", WAKELOCK_TYPE_2, uid2Info.getType());
+        assertEquals("duration", TS_3 - TS_2, uid2Info.getUptimeMillis());
+        assertEquals("count", 1, uid2Info.getCompletedCount());
+    }
+}
diff --git a/services/tests/servicestests/Android.bp b/services/tests/servicestests/Android.bp
index 6ede334..359755a 100644
--- a/services/tests/servicestests/Android.bp
+++ b/services/tests/servicestests/Android.bp
@@ -67,6 +67,7 @@
         "androidx.test.ext.junit",
         "cts-wm-util",
         "platform-compat-test-rules",
+        "platform-parametric-runner-lib",
         "mockito-target-minus-junit4",
         "mockito-kotlin2",
         "platform-test-annotations",
diff --git a/services/tests/servicestests/AndroidManifest.xml b/services/tests/servicestests/AndroidManifest.xml
index 2724149..c645c08 100644
--- a/services/tests/servicestests/AndroidManifest.xml
+++ b/services/tests/servicestests/AndroidManifest.xml
@@ -113,6 +113,7 @@
     <uses-permission android:name="android.permission.MANAGE_ROLE_HOLDERS" />
     <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
     <uses-permission android:name="android.permission.CAMERA" />
+    <uses-permission android:name="android.permission.CREATE_VIRTUAL_DEVICE" />
 
     <queries>
         <package android:name="com.android.servicestests.apps.suspendtestapp" />
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/MouseKeysInterceptorTest.kt b/services/tests/servicestests/src/com/android/server/accessibility/MouseKeysInterceptorTest.kt
index c76392b..5134737 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/MouseKeysInterceptorTest.kt
+++ b/services/tests/servicestests/src/com/android/server/accessibility/MouseKeysInterceptorTest.kt
@@ -236,6 +236,27 @@
     }
 
     @Test
+    fun whenScrollToggleOn_ScrollRightKeyIsPressed_scrollEventIsSent() {
+        // There should be some delay between the downTime of the key event and calling onKeyEvent
+        val downTime = clock.now() - KEYBOARD_POST_EVENT_DELAY_MILLIS
+        val keyCodeScrollToggle = MouseKeysInterceptor.MouseKeyEvent.SCROLL_TOGGLE.keyCodeValue
+        val keyCodeScroll = MouseKeysInterceptor.MouseKeyEvent.RIGHT_MOVE_OR_SCROLL.keyCodeValue
+
+        val scrollToggleDownEvent = KeyEvent(downTime, downTime, KeyEvent.ACTION_DOWN,
+            keyCodeScrollToggle, 0, 0, DEVICE_ID, 0)
+        val scrollDownEvent = KeyEvent(downTime, downTime, KeyEvent.ACTION_DOWN,
+            keyCodeScroll, 0, 0, DEVICE_ID, 0)
+
+        mouseKeysInterceptor.onKeyEvent(scrollToggleDownEvent, 0)
+        mouseKeysInterceptor.onKeyEvent(scrollDownEvent, 0)
+        testLooper.dispatchAll()
+
+        // Verify the sendScrollEvent method is called once and capture the arguments
+        verifyScrollEvents(arrayOf<Float>(-MouseKeysInterceptor.MOUSE_SCROLL_STEP),
+	    arrayOf<Float>(0f))
+    }
+
+    @Test
     fun whenScrollToggleOff_DirectionalUpKeyIsPressed_RelativeEventIsSent() {
         // There should be some delay between the downTime of the key event and calling onKeyEvent
         val downTime = clock.now() - KEYBOARD_POST_EVENT_DELAY_MILLIS
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationConnectionManagerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationConnectionManagerTest.java
index 6aa8a32..06ebe6e 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationConnectionManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationConnectionManagerTest.java
@@ -62,6 +62,7 @@
 import com.android.internal.util.test.FakeSettingsProvider;
 import com.android.server.LocalServices;
 import com.android.server.accessibility.AccessibilityTraceManager;
+import com.android.server.pm.UserManagerInternal;
 import com.android.server.statusbar.StatusBarManagerInternal;
 
 import org.junit.Before;
@@ -92,12 +93,16 @@
     private MagnificationConnectionManager.Callback mMockCallback;
     private MockContentResolver mResolver;
     private MagnificationConnectionManager mMagnificationConnectionManager;
+    @Mock
+    private UserManagerInternal mMockUserManagerInternal;
 
     @Before
     public void setUp() throws RemoteException {
         MockitoAnnotations.initMocks(this);
         LocalServices.removeServiceForTest(StatusBarManagerInternal.class);
+        LocalServices.removeServiceForTest(UserManagerInternal.class);
         LocalServices.addService(StatusBarManagerInternal.class, mMockStatusBarManagerInternal);
+        LocalServices.addService(UserManagerInternal.class, mMockUserManagerInternal);
         mResolver = new MockContentResolver();
         mMockConnection = new MockMagnificationConnection();
         mMagnificationConnectionManager = new MagnificationConnectionManager(mContext, new Object(),
@@ -110,6 +115,8 @@
         Settings.Secure.putFloatForUser(mResolver,
                 Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE, 2.5f,
                 CURRENT_USER_ID);
+
+        when(mMockUserManagerInternal.isVisibleBackgroundFullUser(anyInt())).thenReturn(false);
     }
 
     private void stubSetConnection(boolean needDelay) {
diff --git a/services/tests/servicestests/src/com/android/server/am/OomAdjusterTests.java b/services/tests/servicestests/src/com/android/server/am/OomAdjusterTests.java
index 31bf5f0..4981ceb 100644
--- a/services/tests/servicestests/src/com/android/server/am/OomAdjusterTests.java
+++ b/services/tests/servicestests/src/com/android/server/am/OomAdjusterTests.java
@@ -61,6 +61,7 @@
     private static final long USAGE_STATS_INTERACTION = 10 * 60 * 1000L;
     private static final long SERVICE_USAGE_INTERACTION = 60 * 1000;
 
+    @SuppressWarnings("GuardedBy")
     @BeforeClass
     public static void setUpOnce() {
         sContext = getInstrumentation().getTargetContext();
@@ -92,8 +93,11 @@
                     return true;
                 }
             };
-            sService.mOomAdjuster = new OomAdjuster(sService, sService.mProcessList, null,
-                    injector);
+            sService.mProcessStateController = new ProcessStateController.Builder(sService,
+                    sService.mProcessList, null)
+                    .setOomAdjusterInjector(injector)
+                    .build();
+            sService.mOomAdjuster = sService.mProcessStateController.getOomAdjuster();
             LocalServices.addService(UsageStatsManagerInternal.class,
                     mock(UsageStatsManagerInternal.class));
             sService.mUsageStatsService = LocalServices.getService(UsageStatsManagerInternal.class);
diff --git a/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java b/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java
index 390eb93..2fe6918 100644
--- a/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java
@@ -181,12 +181,14 @@
             Intent.ACTION_USER_STARTING);
 
     private static final Set<Integer> START_FOREGROUND_USER_MESSAGE_CODES = newHashSet(
+            0, // for startUserInternalOnHandler
             REPORT_USER_SWITCH_MSG,
             USER_SWITCH_TIMEOUT_MSG,
             USER_START_MSG,
             USER_CURRENT_MSG);
 
     private static final Set<Integer> START_BACKGROUND_USER_MESSAGE_CODES = newHashSet(
+            0, // for startUserInternalOnHandler
             USER_START_MSG,
             REPORT_LOCKED_BOOT_COMPLETE_MSG);
 
@@ -374,7 +376,7 @@
         // and the cascade effect goes on...). In fact, a better approach would to not assert the
         // binder calls, but their side effects (in this case, that the user is stopped right away)
         assertWithMessage("wrong binder message calls").that(mInjector.mHandler.getMessageCodes())
-                .containsExactly(USER_START_MSG);
+                .containsExactly(/* for startUserInternalOnHandler */ 0, USER_START_MSG);
     }
 
     private void startUserAssertions(
diff --git a/services/tests/servicestests/src/com/android/server/appop/AppOpsActiveWatcherTest.java b/services/tests/servicestests/src/com/android/server/appop/AppOpsActiveWatcherTest.java
index c970a3e..840e5c5 100644
--- a/services/tests/servicestests/src/com/android/server/appop/AppOpsActiveWatcherTest.java
+++ b/services/tests/servicestests/src/com/android/server/appop/AppOpsActiveWatcherTest.java
@@ -65,7 +65,6 @@
             VirtualDeviceRule.withAdditionalPermissions(
                     Manifest.permission.GRANT_RUNTIME_PERMISSIONS,
                     Manifest.permission.REVOKE_RUNTIME_PERMISSIONS,
-                    Manifest.permission.CREATE_VIRTUAL_DEVICE,
                     Manifest.permission.GET_APP_OPS_STATS
             );
     private static final long NOTIFICATION_TIMEOUT_MILLIS = 5000;
diff --git a/services/tests/servicestests/src/com/android/server/appop/AppOpsDeviceAwareServiceTest.java b/services/tests/servicestests/src/com/android/server/appop/AppOpsDeviceAwareServiceTest.java
index 7f2327aa..e3eca6d 100644
--- a/services/tests/servicestests/src/com/android/server/appop/AppOpsDeviceAwareServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/appop/AppOpsDeviceAwareServiceTest.java
@@ -58,7 +58,6 @@
             VirtualDeviceRule.withAdditionalPermissions(
                     Manifest.permission.GRANT_RUNTIME_PERMISSIONS,
                     Manifest.permission.REVOKE_RUNTIME_PERMISSIONS,
-                    Manifest.permission.CREATE_VIRTUAL_DEVICE,
                     Manifest.permission.GET_APP_OPS_STATS);
 
     private static final String ATTRIBUTION_TAG_1 = "attributionTag1";
diff --git a/services/tests/servicestests/src/com/android/server/appop/AppOpsNotedWatcherTest.java b/services/tests/servicestests/src/com/android/server/appop/AppOpsNotedWatcherTest.java
index 1abd4eb..b0846f6 100644
--- a/services/tests/servicestests/src/com/android/server/appop/AppOpsNotedWatcherTest.java
+++ b/services/tests/servicestests/src/com/android/server/appop/AppOpsNotedWatcherTest.java
@@ -22,16 +22,14 @@
 import static org.mockito.Mockito.timeout;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity;
 
 import android.app.AppOpsManager;
 import android.app.AppOpsManager.OnOpNotedListener;
 import android.companion.virtual.VirtualDeviceManager;
-import android.companion.virtual.VirtualDeviceParams;
 import android.content.AttributionSource;
 import android.content.Context;
 import android.os.Process;
-import android.virtualdevice.cts.common.FakeAssociationRule;
+import android.virtualdevice.cts.common.VirtualDeviceRule;
 
 import androidx.test.InstrumentationRegistry;
 import androidx.test.filters.SmallTest;
@@ -42,8 +40,6 @@
 import org.junit.runner.RunWith;
 import org.mockito.InOrder;
 
-import java.util.concurrent.atomic.AtomicInteger;
-
 /**
  * Tests watching noted ops.
  */
@@ -51,7 +47,7 @@
 @RunWith(AndroidJUnit4.class)
 public class AppOpsNotedWatcherTest {
     @Rule
-    public FakeAssociationRule mFakeAssociationRule = new FakeAssociationRule();
+    public VirtualDeviceRule mVirtualDeviceRule = VirtualDeviceRule.createDefault();
     private static final long NOTIFICATION_TIMEOUT_MILLIS = 5000;
 
     @Test
@@ -119,19 +115,12 @@
     public void testWatchNotedOpsForExternalDevice() {
         final AppOpsManager.OnOpNotedListener listener = mock(
                 AppOpsManager.OnOpNotedListener.class);
-        final VirtualDeviceManager virtualDeviceManager = getContext().getSystemService(
-                VirtualDeviceManager.class);
-        AtomicInteger virtualDeviceId = new AtomicInteger();
-        runWithShellPermissionIdentity(() -> {
-            final VirtualDeviceManager.VirtualDevice virtualDevice =
-                    virtualDeviceManager.createVirtualDevice(
-                            mFakeAssociationRule.getAssociationInfo().getId(),
-                            new VirtualDeviceParams.Builder().setName("virtual_device").build());
-            virtualDeviceId.set(virtualDevice.getDeviceId());
-        });
+        final VirtualDeviceManager.VirtualDevice virtualDevice =
+                mVirtualDeviceRule.createManagedVirtualDevice();
+        final int virtualDeviceId = virtualDevice.getDeviceId();
         AttributionSource attributionSource = new AttributionSource(Process.myUid(),
                 getContext().getOpPackageName(), getContext().getAttributionTag(),
-                virtualDeviceId.get());
+                virtualDeviceId);
 
         final AppOpsManager appOpsManager = getContext().getSystemService(AppOpsManager.class);
         appOpsManager.startWatchingNoted(new int[]{AppOpsManager.OP_FINE_LOCATION,
@@ -142,7 +131,7 @@
         verify(listener, timeout(NOTIFICATION_TIMEOUT_MILLIS)
                 .times(1)).onOpNoted(eq(AppOpsManager.OPSTR_FINE_LOCATION),
                 eq(Process.myUid()), eq(getContext().getOpPackageName()),
-                eq(getContext().getAttributionTag()), eq(virtualDeviceId.get()),
+                eq(getContext().getAttributionTag()), eq(virtualDeviceId),
                 eq(AppOpsManager.OP_FLAG_SELF), eq(AppOpsManager.MODE_ALLOWED));
 
         appOpsManager.finishOp(getContext().getAttributionSource().getToken(),
diff --git a/services/tests/servicestests/src/com/android/server/appop/AppOpsStartedWatcherTest.java b/services/tests/servicestests/src/com/android/server/appop/AppOpsStartedWatcherTest.java
index 8a6ba4d..d46fb90 100644
--- a/services/tests/servicestests/src/com/android/server/appop/AppOpsStartedWatcherTest.java
+++ b/services/tests/servicestests/src/com/android/server/appop/AppOpsStartedWatcherTest.java
@@ -16,8 +16,6 @@
 
 package com.android.server.appop;
 
-import static com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity;
-
 import static org.mockito.Mockito.eq;
 import static org.mockito.Mockito.inOrder;
 import static org.mockito.Mockito.mock;
@@ -28,11 +26,10 @@
 import android.app.AppOpsManager;
 import android.app.AppOpsManager.OnOpStartedListener;
 import android.companion.virtual.VirtualDeviceManager;
-import android.companion.virtual.VirtualDeviceParams;
 import android.content.AttributionSource;
 import android.content.Context;
 import android.os.Process;
-import android.virtualdevice.cts.common.FakeAssociationRule;
+import android.virtualdevice.cts.common.VirtualDeviceRule;
 
 import androidx.test.InstrumentationRegistry;
 import androidx.test.filters.SmallTest;
@@ -43,15 +40,13 @@
 import org.junit.runner.RunWith;
 import org.mockito.InOrder;
 
-import java.util.concurrent.atomic.AtomicInteger;
-
 /** Tests watching started ops. */
 @SmallTest
 @RunWith(AndroidJUnit4.class)
 public class AppOpsStartedWatcherTest {
 
     @Rule
-    public FakeAssociationRule mFakeAssociationRule = new FakeAssociationRule();
+    public VirtualDeviceRule mVirtualDeviceRule = VirtualDeviceRule.createDefault();
     private static final long NOTIFICATION_TIMEOUT_MILLIS = 5000;
 
     @Test
@@ -124,20 +119,13 @@
 
     @Test
     public void testWatchStartedOpsForExternalDevice() {
-        final VirtualDeviceManager virtualDeviceManager = getContext().getSystemService(
-                VirtualDeviceManager.class);
-        AtomicInteger virtualDeviceId = new AtomicInteger();
-        runWithShellPermissionIdentity(() -> {
-            final VirtualDeviceManager.VirtualDevice virtualDevice =
-                    virtualDeviceManager.createVirtualDevice(
-                            mFakeAssociationRule.getAssociationInfo().getId(),
-                            new VirtualDeviceParams.Builder().setName("virtual_device").build());
-            virtualDeviceId.set(virtualDevice.getDeviceId());
-        });
+        final VirtualDeviceManager.VirtualDevice virtualDevice =
+                mVirtualDeviceRule.createManagedVirtualDevice();
+        final int virtualDeviceId = virtualDevice.getDeviceId();
         final OnOpStartedListener listener = mock(OnOpStartedListener.class);
         AttributionSource attributionSource = new AttributionSource(Process.myUid(),
                 getContext().getOpPackageName(), getContext().getAttributionTag(),
-                virtualDeviceId.get());
+                virtualDeviceId);
 
         final AppOpsManager appOpsManager = getContext().getSystemService(AppOpsManager.class);
         appOpsManager.startWatchingStarted(new int[]{AppOpsManager.OP_FINE_LOCATION,
@@ -150,7 +138,7 @@
         verify(listener, timeout(NOTIFICATION_TIMEOUT_MILLIS)
                 .times(1)).onOpStarted(eq(AppOpsManager.OP_FINE_LOCATION),
                 eq(Process.myUid()), eq(getContext().getOpPackageName()),
-                eq(getContext().getAttributionTag()), eq(virtualDeviceId.get()),
+                eq(getContext().getAttributionTag()), eq(virtualDeviceId),
                 eq(AppOpsManager.OP_FLAG_SELF),
                 eq(AppOpsManager.MODE_ALLOWED), eq(OnOpStartedListener.START_TYPE_STARTED),
                 eq(AppOpsManager.ATTRIBUTION_FLAGS_NONE),
diff --git a/services/tests/servicestests/src/com/android/server/audio/VolumeHelperTest.java b/services/tests/servicestests/src/com/android/server/audio/VolumeHelperTest.java
index c305fd9..dc8c1b9 100644
--- a/services/tests/servicestests/src/com/android/server/audio/VolumeHelperTest.java
+++ b/services/tests/servicestests/src/com/android/server/audio/VolumeHelperTest.java
@@ -290,6 +290,9 @@
     // --------------- Volume Stream APIs ---------------
     @Test
     public void setStreamVolume_callsASSetStreamVolumeIndex() throws Exception {
+        assumeFalse("Skipping setStreamVolume_callsASSetStreamVolumeIndex on automotive",
+                mIsAutomotive);
+
         int newIndex = circularNoMinMaxIncrementVolume(STREAM_MUSIC);
 
         mAudioService.setDeviceForStream(STREAM_MUSIC, DEVICE_OUT_USB_DEVICE);
@@ -313,6 +316,9 @@
 
     @Test
     public void adjustStreamVolume_callsASSetStreamVolumeIndex() throws Exception {
+        assumeFalse("Skipping adjustStreamVolume_callsASSetStreamVolumeIndex on automotive",
+                mIsAutomotive);
+
         mAudioService.setDeviceForStream(STREAM_MUSIC, DEVICE_OUT_USB_DEVICE);
         mAudioService.adjustStreamVolume(STREAM_MUSIC, ADJUST_LOWER, /*flags=*/0,
                 mContext.getOpPackageName());
@@ -324,6 +330,9 @@
 
     @Test
     public void handleVolumeKey_callsASSetStreamVolumeIndex() throws Exception {
+        assumeFalse("Skipping handleVolumeKey_callsASSetStreamVolumeIndex on automotive",
+                mIsAutomotive);
+
         final KeyEvent keyEvent = new KeyEvent(ACTION_DOWN, KEYCODE_VOLUME_UP);
 
         mAudioService.setDeviceForStream(STREAM_MUSIC, DEVICE_OUT_USB_DEVICE);
@@ -339,6 +348,9 @@
 
     @Test
     public void setVolumeGroupVolumeIndex_callsASSetVolumeIndexForAttributes() throws Exception {
+        assumeFalse(
+                "Skipping setVolumeGroupVolumeIndex_callsASSetVolumeIndexForAttributes on "
+                        + "automotive", mIsAutomotive);
         assumeNotNull(mAudioMusicVolumeGroup);
 
         mAudioService.setDeviceForStream(STREAM_MUSIC, DEVICE_OUT_USB_DEVICE);
@@ -347,8 +359,8 @@
                 mContext.getOpPackageName(),  /*attributionTag*/null);
         mTestLooper.dispatchAll();
 
-        verify(mSpyAudioSystem).setVolumeIndexForAttributes(
-                any(), anyInt(), eq(DEVICE_OUT_USB_DEVICE));
+        verify(mSpyAudioSystem).setVolumeIndexForAttributes(any(), anyInt(),
+                eq(DEVICE_OUT_USB_DEVICE));
     }
 
     @Test
@@ -366,6 +378,7 @@
 
     @Test
     public void check_getVolumeGroupVolumeIndex() throws Exception {
+        assumeFalse("Skipping check_getVolumeGroupVolumeIndex on automotive", mIsAutomotive);
         assumeNotNull(mAudioMusicVolumeGroup);
 
         int newIndex = circularNoMinMaxIncrementVolume(STREAM_MUSIC);
@@ -374,10 +387,9 @@
                 newIndex, /*flags=*/0, mContext.getOpPackageName(),  /*attributionTag*/null);
         mTestLooper.dispatchAll();
 
-        assertEquals(mAudioService.getVolumeGroupVolumeIndex(mAudioMusicVolumeGroup.getId()),
-                newIndex);
-        assertEquals(mAudioService.getStreamVolume(STREAM_MUSIC),
-                newIndex);
+        assertEquals(newIndex,
+                mAudioService.getVolumeGroupVolumeIndex(mAudioMusicVolumeGroup.getId()));
+        assertEquals(newIndex, mAudioService.getStreamVolume(STREAM_MUSIC));
     }
 
     @Test
@@ -432,6 +444,7 @@
 
     @Test
     public void flagAbsVolume_onBtDevice_changesVolume() throws Exception {
+        assumeFalse("Skipping flagAbsVolume_onBtDevice_changesVolume on automotive", mIsAutomotive);
         mAudioService.setDeviceForStream(STREAM_NOTIFICATION, DEVICE_OUT_BLE_SPEAKER);
 
         int newIndex = circularNoMinMaxIncrementVolume(STREAM_NOTIFICATION);
@@ -494,7 +507,7 @@
                 mContext.getOpPackageName());
         mTestLooper.dispatchAll();
 
-        assertEquals(mAudioService.getRingerModeInternal(), RINGER_MODE_VIBRATE);
+        assertEquals(RINGER_MODE_VIBRATE, mAudioService.getRingerModeInternal());
     }
 
     // --------------------- Permission tests ---------------------
@@ -538,6 +551,7 @@
     // ----------------- AudioDeviceVolumeManager -----------------
     @Test
     public void setDeviceVolume_checkIndex() {
+        assumeFalse("Skipping setDeviceVolume_checkIndex on automotive", mIsAutomotive);
         final int minIndex = mAm.getStreamMinVolume(STREAM_MUSIC);
         final int maxIndex = mAm.getStreamMaxVolume(STREAM_MUSIC);
         final int midIndex = (minIndex + maxIndex) / 2;
@@ -553,21 +567,17 @@
         mAudioService.setDeviceVolume(volMin, usbDevice, mContext.getOpPackageName());
         mTestLooper.dispatchAll();
 
-        if (!mIsAutomotive) {
-            // there is a min/max index mismatch in automotive
-            assertEquals(mAudioService.getDeviceVolume(volMin, usbDevice,
-                    mContext.getOpPackageName()), volMin);
-        }
+        // there is a min/max index mismatch in automotive
+        assertEquals(volMin, mAudioService.getDeviceVolume(volMin, usbDevice,
+                mContext.getOpPackageName()));
         verify(mSpyAudioSystem, atLeast(1)).setStreamVolumeIndexAS(
                 eq(STREAM_MUSIC), anyInt(), eq(AudioSystem.DEVICE_OUT_USB_DEVICE));
 
         mAudioService.setDeviceVolume(volMid, usbDevice, mContext.getOpPackageName());
         mTestLooper.dispatchAll();
-        if (!mIsAutomotive) {
-            // there is a min/max index mismatch in automotive
-            assertEquals(mAudioService.getDeviceVolume(volMid, usbDevice,
-                    mContext.getOpPackageName()), volMid);
-        }
+        // there is a min/max index mismatch in automotive
+        assertEquals(volMid, mAudioService.getDeviceVolume(volMid, usbDevice,
+                mContext.getOpPackageName()));
         verify(mSpyAudioSystem, atLeast(1)).setStreamVolumeIndexAS(
                 eq(STREAM_MUSIC), anyInt(), eq(AudioSystem.DEVICE_OUT_USB_DEVICE));
     }
@@ -603,9 +613,8 @@
             mAudioService.setDeviceVolume(volCur, bleDevice, mContext.getOpPackageName());
             mTestLooper.dispatchAll();
 
-            assertEquals(
-                    mAudioService.getDeviceVolume(volCur, bleDevice, mContext.getOpPackageName()),
-                    volCur);
+            assertEquals(volCur,
+                    mAudioService.getDeviceVolume(volCur, bleDevice, mContext.getOpPackageName()));
             // Stream volume changes
             verify(mSpyAudioSystem, atLeast(1)).setStreamVolumeIndexAS(
                     STREAM_MUSIC, targetIndex,
@@ -618,9 +627,8 @@
         mAudioService.setDeviceVolume(volIndex4, bleDevice, mContext.getOpPackageName());
         mTestLooper.dispatchAll();
 
-        assertEquals(
-                mAudioService.getDeviceVolume(volIndex4, bleDevice, mContext.getOpPackageName()),
-                volIndex4);
+        assertEquals(volIndex4,
+                mAudioService.getDeviceVolume(volIndex4, bleDevice, mContext.getOpPackageName()));
         verify(mSpyAudioSystem, atLeast(1)).setStreamVolumeIndexAS(
                 STREAM_MUSIC, maxIndex,
                 AudioSystem.DEVICE_OUT_BLE_HEADSET);
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 4d067f6..e386808 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
@@ -50,7 +50,6 @@
 import static org.mockito.Mockito.when;
 import static org.testng.Assert.assertThrows;
 
-import android.Manifest;
 import android.app.WindowConfiguration;
 import android.app.admin.DevicePolicyManager;
 import android.companion.AssociationInfo;
@@ -113,10 +112,10 @@
 import android.view.DisplayInfo;
 import android.view.KeyEvent;
 import android.view.WindowManager;
+import android.virtualdevice.cts.common.VirtualDeviceRule;
 
 import androidx.test.platform.app.InstrumentationRegistry;
 
-import com.android.compatibility.common.util.AdoptShellPermissionsRule;
 import com.android.internal.app.BlockedAppStreamingActivity;
 import com.android.internal.os.BackgroundThread;
 import com.android.server.LocalServices;
@@ -150,6 +149,7 @@
     private static final String NONBLOCKED_APP_PACKAGE_NAME = "com.someapp";
     private static final String PERMISSION_CONTROLLER_PACKAGE_NAME =
             "com.android.permissioncontroller";
+    private static final String VIRTUAL_DEVICE_OWNER_PACKAGE = "com.android.virtualdevice.test";
     private static final String SETTINGS_PACKAGE_NAME = "com.android.settings";
     private static final String VENDING_PACKAGE_NAME = "com.android.vending";
     private static final String GOOGLE_DIALER_PACKAGE_NAME = "com.google.android.dialer";
@@ -160,8 +160,8 @@
     private static final int DISPLAY_ID_1 = 2;
     private static final int DISPLAY_ID_2 = 3;
     private static final int NON_EXISTENT_DISPLAY_ID = 42;
-    private static final int DEVICE_OWNER_UID_1 = 50;
-    private static final int DEVICE_OWNER_UID_2 = 51;
+    private static final int DEVICE_OWNER_UID_1 = Process.myUid();
+    private static final int DEVICE_OWNER_UID_2 = DEVICE_OWNER_UID_1 + 1;
     private static final int UID_1 = 0;
     private static final int UID_2 = 10;
     private static final int UID_3 = 10000;
@@ -223,9 +223,7 @@
     public SetFlagsRule mSetFlagsRule = new SetFlagsRule();
 
     @Rule
-    public AdoptShellPermissionsRule mAdoptShellPermissionsRule = new AdoptShellPermissionsRule(
-            InstrumentationRegistry.getInstrumentation().getUiAutomation(),
-            Manifest.permission.CREATE_VIRTUAL_DEVICE);
+    public VirtualDeviceRule mVirtualDeviceRule = VirtualDeviceRule.createDefault();
 
     private Context mContext;
     private InputManagerMockHelper mInputManagerMockHelper;
@@ -246,6 +244,8 @@
     @Mock
     private IDisplayManager mIDisplayManager;
     @Mock
+    private WindowManager mWindowManager;
+    @Mock
     private VirtualDeviceImpl.PendingTrampolineCallback mPendingTrampolineCallback;
     @Mock
     private DevicePolicyManager mDevicePolicyManagerMock;
@@ -296,11 +296,10 @@
     private Intent createRestrictedActivityBlockedIntent(Set<String> displayCategories,
             String targetDisplayCategory) {
         when(mDisplayManagerInternalMock.createVirtualDisplay(any(), any(), any(), any(),
-                eq(NONBLOCKED_APP_PACKAGE_NAME))).thenReturn(DISPLAY_ID_1);
+                eq(VIRTUAL_DEVICE_OWNER_PACKAGE))).thenReturn(DISPLAY_ID_1);
         VirtualDisplayConfig config = new VirtualDisplayConfig.Builder("display", 640, 480,
                 420).setDisplayCategories(displayCategories).build();
-        mDeviceImpl.createVirtualDisplay(config, mVirtualDisplayCallback,
-                NONBLOCKED_APP_PACKAGE_NAME);
+        mDeviceImpl.createVirtualDisplay(config, mVirtualDisplayCallback);
         GenericWindowPolicyController gwpc = mDeviceImpl.getDisplayWindowPolicyControllerForTest(
                 DISPLAY_ID_1);
         doNothing().when(mContext).startActivityAsUser(any(), any(), any());
@@ -385,8 +384,7 @@
         // Allow virtual devices to be created on the looper thread for testing.
         final InputController.DeviceCreationThreadVerifier threadVerifier = () -> true;
         mInputController = new InputController(mNativeWrapperMock,
-                new Handler(TestableLooper.get(this).getLooper()),
-                mContext.getSystemService(WindowManager.class),
+                new Handler(TestableLooper.get(this).getLooper()), mWindowManager,
                 AttributionSource.myAttributionSource(), threadVerifier);
         mCameraAccessController =
                 new CameraAccessController(mContext, mLocalService, mCameraAccessBlockedCallback);
@@ -537,7 +535,7 @@
                 .build();
         mDeviceImpl.close();
         mDeviceImpl = createVirtualDevice(VIRTUAL_DEVICE_ID_1, DEVICE_OWNER_UID_1, params);
-        addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
+        addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1, Display.FLAG_TRUSTED);
 
         GenericWindowPolicyController gwpc =
                 mDeviceImpl.getDisplayWindowPolicyControllerForTest(DISPLAY_ID_1);
@@ -545,6 +543,83 @@
     }
 
     @Test
+    public void getDevicePolicy_customRecentsPolicy_untrustedDisplaygwpcShowsRecentsOnHostDevice() {
+        VirtualDeviceParams params = new VirtualDeviceParams
+                .Builder()
+                .setDevicePolicy(POLICY_TYPE_RECENTS, DEVICE_POLICY_CUSTOM)
+                .build();
+        mDeviceImpl.close();
+        mDeviceImpl = createVirtualDevice(VIRTUAL_DEVICE_ID_1, DEVICE_OWNER_UID_1, params);
+        addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
+
+        GenericWindowPolicyController gwpc =
+                mDeviceImpl.getDisplayWindowPolicyControllerForTest(DISPLAY_ID_1);
+        assertThat(gwpc.canShowTasksInHostDeviceRecents()).isTrue();
+    }
+
+    @Test
+    public void deviceOwner_cannotMessWithAnotherDeviceTheyDoNotOwn() {
+        VirtualDeviceImpl unownedDevice =
+                createVirtualDevice(VIRTUAL_DEVICE_ID_2, DEVICE_OWNER_UID_2);
+
+        // The arguments don't matter, the owner uid check is always the first statement.
+        assertThrows(SecurityException.class, () -> unownedDevice.goToSleep());
+        assertThrows(SecurityException.class, () -> unownedDevice.wakeUp());
+
+        assertThrows(SecurityException.class,
+                () -> unownedDevice.launchPendingIntent(0, null, null));
+        assertThrows(SecurityException.class,
+                () -> unownedDevice.registerIntentInterceptor(null, null));
+        assertThrows(SecurityException.class,
+                () -> unownedDevice.unregisterIntentInterceptor(null));
+
+        assertThrows(SecurityException.class,
+                () -> unownedDevice.addActivityPolicyExemption(null));
+        assertThrows(SecurityException.class,
+                () -> unownedDevice.removeActivityPolicyExemption(null));
+        assertThrows(SecurityException.class, () -> unownedDevice.setDevicePolicy(0, 0));
+        assertThrows(SecurityException.class,
+                () -> unownedDevice.setDevicePolicyForDisplay(0, 0, 0));
+        assertThrows(SecurityException.class, () -> unownedDevice.setDisplayImePolicy(0, 0));
+
+        assertThrows(SecurityException.class, () -> unownedDevice.registerVirtualCamera(null));
+        assertThrows(SecurityException.class, () -> unownedDevice.unregisterVirtualCamera(null));
+
+        assertThrows(SecurityException.class,
+                () -> unownedDevice.onAudioSessionStarting(0, null, null));
+        assertThrows(SecurityException.class, () -> unownedDevice.onAudioSessionEnded());
+
+        assertThrows(SecurityException.class, () -> unownedDevice.createVirtualDisplay(null, null));
+        assertThrows(SecurityException.class, () -> unownedDevice.createVirtualDpad(null, null));
+        assertThrows(SecurityException.class, () -> unownedDevice.createVirtualMouse(null, null));
+        assertThrows(SecurityException.class,
+                () -> unownedDevice.createVirtualTouchscreen(null, null));
+        assertThrows(SecurityException.class,
+                () -> unownedDevice.createVirtualNavigationTouchpad(null, null));
+        assertThrows(SecurityException.class, () -> unownedDevice.createVirtualStylus(null, null));
+        assertThrows(SecurityException.class,
+                () -> unownedDevice.createVirtualRotaryEncoder(null, null));
+        assertThrows(SecurityException.class, () -> unownedDevice.unregisterInputDevice(null));
+
+        assertThrows(SecurityException.class, () -> unownedDevice.sendDpadKeyEvent(null, null));
+        assertThrows(SecurityException.class, () -> unownedDevice.sendKeyEvent(null, null));
+        assertThrows(SecurityException.class, () -> unownedDevice.sendButtonEvent(null, null));
+        assertThrows(SecurityException.class, () -> unownedDevice.sendTouchEvent(null, null));
+        assertThrows(SecurityException.class, () -> unownedDevice.sendRelativeEvent(null, null));
+        assertThrows(SecurityException.class, () -> unownedDevice.sendScrollEvent(null, null));
+        assertThrows(SecurityException.class,
+                () -> unownedDevice.sendStylusMotionEvent(null, null));
+        assertThrows(SecurityException.class,
+                () -> unownedDevice.sendStylusButtonEvent(null, null));
+        assertThrows(SecurityException.class,
+                () -> unownedDevice.sendRotaryEncoderScrollEvent(null, null));
+        assertThrows(SecurityException.class, () -> unownedDevice.setShowPointerIcon(true));
+
+        assertThrows(SecurityException.class, () -> unownedDevice.getVirtualSensorList());
+        assertThrows(SecurityException.class, () -> unownedDevice.sendSensorEvent(null, null));
+    }
+
+    @Test
     public void getDeviceOwnerUid_oneDevice_returnsCorrectId() {
         int ownerUid = mLocalService.getDeviceOwnerUid(mDeviceImpl.getDeviceId());
         assertThat(ownerUid).isEqualTo(mDeviceImpl.getOwnerUid());
@@ -662,7 +737,7 @@
     @Test
     public void getDeviceIdsForUid_twoDevicesUidOnOne_returnsCorrectId() {
         VirtualDeviceImpl secondDevice = createVirtualDevice(VIRTUAL_DEVICE_ID_2,
-                DEVICE_OWNER_UID_2);
+                DEVICE_OWNER_UID_1);
         addVirtualDisplay(secondDevice, DISPLAY_ID_2);
 
         secondDevice.getDisplayWindowPolicyControllerForTest(DISPLAY_ID_2).onRunningAppsChanged(
@@ -677,7 +752,7 @@
     public void getDeviceIdsForUid_twoDevicesUidOnBoth_returnsCorrectId() {
         addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
         VirtualDeviceImpl secondDevice = createVirtualDevice(VIRTUAL_DEVICE_ID_2,
-                DEVICE_OWNER_UID_2);
+                DEVICE_OWNER_UID_1);
         addVirtualDisplay(secondDevice, DISPLAY_ID_2);
 
 
@@ -694,7 +769,7 @@
 
     @Test
     public void getPreferredLocaleListForApp_keyboardAttached_returnLocaleHints() {
-        addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
+        addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1, Display.FLAG_TRUSTED);
         mDeviceImpl.createVirtualKeyboard(KEYBOARD_CONFIG, BINDER);
 
         mVdms.notifyRunningAppsChanged(mDeviceImpl.getDeviceId(), Sets.newArraySet(UID_1));
@@ -715,7 +790,7 @@
     @Test
     public void getPreferredLocaleListForApp_appOnMultipleVD_localeOnFirstVDReturned() {
         VirtualDeviceImpl secondDevice = createVirtualDevice(VIRTUAL_DEVICE_ID_2,
-                DEVICE_OWNER_UID_2);
+                DEVICE_OWNER_UID_1);
         Binder secondBinder = new Binder("secondBinder");
         VirtualKeyboardConfig firstKeyboardConfig =
                 new VirtualKeyboardConfig.Builder()
@@ -734,8 +809,8 @@
                         .setLanguageTag("fr-FR")
                         .build();
 
-        addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
-        addVirtualDisplay(secondDevice, DISPLAY_ID_2);
+        addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1, Display.FLAG_TRUSTED);
+        addVirtualDisplay(secondDevice, DISPLAY_ID_2, Display.FLAG_TRUSTED);
 
         mDeviceImpl.createVirtualKeyboard(firstKeyboardConfig, BINDER);
         secondDevice.createVirtualKeyboard(secondKeyboardConfig, secondBinder);
@@ -753,7 +828,7 @@
         assertThat(mCameraAccessController.getObserverCount()).isEqualTo(1);
 
         VirtualDeviceImpl secondDevice =
-                createVirtualDevice(VIRTUAL_DEVICE_ID_2, DEVICE_OWNER_UID_2);
+                createVirtualDevice(VIRTUAL_DEVICE_ID_2, DEVICE_OWNER_UID_1);
         assertThat(mCameraAccessController.getObserverCount()).isEqualTo(2);
 
         mDeviceImpl.close();
@@ -912,11 +987,24 @@
     }
 
     @Test
-    public void onVirtualDisplayCreatedLocked_wakeLockIsAcquired() throws RemoteException {
+    public void onVirtualDisplayCreatedLocked_notTrustedDisplay_noWakeLockIsAcquired()
+            throws RemoteException {
         verify(mIPowerManagerMock, never()).acquireWakeLock(any(Binder.class), anyInt(),
                 nullable(String.class), nullable(String.class), nullable(WorkSource.class),
                 nullable(String.class), anyInt(), eq(null));
         addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
+        TestableLooper.get(this).processAllMessages();
+        verify(mIPowerManagerMock, never()).acquireWakeLock(any(Binder.class), anyInt(),
+                nullable(String.class), nullable(String.class), nullable(WorkSource.class),
+                nullable(String.class), anyInt(), eq(null));
+    }
+
+    @Test
+    public void onVirtualDisplayCreatedLocked_wakeLockIsAcquired() throws RemoteException {
+        verify(mIPowerManagerMock, never()).acquireWakeLock(any(Binder.class), anyInt(),
+                nullable(String.class), nullable(String.class), nullable(WorkSource.class),
+                nullable(String.class), anyInt(), eq(null));
+        addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1, Display.FLAG_TRUSTED);
         verify(mIPowerManagerMock).acquireWakeLock(any(Binder.class), anyInt(),
                 nullable(String.class), nullable(String.class), nullable(WorkSource.class),
                 nullable(String.class), eq(DISPLAY_ID_1), eq(null));
@@ -925,7 +1013,7 @@
     @Test
     public void onVirtualDisplayCreatedLocked_duplicateCalls_onlyOneWakeLockIsAcquired()
             throws RemoteException {
-        addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
+        addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1, Display.FLAG_TRUSTED);
         assertThrows(IllegalStateException.class,
                 () -> addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1));
         TestableLooper.get(this).processAllMessages();
@@ -936,7 +1024,7 @@
 
     @Test
     public void onVirtualDisplayRemovedLocked_wakeLockIsReleased() throws RemoteException {
-        addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
+        addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1, Display.FLAG_TRUSTED);
         ArgumentCaptor<IBinder> wakeLockCaptor = ArgumentCaptor.forClass(IBinder.class);
         TestableLooper.get(this).processAllMessages();
         verify(mIPowerManagerMock).acquireWakeLock(wakeLockCaptor.capture(),
@@ -951,7 +1039,7 @@
 
     @Test
     public void addVirtualDisplay_displayNotReleased_wakeLockIsReleased() throws RemoteException {
-        addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
+        addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1, Display.FLAG_TRUSTED);
         ArgumentCaptor<IBinder> wakeLockCaptor = ArgumentCaptor.forClass(IBinder.class);
         TestableLooper.get(this).processAllMessages();
         verify(mIPowerManagerMock).acquireWakeLock(wakeLockCaptor.capture(),
@@ -972,24 +1060,52 @@
     }
 
     @Test
+    public void createVirtualDpad_untrustedDisplay_failsSecurityException() {
+        addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
+        assertThrows(SecurityException.class,
+                () -> mDeviceImpl.createVirtualDpad(DPAD_CONFIG, BINDER));
+    }
+
+    @Test
     public void createVirtualKeyboard_noDisplay_failsSecurityException() {
         assertThrows(SecurityException.class,
                 () -> mDeviceImpl.createVirtualKeyboard(KEYBOARD_CONFIG, BINDER));
     }
 
     @Test
+    public void createVirtualKeyboard_untrustedDisplay_failsSecurityException() {
+        addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
+        assertThrows(SecurityException.class,
+                () -> mDeviceImpl.createVirtualKeyboard(KEYBOARD_CONFIG, BINDER));
+    }
+
+    @Test
     public void createVirtualMouse_noDisplay_failsSecurityException() {
         assertThrows(SecurityException.class,
                 () -> mDeviceImpl.createVirtualMouse(MOUSE_CONFIG, BINDER));
     }
 
     @Test
+    public void createVirtualMouse_untrustedDisplay_failsSecurityException() {
+        addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
+        assertThrows(SecurityException.class,
+                () -> mDeviceImpl.createVirtualMouse(MOUSE_CONFIG, BINDER));
+    }
+
+    @Test
     public void createVirtualTouchscreen_noDisplay_failsSecurityException() {
         assertThrows(SecurityException.class,
                 () -> mDeviceImpl.createVirtualTouchscreen(TOUCHSCREEN_CONFIG, BINDER));
     }
 
     @Test
+    public void createVirtualTouchscreen_untrustedDisplay_failsSecurityException() {
+        addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
+        assertThrows(SecurityException.class,
+                () -> mDeviceImpl.createVirtualTouchscreen(TOUCHSCREEN_CONFIG, BINDER));
+    }
+
+    @Test
     public void createVirtualTouchscreen_zeroDisplayDimension_failsIllegalArgumentException() {
         assertThrows(IllegalArgumentException.class,
                 () -> new VirtualTouchscreenConfig.Builder(
@@ -1005,7 +1121,7 @@
 
     @Test
     public void createVirtualTouchscreen_positiveDisplayDimension_successful() {
-        addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
+        addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1, Display.FLAG_TRUSTED);
         VirtualTouchscreenConfig positiveConfig =
                 new VirtualTouchscreenConfig.Builder(
                         /* touchscrenWidth= */ 600, /* touchscreenHeight= */ 800)
@@ -1028,6 +1144,14 @@
     }
 
     @Test
+    public void createVirtualNavigationTouchpad_untrustedDisplay_failsSecurityException() {
+        addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
+        assertThrows(SecurityException.class,
+                () -> mDeviceImpl.createVirtualNavigationTouchpad(NAVIGATION_TOUCHPAD_CONFIG,
+                        BINDER));
+    }
+
+    @Test
     public void createVirtualNavigationTouchpad_zeroDisplayDimension_failsWithException() {
         assertThrows(IllegalArgumentException.class,
                 () -> new VirtualNavigationTouchpadConfig.Builder(
@@ -1043,7 +1167,7 @@
 
     @Test
     public void createVirtualNavigationTouchpad_positiveDisplayDimension_successful() {
-        addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
+        addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1, Display.FLAG_TRUSTED);
         VirtualNavigationTouchpadConfig positiveConfig =
                 new VirtualNavigationTouchpadConfig.Builder(
                         /* touchpadHeight= */ 50, /* touchpadWidth= */ 50)
@@ -1067,71 +1191,8 @@
     }
 
     @Test
-    public void createVirtualDpad_noPermission_failsSecurityException() {
-        addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
-        try (DropShellPermissionsTemporarily drop = new DropShellPermissionsTemporarily()) {
-            assertThrows(SecurityException.class,
-                    () -> mDeviceImpl.createVirtualDpad(DPAD_CONFIG, BINDER));
-        }
-    }
-
-    @Test
-    public void createVirtualKeyboard_noPermission_failsSecurityException() {
-        addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
-        try (DropShellPermissionsTemporarily drop = new DropShellPermissionsTemporarily()) {
-            assertThrows(SecurityException.class,
-                    () -> mDeviceImpl.createVirtualKeyboard(KEYBOARD_CONFIG, BINDER));
-        }
-    }
-
-    @Test
-    public void createVirtualMouse_noPermission_failsSecurityException() {
-        addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
-        try (DropShellPermissionsTemporarily drop = new DropShellPermissionsTemporarily()) {
-            assertThrows(SecurityException.class,
-                    () -> mDeviceImpl.createVirtualMouse(MOUSE_CONFIG, BINDER));
-        }
-    }
-
-    @Test
-    public void createVirtualTouchscreen_noPermission_failsSecurityException() {
-        addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
-        try (DropShellPermissionsTemporarily drop = new DropShellPermissionsTemporarily()) {
-            assertThrows(SecurityException.class,
-                    () -> mDeviceImpl.createVirtualTouchscreen(TOUCHSCREEN_CONFIG, BINDER));
-        }
-    }
-
-    @Test
-    public void createVirtualNavigationTouchpad_noPermission_failsSecurityException() {
-        addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
-        try (DropShellPermissionsTemporarily drop = new DropShellPermissionsTemporarily()) {
-            assertThrows(SecurityException.class,
-                    () -> mDeviceImpl.createVirtualNavigationTouchpad(NAVIGATION_TOUCHPAD_CONFIG,
-                            BINDER));
-        }
-    }
-
-    @Test
-    public void onAudioSessionStarting_noPermission_failsSecurityException() {
-        addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
-        try (DropShellPermissionsTemporarily drop = new DropShellPermissionsTemporarily()) {
-            assertThrows(SecurityException.class,
-                    () -> mDeviceImpl.onAudioSessionStarting(
-                            DISPLAY_ID_1, mRoutingCallback, mConfigChangedCallback));
-        }
-    }
-
-    @Test
-    public void onAudioSessionEnded_noPermission_failsSecurityException() {
-        try (DropShellPermissionsTemporarily drop = new DropShellPermissionsTemporarily()) {
-            assertThrows(SecurityException.class, () -> mDeviceImpl.onAudioSessionEnded());
-        }
-    }
-
-    @Test
     public void createVirtualDpad_hasDisplay_obtainFileDescriptor() {
-        addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
+        addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1, Display.FLAG_TRUSTED);
         mDeviceImpl.createVirtualDpad(DPAD_CONFIG, BINDER);
         assertWithMessage("Virtual dpad should register fd when the display matches").that(
                 mInputController.getInputDeviceDescriptors()).isNotEmpty();
@@ -1141,7 +1202,7 @@
 
     @Test
     public void createVirtualKeyboard_hasDisplay_obtainFileDescriptor() {
-        addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
+        addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1, Display.FLAG_TRUSTED);
         mDeviceImpl.createVirtualKeyboard(KEYBOARD_CONFIG, BINDER);
         assertWithMessage("Virtual keyboard should register fd when the display matches").that(
                 mInputController.getInputDeviceDescriptors()).isNotEmpty();
@@ -1151,7 +1212,7 @@
 
     @Test
     public void createVirtualKeyboard_keyboardCreated_localeUpdated() {
-        addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
+        addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1, Display.FLAG_TRUSTED);
         mDeviceImpl.createVirtualKeyboard(KEYBOARD_CONFIG, BINDER);
         assertWithMessage("Virtual keyboard should register fd when the display matches")
                 .that(mInputController.getInputDeviceDescriptors())
@@ -1172,7 +1233,7 @@
                         .setAssociatedDisplayId(DISPLAY_ID_1)
                         .build();
 
-        addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
+        addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1, Display.FLAG_TRUSTED);
         mDeviceImpl.createVirtualKeyboard(configWithoutExplicitLayoutInfo, BINDER);
         assertWithMessage("Virtual keyboard should register fd when the display matches")
                 .that(mInputController.getInputDeviceDescriptors())
@@ -1193,7 +1254,7 @@
 
     @Test
     public void createVirtualMouse_hasDisplay_obtainFileDescriptor() {
-        addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
+        addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1, Display.FLAG_TRUSTED);
         mDeviceImpl.createVirtualMouse(MOUSE_CONFIG, BINDER);
         assertWithMessage("Virtual mouse should register fd when the display matches").that(
                 mInputController.getInputDeviceDescriptors()).isNotEmpty();
@@ -1203,7 +1264,7 @@
 
     @Test
     public void createVirtualTouchscreen_hasDisplay_obtainFileDescriptor() {
-        addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
+        addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1, Display.FLAG_TRUSTED);
         mDeviceImpl.createVirtualTouchscreen(TOUCHSCREEN_CONFIG, BINDER);
         assertWithMessage("Virtual touchscreen should register fd when the display matches").that(
                 mInputController.getInputDeviceDescriptors()).isNotEmpty();
@@ -1213,7 +1274,7 @@
 
     @Test
     public void createVirtualNavigationTouchpad_hasDisplay_obtainFileDescriptor() {
-        addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
+        addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1, Display.FLAG_TRUSTED);
         mDeviceImpl.createVirtualNavigationTouchpad(NAVIGATION_TOUCHPAD_CONFIG, BINDER);
         assertWithMessage("Virtual navigation touchpad should register fd when the display matches")
                 .that(
@@ -1473,9 +1534,9 @@
 
     @Test
     public void setShowPointerIcon_setsValueForAllDisplays() {
-        addVirtualDisplay(mDeviceImpl, 1);
-        addVirtualDisplay(mDeviceImpl, 2);
-        addVirtualDisplay(mDeviceImpl, 3);
+        addVirtualDisplay(mDeviceImpl, 1, Display.FLAG_TRUSTED);
+        addVirtualDisplay(mDeviceImpl, 2, Display.FLAG_TRUSTED);
+        addVirtualDisplay(mDeviceImpl, 3, Display.FLAG_TRUSTED);
         VirtualMouseConfig config1 = new VirtualMouseConfig.Builder()
                 .setAssociatedDisplayId(1)
                 .setInputDeviceName(DEVICE_NAME_1)
@@ -1508,6 +1569,14 @@
     }
 
     @Test
+    public void setShowPointerIcon_untrustedDisplay_pointerIconIsAlwaysShown() {
+        addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
+        clearInvocations(mInputManagerInternalMock);
+        mDeviceImpl.setShowPointerIcon(false);
+        verify(mInputManagerInternalMock, times(0)).setPointerIconVisible(eq(false), anyInt());
+    }
+
+    @Test
     public void openNonBlockedAppOnVirtualDisplay_doesNotStartBlockedAlertActivity() {
         addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
         GenericWindowPolicyController gwpc = mDeviceImpl.getDisplayWindowPolicyControllerForTest(
@@ -1950,7 +2019,7 @@
                         mVirtualDeviceLog,
                         new Binder(),
                         new AttributionSource(
-                                ownerUid, "com.android.virtualdevice.test", "virtualdevice"),
+                                ownerUid, VIRTUAL_DEVICE_OWNER_PACKAGE, "virtualdevice"),
                         virtualDeviceId,
                         mInputController,
                         mCameraAccessController,
@@ -1969,16 +2038,20 @@
     }
 
     private void addVirtualDisplay(VirtualDeviceImpl virtualDevice, int displayId) {
+        addVirtualDisplay(virtualDevice, displayId, /* flags= */ 0);
+    }
+
+    private void addVirtualDisplay(VirtualDeviceImpl virtualDevice, int displayId, int flags) {
         when(mDisplayManagerInternalMock.createVirtualDisplay(any(), eq(mVirtualDisplayCallback),
                 eq(virtualDevice), any(), any())).thenReturn(displayId);
-        virtualDevice.createVirtualDisplay(VIRTUAL_DISPLAY_CONFIG, mVirtualDisplayCallback,
-                NONBLOCKED_APP_PACKAGE_NAME);
         final String uniqueId = UNIQUE_ID + displayId;
         doAnswer(inv -> {
             final DisplayInfo displayInfo = new DisplayInfo();
             displayInfo.uniqueId = uniqueId;
+            displayInfo.flags = flags;
             return displayInfo;
         }).when(mDisplayManagerInternalMock).getDisplayInfo(eq(displayId));
+        virtualDevice.createVirtualDisplay(VIRTUAL_DISPLAY_CONFIG, mVirtualDisplayCallback);
         mInputManagerMockHelper.addDisplayIdMapping(uniqueId, displayId);
     }
 
@@ -2000,20 +2073,7 @@
                 /* tag= */ null, MacAddress.BROADCAST_ADDRESS, displayName, deviceProfile,
                 /* associatedDevice= */ null, /* selfManaged= */ true,
                 /* notifyOnDeviceNearby= */ false, /* revoked= */ false, /* pending= */ false,
-                /* timeApprovedMs= */0, /* lastTimeConnectedMs= */0, /* systemDataSyncFlags= */ -1);
-    }
-
-    /** Helper class to drop permissions temporarily and restore them at the end of a test. */
-    static final class DropShellPermissionsTemporarily implements AutoCloseable {
-        DropShellPermissionsTemporarily() {
-            InstrumentationRegistry.getInstrumentation().getUiAutomation()
-                    .dropShellPermissionIdentity();
-        }
-
-        @Override
-        public void close() {
-            InstrumentationRegistry.getInstrumentation().getUiAutomation()
-                    .adoptShellPermissionIdentity();
-        }
+                /* timeApprovedMs= */0, /* lastTimeConnectedMs= */0,
+                /* systemDataSyncFlags= */ -1, /* deviceIcon= */ null);
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/compat/PlatformCompatTest.java b/services/tests/servicestests/src/com/android/server/compat/PlatformCompatTest.java
index 9df7a36..1d07540 100644
--- a/services/tests/servicestests/src/com/android/server/compat/PlatformCompatTest.java
+++ b/services/tests/servicestests/src/com/android/server/compat/PlatformCompatTest.java
@@ -20,6 +20,7 @@
 
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.anyLong;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.reset;
 import static org.mockito.Mockito.verify;
@@ -33,6 +34,11 @@
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManagerInternal;
 import android.os.Build;
+import android.os.Process;
+
+import android.platform.test.annotations.DisableFlags;
+import android.platform.test.annotations.EnableFlags;
+import android.platform.test.flag.junit.SetFlagsRule;
 
 import androidx.test.runner.AndroidJUnit4;
 
@@ -43,6 +49,7 @@
 import com.android.server.LocalServices;
 
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
@@ -55,6 +62,8 @@
 public class PlatformCompatTest {
     private static final String PACKAGE_NAME = "my.package";
 
+    @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+
     @Mock
     private Context mContext;
     @Mock
@@ -441,4 +450,79 @@
         assertThat(mPlatformCompat.isChangeEnabled(3L, systemAppInfo)).isTrue();
         verify(mChangeReporter).reportChange(123, 3L, ChangeReporter.STATE_ENABLED, true, false);
     }
+
+    @DisableFlags(Flags.FLAG_SYSTEM_UID_TARGET_SYSTEM_SDK)
+    @Test
+    public void testSharedSystemUidFlagOff() throws Exception {
+        testSharedSystemUid(false);
+    }
+
+    @EnableFlags(Flags.FLAG_SYSTEM_UID_TARGET_SYSTEM_SDK)
+    @Test
+    public void testSharedSystemUidFlagOn() throws Exception {
+        testSharedSystemUid(true);
+    }
+
+    private void testSharedSystemUid(Boolean expectSystemUidTargetSystemSdk) throws Exception {
+        final String systemUidPackageNameTargetsR = "systemuid.package1";
+        final String systemUidPackageNameTargetsQ = "systemuid.package2";
+        final String nonSystemUidPackageNameTargetsR = "nonsystemuid.package1";
+        final String nonSystemUidPackageNameTargetsQ = "nonsystemuid.package2";
+        final int nonSystemUid = 123;
+
+        mCompatConfig =
+                CompatConfigBuilder.create(mBuildClassifier, mContext)
+                        .addEnableSinceSdkChangeWithId(Build.VERSION_CODES.R, 1L)
+                        .build();
+        mCompatConfig.forceNonDebuggableFinalForTest(true);
+        mPlatformCompat =
+                new PlatformCompat(mContext, mCompatConfig, mBuildClassifier, mChangeReporter);
+
+        ApplicationInfo systemUidAppInfo1 = ApplicationInfoBuilder.create()
+            .withPackageName(systemUidPackageNameTargetsR)
+            .withUid(Process.SYSTEM_UID)
+            .withTargetSdk(Build.VERSION_CODES.R)
+            .build();
+        when(mPackageManagerInternal.getApplicationInfo(
+                 eq(systemUidPackageNameTargetsR), anyLong(), anyInt(), anyInt()))
+            .thenReturn(systemUidAppInfo1);
+
+        ApplicationInfo systemUidAppInfo2 = ApplicationInfoBuilder.create()
+            .withPackageName(systemUidPackageNameTargetsQ)
+            .withUid(Process.SYSTEM_UID)
+            .withTargetSdk(Build.VERSION_CODES.Q)
+            .build();
+        when(mPackageManagerInternal.getApplicationInfo(
+                 eq(systemUidPackageNameTargetsQ), anyLong(), anyInt(), anyInt()))
+            .thenReturn(systemUidAppInfo2);
+
+        ApplicationInfo nonSystemUidAppInfo1 = ApplicationInfoBuilder.create()
+            .withPackageName(nonSystemUidPackageNameTargetsR)
+            .withUid(nonSystemUid)
+            .withTargetSdk(Build.VERSION_CODES.R)
+            .build();
+        when(mPackageManagerInternal.getApplicationInfo(
+                 eq(nonSystemUidPackageNameTargetsR), anyLong(), anyInt(), anyInt()))
+            .thenReturn(nonSystemUidAppInfo1);
+
+        ApplicationInfo nonSystemUidAppInfo2 = ApplicationInfoBuilder.create()
+            .withPackageName(nonSystemUidPackageNameTargetsQ)
+            .withUid(nonSystemUid)
+            .withTargetSdk(Build.VERSION_CODES.Q)
+            .build();
+        when(mPackageManagerInternal.getApplicationInfo(
+                 eq(nonSystemUidPackageNameTargetsQ), anyLong(), anyInt(), anyInt()))
+            .thenReturn(nonSystemUidAppInfo2);
+
+        when(mPackageManager.getPackagesForUid(eq(Process.SYSTEM_UID)))
+            .thenReturn(new String[] {systemUidPackageNameTargetsR, systemUidPackageNameTargetsQ});
+        when(mPackageManager.getPackagesForUid(eq(nonSystemUid)))
+            .thenReturn(new String[] {
+                            nonSystemUidPackageNameTargetsR, nonSystemUidPackageNameTargetsQ
+                        });
+
+        assertThat(mPlatformCompat.isChangeEnabledByUid(1L, Process.SYSTEM_UID))
+            .isEqualTo(expectSystemUidTargetSystemSdk);
+        assertThat(mPlatformCompat.isChangeEnabledByUid(1L, nonSystemUid)).isFalse();
+    }
 }
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 733f056..ab5a5a9 100644
--- a/services/tests/servicestests/src/com/android/server/devicestate/DeviceStateManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicestate/DeviceStateManagerServiceTest.java
@@ -24,13 +24,9 @@
 
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
-import static org.testng.Assert.assertEquals;
-import static org.testng.Assert.assertFalse;
-import static org.testng.Assert.assertNotNull;
-import static org.testng.Assert.assertNull;
 import static org.testng.Assert.assertThrows;
 
-import android.annotation.NonNull;
+import android.content.Context;
 import android.hardware.devicestate.DeviceState;
 import android.hardware.devicestate.DeviceStateInfo;
 import android.hardware.devicestate.DeviceStateRequest;
@@ -39,16 +35,20 @@
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.platform.test.annotations.Presubmit;
+import android.platform.test.flag.junit.FlagsParameterization;
+import android.platform.test.flag.junit.SetFlagsRule;
 
-import androidx.test.InstrumentationRegistry;
+import androidx.annotation.NonNull;
 import androidx.test.filters.FlakyTest;
-import androidx.test.runner.AndroidJUnit4;
+import androidx.test.platform.app.InstrumentationRegistry;
 
 import com.android.compatibility.common.util.PollingCheck;
 import com.android.server.wm.ActivityTaskManagerInternal;
 import com.android.server.wm.WindowProcessController;
+import com.android.window.flags.Flags;
 
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -61,18 +61,30 @@
 
 import javax.annotation.Nullable;
 
+import platform.test.runner.parameterized.ParameterizedAndroidJunit4;
+import platform.test.runner.parameterized.Parameters;
+
 /**
  * Unit tests for {@link DeviceStateManagerService}.
- * <p/>
- * Run with <code>atest DeviceStateManagerServiceTest</code>.
+ *
+ * <p> Build/Install/Run:
+ * atest FrameworksServicesTests:DeviceStateManagerServiceTest
  */
 @Presubmit
-@RunWith(AndroidJUnit4.class)
+@RunWith(ParameterizedAndroidJunit4.class)
 public final class DeviceStateManagerServiceTest {
     private static final DeviceState DEFAULT_DEVICE_STATE = new DeviceState(
             new DeviceState.Configuration.Builder(0, "DEFAULT").build());
+    private static final int DEFAULT_DEVICE_STATE_IDENTIFIER = DEFAULT_DEVICE_STATE.getIdentifier();
+    private static final String DEFAULT_DEVICE_STATE_TRACE_STRING =
+            DEFAULT_DEVICE_STATE_IDENTIFIER + ":" + DEFAULT_DEVICE_STATE.getName();
+
     private static final DeviceState OTHER_DEVICE_STATE = new DeviceState(
             new DeviceState.Configuration.Builder(1, "DEFAULT").build());
+    private static final int OTHER_DEVICE_STATE_IDENTIFIER = OTHER_DEVICE_STATE.getIdentifier();
+    private static final String OTHER_DEVICE_STATE_TRACE_STRING =
+            OTHER_DEVICE_STATE_IDENTIFIER + ":" + OTHER_DEVICE_STATE.getName();
+
     private static final DeviceState DEVICE_STATE_CANCEL_WHEN_REQUESTER_NOT_ON_TOP =
             new DeviceState(new DeviceState.Configuration.Builder(2,
                     "DEVICE_STATE_CANCEL_WHEN_REQUESTER_NOT_ON_TOP")
@@ -93,24 +105,43 @@
 
     private static final int TIMEOUT = 2000;
 
+    @Rule
+    public final SetFlagsRule mSetFlagsRule;
+
+    @Parameters(name = "{0}")
+    public static List<FlagsParameterization> getParams() {
+        return FlagsParameterization.allCombinationsOf(Flags.FLAG_WLINFO_ONCREATE);
+    }
+
+    private final Context mContext = InstrumentationRegistry.getInstrumentation().getContext();
+    @NonNull
     private TestDeviceStatePolicy mPolicy;
+    @NonNull
     private TestDeviceStateProvider mProvider;
+    @NonNull
     private DeviceStateManagerService mService;
+    @NonNull
     private TestSystemPropertySetter mSysPropSetter;
+    @NonNull
     private WindowProcessController mWindowProcessController;
 
+    public DeviceStateManagerServiceTest(FlagsParameterization flags) {
+        mSetFlagsRule = new SetFlagsRule(flags);
+    }
+
     @Before
     public void setup() {
         mProvider = new TestDeviceStateProvider();
-        mPolicy = new TestDeviceStatePolicy(mProvider);
+        mPolicy = new TestDeviceStatePolicy(mContext, mProvider);
         mSysPropSetter = new TestSystemPropertySetter();
         setupDeviceStateManagerService();
-        flushHandler(); // Flush the handler to ensure the initial values are committed.
+        if (!Flags.wlinfoOncreate()) {
+            flushHandler(); // Flush the handler to ensure the initial values are committed.
+        }
     }
 
     private void setupDeviceStateManagerService() {
-        mService = new DeviceStateManagerService(InstrumentationRegistry.getContext(), mPolicy,
-                mSysPropSetter);
+        mService = new DeviceStateManagerService(mContext, mPolicy, mSysPropSetter);
 
         // Necessary to allow us to check for top app process id in tests
         mService.mActivityTaskManagerInternal = mock(ActivityTaskManagerInternal.class);
@@ -136,56 +167,53 @@
 
     @Test
     public void baseStateChanged() {
-        assertEquals(mService.getCommittedState(), Optional.of(DEFAULT_DEVICE_STATE));
-        assertEquals(mService.getPendingState(), Optional.empty());
-        assertEquals(mSysPropSetter.getValue(),
-                DEFAULT_DEVICE_STATE.getIdentifier() + ":" + DEFAULT_DEVICE_STATE.getName());
-        assertEquals(mService.getBaseState(), Optional.of(DEFAULT_DEVICE_STATE));
-        assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(),
-                DEFAULT_DEVICE_STATE.getIdentifier());
+        assertThat(mService.getCommittedState()).hasValue(DEFAULT_DEVICE_STATE);
+        assertThat(mService.getPendingState()).isEmpty();
+        assertThat(mSysPropSetter.getValue()).isEqualTo(DEFAULT_DEVICE_STATE_TRACE_STRING);
+        assertThat(mService.getBaseState()).hasValue(DEFAULT_DEVICE_STATE);
+        assertThat(mPolicy.getMostRecentRequestedStateToConfigure())
+                .isEqualTo(DEFAULT_DEVICE_STATE_IDENTIFIER);
 
-        mProvider.setState(OTHER_DEVICE_STATE.getIdentifier());
+        mProvider.setState(OTHER_DEVICE_STATE_IDENTIFIER);
         flushHandler();
-        assertEquals(mService.getCommittedState(), Optional.of(OTHER_DEVICE_STATE));
-        assertEquals(mService.getPendingState(), Optional.empty());
-        assertEquals(mSysPropSetter.getValue(),
-                OTHER_DEVICE_STATE.getIdentifier() + ":" + OTHER_DEVICE_STATE.getName());
-        assertEquals(mService.getBaseState(), Optional.of(OTHER_DEVICE_STATE));
-        assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(),
-                OTHER_DEVICE_STATE.getIdentifier());
+
+        assertThat(mService.getCommittedState()).hasValue(OTHER_DEVICE_STATE);
+        assertThat(mService.getPendingState()).isEmpty();
+        assertThat(mSysPropSetter.getValue()).isEqualTo(OTHER_DEVICE_STATE_TRACE_STRING);
+        assertThat(mService.getBaseState()).hasValue(OTHER_DEVICE_STATE);
+        assertThat(mPolicy.getMostRecentRequestedStateToConfigure())
+                .isEqualTo(OTHER_DEVICE_STATE_IDENTIFIER);
     }
 
     @Test
     public void baseStateChanged_withStatePendingPolicyCallback() {
         mPolicy.blockConfigure();
 
-        mProvider.setState(OTHER_DEVICE_STATE.getIdentifier());
+        mProvider.setState(OTHER_DEVICE_STATE_IDENTIFIER);
         flushHandler();
-        assertEquals(mService.getCommittedState(), Optional.of(DEFAULT_DEVICE_STATE));
-        assertEquals(mService.getPendingState(), Optional.of(OTHER_DEVICE_STATE));
-        assertEquals(mSysPropSetter.getValue(),
-                DEFAULT_DEVICE_STATE.getIdentifier() + ":" + DEFAULT_DEVICE_STATE.getName());
-        assertEquals(mService.getBaseState(), Optional.of(OTHER_DEVICE_STATE));
-        assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(),
-                OTHER_DEVICE_STATE.getIdentifier());
+        assertThat(mService.getCommittedState()).hasValue(DEFAULT_DEVICE_STATE);
+        assertThat(mService.getPendingState()).hasValue(OTHER_DEVICE_STATE);
+        assertThat(mSysPropSetter.getValue()).isEqualTo(DEFAULT_DEVICE_STATE_TRACE_STRING);
+        assertThat(mService.getBaseState()).hasValue(OTHER_DEVICE_STATE);
+        assertThat(mPolicy.getMostRecentRequestedStateToConfigure())
+                .isEqualTo(OTHER_DEVICE_STATE_IDENTIFIER);
 
-        mProvider.setState(DEFAULT_DEVICE_STATE.getIdentifier());
+        mProvider.setState(DEFAULT_DEVICE_STATE_IDENTIFIER);
         flushHandler();
-        assertEquals(mService.getCommittedState(), Optional.of(DEFAULT_DEVICE_STATE));
-        assertEquals(mService.getPendingState(), Optional.of(OTHER_DEVICE_STATE));
-        assertEquals(mSysPropSetter.getValue(),
-                DEFAULT_DEVICE_STATE.getIdentifier() + ":" + DEFAULT_DEVICE_STATE.getName());
-        assertEquals(mService.getBaseState(), Optional.of(DEFAULT_DEVICE_STATE));
-        assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(),
-                OTHER_DEVICE_STATE.getIdentifier());
+        assertThat(mService.getCommittedState()).hasValue(DEFAULT_DEVICE_STATE);
+        assertThat(mService.getPendingState()).hasValue(OTHER_DEVICE_STATE);
+        assertThat(mSysPropSetter.getValue()).isEqualTo(DEFAULT_DEVICE_STATE_TRACE_STRING);
+        assertThat(mService.getBaseState()).hasValue(DEFAULT_DEVICE_STATE);
+        assertThat(mPolicy.getMostRecentRequestedStateToConfigure())
+                .isEqualTo(OTHER_DEVICE_STATE_IDENTIFIER);
 
         mPolicy.resumeConfigure();
         flushHandler();
-        assertEquals(mService.getCommittedState(), Optional.of(DEFAULT_DEVICE_STATE));
-        assertEquals(mService.getPendingState(), Optional.empty());
-        assertEquals(mService.getBaseState(), Optional.of(DEFAULT_DEVICE_STATE));
-        assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(),
-                DEFAULT_DEVICE_STATE.getIdentifier());
+        assertThat(mService.getCommittedState()).hasValue(DEFAULT_DEVICE_STATE);
+        assertThat(mService.getPendingState()).isEmpty();
+        assertThat(mService.getBaseState()).hasValue(DEFAULT_DEVICE_STATE);
+        assertThat(mPolicy.getMostRecentRequestedStateToConfigure())
+                .isEqualTo(DEFAULT_DEVICE_STATE_IDENTIFIER);
     }
 
     @Test
@@ -194,13 +222,12 @@
             mProvider.setState(UNSUPPORTED_DEVICE_STATE.getIdentifier());
         });
 
-        assertEquals(mService.getCommittedState(), Optional.of(DEFAULT_DEVICE_STATE));
-        assertEquals(mService.getPendingState(), Optional.empty());
-        assertEquals(mSysPropSetter.getValue(),
-                DEFAULT_DEVICE_STATE.getIdentifier() + ":" + DEFAULT_DEVICE_STATE.getName());
-        assertEquals(mService.getBaseState(), Optional.of(DEFAULT_DEVICE_STATE));
-        assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(),
-                DEFAULT_DEVICE_STATE.getIdentifier());
+        assertThat(mService.getCommittedState()).hasValue(DEFAULT_DEVICE_STATE);
+        assertThat(mService.getPendingState()).isEmpty();
+        assertThat(mSysPropSetter.getValue()).isEqualTo(DEFAULT_DEVICE_STATE_TRACE_STRING);
+        assertThat(mService.getBaseState()).hasValue(DEFAULT_DEVICE_STATE);
+        assertThat(mPolicy.getMostRecentRequestedStateToConfigure())
+                .isEqualTo(DEFAULT_DEVICE_STATE_IDENTIFIER);
     }
 
     @Test
@@ -208,25 +235,23 @@
         assertThrows(IllegalArgumentException.class,
                 () -> mProvider.setState(INVALID_DEVICE_STATE_IDENTIFIER));
 
-        assertEquals(mService.getCommittedState(), Optional.of(DEFAULT_DEVICE_STATE));
-        assertEquals(mService.getPendingState(), Optional.empty());
-        assertEquals(mSysPropSetter.getValue(),
-                DEFAULT_DEVICE_STATE.getIdentifier() + ":" + DEFAULT_DEVICE_STATE.getName());
-        assertEquals(mService.getBaseState(), Optional.of(DEFAULT_DEVICE_STATE));
-        assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(),
-                DEFAULT_DEVICE_STATE.getIdentifier());
+        assertThat(mService.getCommittedState()).hasValue(DEFAULT_DEVICE_STATE);
+        assertThat(mService.getPendingState()).isEmpty();
+        assertThat(mSysPropSetter.getValue()).isEqualTo(DEFAULT_DEVICE_STATE_TRACE_STRING);
+        assertThat(mService.getBaseState()).hasValue(DEFAULT_DEVICE_STATE);
+        assertThat(mPolicy.getMostRecentRequestedStateToConfigure())
+                .isEqualTo(DEFAULT_DEVICE_STATE_IDENTIFIER);
     }
 
     @Test
     public void supportedStatesChanged() throws RemoteException {
-        TestDeviceStateManagerCallback callback = new TestDeviceStateManagerCallback();
+        final TestDeviceStateManagerCallback callback = new TestDeviceStateManagerCallback();
         mService.getBinderService().registerCallback(callback);
 
-        assertEquals(mService.getCommittedState(), Optional.of(DEFAULT_DEVICE_STATE));
-        assertEquals(mService.getPendingState(), Optional.empty());
-        assertEquals(mSysPropSetter.getValue(),
-                DEFAULT_DEVICE_STATE.getIdentifier() + ":" + DEFAULT_DEVICE_STATE.getName());
-        assertEquals(mService.getBaseState(), Optional.of(DEFAULT_DEVICE_STATE));
+        assertThat(mService.getCommittedState()).hasValue(DEFAULT_DEVICE_STATE);
+        assertThat(mService.getPendingState()).isEmpty();
+        assertThat(mSysPropSetter.getValue()).isEqualTo(DEFAULT_DEVICE_STATE_TRACE_STRING);
+        assertThat(mService.getBaseState()).hasValue(DEFAULT_DEVICE_STATE);
         assertThat(mService.getSupportedStates()).containsExactly(DEFAULT_DEVICE_STATE,
                 OTHER_DEVICE_STATE, DEVICE_STATE_CANCEL_WHEN_REQUESTER_NOT_ON_TOP);
 
@@ -235,30 +260,31 @@
 
         // The current committed and requests states do not change because the current state remains
         // supported.
-        assertEquals(mService.getCommittedState(), Optional.of(DEFAULT_DEVICE_STATE));
-        assertEquals(mService.getPendingState(), Optional.empty());
-        assertEquals(mSysPropSetter.getValue(),
-                DEFAULT_DEVICE_STATE.getIdentifier() + ":" + DEFAULT_DEVICE_STATE.getName());
-        assertEquals(mService.getBaseState(), Optional.of(DEFAULT_DEVICE_STATE));
+        assertThat(mService.getCommittedState()).hasValue(DEFAULT_DEVICE_STATE);
+        assertThat(mService.getPendingState()).isEmpty();
+        assertThat(mSysPropSetter.getValue()).isEqualTo(DEFAULT_DEVICE_STATE_TRACE_STRING);
+        assertThat(mService.getBaseState()).hasValue(DEFAULT_DEVICE_STATE);
         assertThat(mService.getSupportedStates()).containsExactly(DEFAULT_DEVICE_STATE);
 
-        assertEquals(callback.getLastNotifiedInfo().supportedStates, List.of(DEFAULT_DEVICE_STATE));
+        assertThat(callback.getLastNotifiedInfo().supportedStates)
+                .containsExactly(DEFAULT_DEVICE_STATE);
     }
 
     @Test
     public void supportedStatesChanged_statesRemainSame() throws RemoteException {
-        TestDeviceStateManagerCallback callback = new TestDeviceStateManagerCallback();
+        final TestDeviceStateManagerCallback callback = new TestDeviceStateManagerCallback();
         mService.getBinderService().registerCallback(callback);
 
-        // An initial callback will be triggered on registration, so we clear it here.
-        flushHandler();
-        callback.clearLastNotifiedInfo();
+        if (!Flags.wlinfoOncreate()) {
+            // An initial callback will be triggered on registration, so we clear it here.
+            flushHandler();
+            callback.clearLastNotifiedInfo();
+        }
 
-        assertEquals(mService.getCommittedState(), Optional.of(DEFAULT_DEVICE_STATE));
-        assertEquals(mService.getPendingState(), Optional.empty());
-        assertEquals(mSysPropSetter.getValue(),
-                DEFAULT_DEVICE_STATE.getIdentifier() + ":" + DEFAULT_DEVICE_STATE.getName());
-        assertEquals(mService.getBaseState(), Optional.of(DEFAULT_DEVICE_STATE));
+        assertThat(mService.getCommittedState()).hasValue(DEFAULT_DEVICE_STATE);
+        assertThat(mService.getPendingState()).isEmpty();
+        assertThat(mSysPropSetter.getValue()).isEqualTo(DEFAULT_DEVICE_STATE_TRACE_STRING);
+        assertThat(mService.getBaseState()).hasValue(DEFAULT_DEVICE_STATE);
         assertThat(mService.getSupportedStates()).containsExactly(DEFAULT_DEVICE_STATE,
                 OTHER_DEVICE_STATE, DEVICE_STATE_CANCEL_WHEN_REQUESTER_NOT_ON_TOP);
 
@@ -268,26 +294,26 @@
 
         // The current committed and requests states do not change because the current state remains
         // supported.
-        assertEquals(mService.getCommittedState(), Optional.of(DEFAULT_DEVICE_STATE));
-        assertEquals(mService.getPendingState(), Optional.empty());
-        assertEquals(mSysPropSetter.getValue(),
-                DEFAULT_DEVICE_STATE.getIdentifier() + ":" + DEFAULT_DEVICE_STATE.getName());
-        assertEquals(mService.getBaseState(), Optional.of(DEFAULT_DEVICE_STATE));
+        assertThat(mService.getCommittedState()).hasValue(DEFAULT_DEVICE_STATE);
+        assertThat(mService.getPendingState()).isEmpty();
+        assertThat(mSysPropSetter.getValue()).isEqualTo(DEFAULT_DEVICE_STATE_TRACE_STRING);
+        assertThat(mService.getBaseState()).hasValue(DEFAULT_DEVICE_STATE);
         assertThat(mService.getSupportedStates()).containsExactly(DEFAULT_DEVICE_STATE,
                 OTHER_DEVICE_STATE, DEVICE_STATE_CANCEL_WHEN_REQUESTER_NOT_ON_TOP);
 
         // The callback wasn't notified about a change in supported states as the states have not
         // changed.
-        assertNull(callback.getLastNotifiedInfo());
+        assertThat(callback.getLastNotifiedInfo()).isNull();
     }
 
     @Test
     public void getDeviceStateInfo() throws RemoteException {
-        DeviceStateInfo info = mService.getBinderService().getDeviceStateInfo();
-        assertNotNull(info);
-        assertEquals(info.supportedStates, SUPPORTED_DEVICE_STATES);
-        assertEquals(info.baseState, DEFAULT_DEVICE_STATE);
-        assertEquals(info.currentState, DEFAULT_DEVICE_STATE);
+        final DeviceStateInfo info = mService.getBinderService().getDeviceStateInfo();
+        assertThat(info).isNotNull();
+        assertThat(info.supportedStates)
+                .containsExactlyElementsIn(SUPPORTED_DEVICE_STATES).inOrder();
+        assertThat(info.baseState).isEqualTo(DEFAULT_DEVICE_STATE);
+        assertThat(info.currentState).isEqualTo(DEFAULT_DEVICE_STATE);
     }
 
     @FlakyTest(bugId = 297949293)
@@ -295,105 +321,129 @@
     public void getDeviceStateInfo_baseStateAndCommittedStateNotSet() throws RemoteException {
         // Create a provider and a service without an initial base state.
         mProvider = new TestDeviceStateProvider(null /* initialState */);
-        mPolicy = new TestDeviceStatePolicy(mProvider);
+        mPolicy = new TestDeviceStatePolicy(mContext, mProvider);
         setupDeviceStateManagerService();
-        flushHandler(); // Flush the handler to ensure the initial values are committed.
+        if (!Flags.wlinfoOncreate()) {
+            flushHandler(); // Flush the handler to ensure the initial values are committed.
+        }
 
-        DeviceStateInfo info = mService.getBinderService().getDeviceStateInfo();
+        final DeviceStateInfo info = mService.getBinderService().getDeviceStateInfo();
 
-        assertEquals(info.supportedStates, SUPPORTED_DEVICE_STATES);
-        assertEquals(info.baseState.getIdentifier(), INVALID_DEVICE_STATE_IDENTIFIER);
-        assertEquals(info.currentState.getIdentifier(), INVALID_DEVICE_STATE_IDENTIFIER);
+        assertThat(info.supportedStates)
+                .containsExactlyElementsIn(SUPPORTED_DEVICE_STATES).inOrder();
+        assertThat(info.baseState.getIdentifier()).isEqualTo(INVALID_DEVICE_STATE_IDENTIFIER);
+        assertThat(info.currentState.getIdentifier()).isEqualTo(INVALID_DEVICE_STATE_IDENTIFIER);
     }
 
     @Test
     public void registerCallback() throws RemoteException {
-        TestDeviceStateManagerCallback callback = new TestDeviceStateManagerCallback();
+        final TestDeviceStateManagerCallback callback = new TestDeviceStateManagerCallback();
         mService.getBinderService().registerCallback(callback);
 
-        mProvider.setState(OTHER_DEVICE_STATE.getIdentifier());
+        mProvider.setState(OTHER_DEVICE_STATE_IDENTIFIER);
+        if (Flags.wlinfoOncreate()) {
+            waitAndAssert(() -> callback.getLastNotifiedInfo() != null);
+        }
         waitAndAssert(() -> callback.getLastNotifiedInfo().baseState.getIdentifier()
-                == OTHER_DEVICE_STATE.getIdentifier());
+                == OTHER_DEVICE_STATE_IDENTIFIER);
         waitAndAssert(() -> callback.getLastNotifiedInfo().currentState.getIdentifier()
-                == OTHER_DEVICE_STATE.getIdentifier());
+                == OTHER_DEVICE_STATE_IDENTIFIER);
 
-        mProvider.setState(DEFAULT_DEVICE_STATE.getIdentifier());
+        mProvider.setState(DEFAULT_DEVICE_STATE_IDENTIFIER);
         waitAndAssert(() -> callback.getLastNotifiedInfo().baseState.getIdentifier()
-                == DEFAULT_DEVICE_STATE.getIdentifier());
-
+                == DEFAULT_DEVICE_STATE_IDENTIFIER);
         waitAndAssert(() -> callback.getLastNotifiedInfo().currentState.getIdentifier()
-                == DEFAULT_DEVICE_STATE.getIdentifier());
+                == DEFAULT_DEVICE_STATE_IDENTIFIER);
 
         mPolicy.blockConfigure();
-        mProvider.setState(OTHER_DEVICE_STATE.getIdentifier());
+        mProvider.setState(OTHER_DEVICE_STATE_IDENTIFIER);
         // The callback should not have been notified of the state change as the policy is still
         // pending callback.
         waitAndAssert(() -> callback.getLastNotifiedInfo().baseState.getIdentifier()
-                == DEFAULT_DEVICE_STATE.getIdentifier());
+                == DEFAULT_DEVICE_STATE_IDENTIFIER);
         waitAndAssert(() -> callback.getLastNotifiedInfo().currentState.getIdentifier()
-                == DEFAULT_DEVICE_STATE.getIdentifier());
+                == DEFAULT_DEVICE_STATE_IDENTIFIER);
 
         mPolicy.resumeConfigure();
         // Now that the policy is finished processing the callback should be notified of the state
         // change.
         waitAndAssert(() -> callback.getLastNotifiedInfo().baseState.getIdentifier()
-                == OTHER_DEVICE_STATE.getIdentifier());
+                == OTHER_DEVICE_STATE_IDENTIFIER);
         waitAndAssert(() -> callback.getLastNotifiedInfo().currentState.getIdentifier()
-                == OTHER_DEVICE_STATE.getIdentifier());
+                == OTHER_DEVICE_STATE_IDENTIFIER);
     }
 
     @Test
-    public void registerCallback_emitsInitialValue() throws RemoteException {
-        TestDeviceStateManagerCallback callback = new TestDeviceStateManagerCallback();
-        mService.getBinderService().registerCallback(callback);
-        flushHandler();
-        assertNotNull(callback.getLastNotifiedInfo());
-        assertEquals(callback.getLastNotifiedInfo().baseState, DEFAULT_DEVICE_STATE);
-        assertEquals(callback.getLastNotifiedInfo().currentState, DEFAULT_DEVICE_STATE);
+    public void registerCallback_initialValueAvailable_emitsDeviceState() throws RemoteException {
+        final TestDeviceStateManagerCallback callback = new TestDeviceStateManagerCallback();
+
+        final DeviceStateInfo stateInfo;
+        if (Flags.wlinfoOncreate()) {
+            stateInfo = mService.getBinderService().registerCallback(callback);
+        } else {
+            mService.getBinderService().registerCallback(callback);
+            flushHandler();
+            stateInfo = callback.getLastNotifiedInfo();
+        }
+
+        assertThat(stateInfo).isNotNull();
+        assertThat(stateInfo.baseState).isEqualTo(DEFAULT_DEVICE_STATE);
+        assertThat(stateInfo.currentState).isEqualTo(DEFAULT_DEVICE_STATE);
     }
 
     @Test
-    public void registerCallback_initialValueUnavailable() throws RemoteException {
+    public void registerCallback_initialValueUnavailable_nullDeviceState() throws RemoteException {
         // Create a provider and a service without an initial base state.
         mProvider = new TestDeviceStateProvider(null /* initialState */);
-        mPolicy = new TestDeviceStatePolicy(mProvider);
+        mPolicy = new TestDeviceStatePolicy(mContext, mProvider);
         setupDeviceStateManagerService();
-        flushHandler(); // Flush the handler to ensure the initial values are committed.
+        if (!Flags.wlinfoOncreate()) {
+            flushHandler(); // Flush the handler to ensure the initial values are committed.
+        }
 
-        TestDeviceStateManagerCallback callback = new TestDeviceStateManagerCallback();
-        mService.getBinderService().registerCallback(callback);
-        flushHandler();
-        // The callback should never be called when the base state is not set yet.
-        assertNull(callback.getLastNotifiedInfo());
+        final TestDeviceStateManagerCallback callback = new TestDeviceStateManagerCallback();
+        final DeviceStateInfo stateInfo;
+        if (Flags.wlinfoOncreate()) {
+            // Return null when the base state is not set yet.
+            stateInfo = mService.getBinderService().registerCallback(callback);
+        } else {
+            mService.getBinderService().registerCallback(callback);
+            flushHandler();
+            // The callback should never be called when the base state is not set yet.
+            stateInfo = callback.getLastNotifiedInfo();
+        }
+
+        assertThat(stateInfo).isNull();
     }
 
     @Test
     public void requestState() throws RemoteException {
-        TestDeviceStateManagerCallback callback = new TestDeviceStateManagerCallback();
+        final TestDeviceStateManagerCallback callback = new TestDeviceStateManagerCallback();
         mService.getBinderService().registerCallback(callback);
-        flushHandler();
+        if (!Flags.wlinfoOncreate()) {
+            flushHandler();
+        }
 
         final IBinder token = new Binder();
-        assertEquals(callback.getLastNotifiedStatus(token),
-                TestDeviceStateManagerCallback.STATUS_UNKNOWN);
+        assertThat(callback.getLastNotifiedStatus(token))
+                .isEqualTo(TestDeviceStateManagerCallback.STATUS_UNKNOWN);
 
-        mService.getBinderService().requestState(token, OTHER_DEVICE_STATE.getIdentifier(),
-                0 /* flags */);
+        mService.getBinderService()
+                .requestState(token, OTHER_DEVICE_STATE_IDENTIFIER, 0 /* flags */);
 
         waitAndAssert(() -> callback.getLastNotifiedStatus(token)
                 == TestDeviceStateManagerCallback.STATUS_ACTIVE);
         // Committed state changes as there is a requested override.
-        assertEquals(mService.getCommittedState(), Optional.of(OTHER_DEVICE_STATE));
-        assertEquals(mSysPropSetter.getValue(),
-                OTHER_DEVICE_STATE.getIdentifier() + ":" + OTHER_DEVICE_STATE.getName());
-        assertEquals(mService.getBaseState(), Optional.of(DEFAULT_DEVICE_STATE));
-        assertEquals(mService.getOverrideState().get(), OTHER_DEVICE_STATE);
-        assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(),
-                OTHER_DEVICE_STATE.getIdentifier());
+        assertThat(mService.getCommittedState()).hasValue(OTHER_DEVICE_STATE);
+        assertThat(mSysPropSetter.getValue()).isEqualTo(OTHER_DEVICE_STATE_TRACE_STRING);
+        assertThat(mService.getBaseState()).hasValue(DEFAULT_DEVICE_STATE);
+        assertThat(mService.getOverrideState()).hasValue(OTHER_DEVICE_STATE);
+        assertThat(mPolicy.getMostRecentRequestedStateToConfigure())
+                .isEqualTo(OTHER_DEVICE_STATE_IDENTIFIER);
 
-        assertNotNull(callback.getLastNotifiedInfo());
-        assertEquals(callback.getLastNotifiedInfo().baseState, DEFAULT_DEVICE_STATE);
-        assertEquals(callback.getLastNotifiedInfo().currentState, OTHER_DEVICE_STATE);
+        assertThat(callback.getLastNotifiedInfo()).isNotNull();
+        assertThat(callback.getLastNotifiedInfo().baseState).isEqualTo(DEFAULT_DEVICE_STATE);
+        assertThat(callback.getLastNotifiedInfo().currentState).isEqualTo(OTHER_DEVICE_STATE);
 
         mService.getBinderService().cancelStateRequest();
 
@@ -401,156 +451,156 @@
                 == TestDeviceStateManagerCallback.STATUS_CANCELED);
         // Committed state is set back to the requested state once the override is cleared.
         waitAndAssert(() -> mService.getCommittedState().equals(Optional.of(DEFAULT_DEVICE_STATE)));
-        assertEquals(mSysPropSetter.getValue(),
-                DEFAULT_DEVICE_STATE.getIdentifier() + ":" + DEFAULT_DEVICE_STATE.getName());
-        assertEquals(mService.getBaseState(), Optional.of(DEFAULT_DEVICE_STATE));
-        assertFalse(mService.getOverrideState().isPresent());
-        assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(),
-                DEFAULT_DEVICE_STATE.getIdentifier());
+        assertThat(mSysPropSetter.getValue()).isEqualTo(DEFAULT_DEVICE_STATE_TRACE_STRING);
+        assertThat(mService.getBaseState()).hasValue(DEFAULT_DEVICE_STATE);
+        assertThat(mService.getOverrideState()).isEmpty();
+        assertThat(mPolicy.getMostRecentRequestedStateToConfigure())
+                .isEqualTo(DEFAULT_DEVICE_STATE_IDENTIFIER);
 
-        assertEquals(callback.getLastNotifiedInfo().baseState, DEFAULT_DEVICE_STATE);
-        assertEquals(callback.getLastNotifiedInfo().currentState, DEFAULT_DEVICE_STATE);
+        assertThat(callback.getLastNotifiedInfo().baseState).isEqualTo(DEFAULT_DEVICE_STATE);
+        assertThat(callback.getLastNotifiedInfo().currentState).isEqualTo(DEFAULT_DEVICE_STATE);
     }
 
     @FlakyTest(bugId = 200332057)
     @Test
     public void requestState_pendingStateAtRequest() throws RemoteException {
-        TestDeviceStateManagerCallback callback = new TestDeviceStateManagerCallback();
+        final TestDeviceStateManagerCallback callback = new TestDeviceStateManagerCallback();
         mService.getBinderService().registerCallback(callback);
-        flushHandler();
+        if (!Flags.wlinfoOncreate()) {
+            flushHandler();
+        }
 
         mPolicy.blockConfigure();
 
         final IBinder firstRequestToken = new Binder();
         final IBinder secondRequestToken = new Binder();
-        assertEquals(callback.getLastNotifiedStatus(firstRequestToken),
-                TestDeviceStateManagerCallback.STATUS_UNKNOWN);
-        assertEquals(callback.getLastNotifiedStatus(secondRequestToken),
-                TestDeviceStateManagerCallback.STATUS_UNKNOWN);
+        assertThat(callback.getLastNotifiedStatus(firstRequestToken))
+                .isEqualTo(TestDeviceStateManagerCallback.STATUS_UNKNOWN);
+        assertThat(callback.getLastNotifiedStatus(secondRequestToken))
+                .isEqualTo(TestDeviceStateManagerCallback.STATUS_UNKNOWN);
 
-        mService.getBinderService().requestState(firstRequestToken,
-                OTHER_DEVICE_STATE.getIdentifier(), 0 /* flags */);
+        mService.getBinderService()
+                .requestState(firstRequestToken, OTHER_DEVICE_STATE_IDENTIFIER, 0 /* flags */);
         // Flush the handler twice. The first flush ensures the request is added and the policy is
         // notified, while the second flush ensures the callback is notified once the change is
         // committed.
         flushHandler(2 /* count */);
 
-        assertEquals(mService.getCommittedState(), Optional.of(DEFAULT_DEVICE_STATE));
-        assertEquals(mService.getPendingState(), Optional.of(OTHER_DEVICE_STATE));
-        assertEquals(mService.getBaseState(), Optional.of(DEFAULT_DEVICE_STATE));
-        assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(),
-                OTHER_DEVICE_STATE.getIdentifier());
+        assertThat(mService.getCommittedState()).hasValue(DEFAULT_DEVICE_STATE);
+        assertThat(mService.getPendingState()).hasValue(OTHER_DEVICE_STATE);
+        assertThat(mService.getBaseState()).hasValue(DEFAULT_DEVICE_STATE);
+        assertThat(mPolicy.getMostRecentRequestedStateToConfigure())
+                .isEqualTo(OTHER_DEVICE_STATE_IDENTIFIER);
 
-        mService.getBinderService().requestState(secondRequestToken,
-                DEFAULT_DEVICE_STATE.getIdentifier(), 0 /* flags */);
+        mService.getBinderService()
+                .requestState(secondRequestToken, DEFAULT_DEVICE_STATE_IDENTIFIER, 0 /* flags */);
         mPolicy.resumeConfigureOnce();
         flushHandler();
 
         // First request status is now canceled as there is another pending request.
-        assertEquals(callback.getLastNotifiedStatus(firstRequestToken),
-                TestDeviceStateManagerCallback.STATUS_CANCELED);
+        assertThat(callback.getLastNotifiedStatus(firstRequestToken))
+                .isEqualTo(TestDeviceStateManagerCallback.STATUS_CANCELED);
         // Second request status still unknown because the service is still awaiting policy
         // callback.
-        assertEquals(callback.getLastNotifiedStatus(secondRequestToken),
-                TestDeviceStateManagerCallback.STATUS_UNKNOWN);
-        assertEquals(mService.getCommittedState(), Optional.of(OTHER_DEVICE_STATE));
-        assertEquals(mService.getPendingState(), Optional.of(DEFAULT_DEVICE_STATE));
-        assertEquals(mSysPropSetter.getValue(),
-                OTHER_DEVICE_STATE.getIdentifier() + ":" + OTHER_DEVICE_STATE.getName());
-        assertEquals(mService.getBaseState(), Optional.of(DEFAULT_DEVICE_STATE));
-        assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(),
-                DEFAULT_DEVICE_STATE.getIdentifier());
+        assertThat(callback.getLastNotifiedStatus(secondRequestToken))
+                .isEqualTo(TestDeviceStateManagerCallback.STATUS_UNKNOWN);
+        assertThat(mService.getCommittedState()).hasValue(OTHER_DEVICE_STATE);
+        assertThat(mService.getPendingState()).hasValue(DEFAULT_DEVICE_STATE);
+        assertThat(mSysPropSetter.getValue()).isEqualTo(OTHER_DEVICE_STATE_TRACE_STRING);
+        assertThat(mService.getBaseState()).hasValue(DEFAULT_DEVICE_STATE);
+        assertThat(mPolicy.getMostRecentRequestedStateToConfigure())
+                .isEqualTo(DEFAULT_DEVICE_STATE_IDENTIFIER);
 
         mPolicy.resumeConfigure();
         flushHandler();
 
-        assertEquals(mService.getCommittedState(), Optional.of(DEFAULT_DEVICE_STATE));
-        assertEquals(mService.getPendingState(), Optional.empty());
-        assertEquals(mSysPropSetter.getValue(),
-                DEFAULT_DEVICE_STATE.getIdentifier() + ":" + DEFAULT_DEVICE_STATE.getName());
-        assertEquals(mService.getBaseState(), Optional.of(DEFAULT_DEVICE_STATE));
-        assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(),
-                DEFAULT_DEVICE_STATE.getIdentifier());
+        assertThat(mService.getCommittedState()).hasValue(DEFAULT_DEVICE_STATE);
+        assertThat(mService.getPendingState()).isEmpty();
+        assertThat(mSysPropSetter.getValue()).isEqualTo(DEFAULT_DEVICE_STATE_TRACE_STRING);
+        assertThat(mService.getBaseState()).hasValue(DEFAULT_DEVICE_STATE);
+        assertThat(mPolicy.getMostRecentRequestedStateToConfigure())
+                .isEqualTo(DEFAULT_DEVICE_STATE_IDENTIFIER);
 
         // Now cancel the second request to make the first request active.
         mService.getBinderService().cancelStateRequest();
         flushHandler();
 
-        assertEquals(callback.getLastNotifiedStatus(firstRequestToken),
-                TestDeviceStateManagerCallback.STATUS_CANCELED);
-        assertEquals(callback.getLastNotifiedStatus(secondRequestToken),
-                TestDeviceStateManagerCallback.STATUS_CANCELED);
+        assertThat(callback.getLastNotifiedStatus(firstRequestToken))
+                .isEqualTo(TestDeviceStateManagerCallback.STATUS_CANCELED);
+        assertThat(callback.getLastNotifiedStatus(secondRequestToken))
+                .isEqualTo(TestDeviceStateManagerCallback.STATUS_CANCELED);
 
-        assertEquals(mService.getCommittedState(), Optional.of(DEFAULT_DEVICE_STATE));
-        assertEquals(mService.getPendingState(), Optional.empty());
-        assertEquals(mSysPropSetter.getValue(),
-                DEFAULT_DEVICE_STATE.getIdentifier() + ":" + DEFAULT_DEVICE_STATE.getName());
-        assertEquals(mService.getBaseState(), Optional.of(DEFAULT_DEVICE_STATE));
-        assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(),
-                DEFAULT_DEVICE_STATE.getIdentifier());
+        assertThat(mService.getCommittedState()).hasValue(DEFAULT_DEVICE_STATE);
+        assertThat(mService.getPendingState()).isEmpty();
+        assertThat(mSysPropSetter.getValue()).isEqualTo(DEFAULT_DEVICE_STATE_TRACE_STRING);
+        assertThat(mService.getBaseState()).hasValue(DEFAULT_DEVICE_STATE);
+        assertThat(mPolicy.getMostRecentRequestedStateToConfigure())
+                .isEqualTo(DEFAULT_DEVICE_STATE_IDENTIFIER);
     }
 
     @Test
     public void requestState_sameAsBaseState() throws RemoteException {
-        TestDeviceStateManagerCallback callback = new TestDeviceStateManagerCallback();
+        final TestDeviceStateManagerCallback callback = new TestDeviceStateManagerCallback();
         mService.getBinderService().registerCallback(callback);
-        flushHandler();
+        if (!Flags.wlinfoOncreate()) {
+            flushHandler();
+        }
 
         final IBinder token = new Binder();
-        assertEquals(callback.getLastNotifiedStatus(token),
-                TestDeviceStateManagerCallback.STATUS_UNKNOWN);
+        assertThat(callback.getLastNotifiedStatus(token))
+                .isEqualTo(TestDeviceStateManagerCallback.STATUS_UNKNOWN);
 
-        mService.getBinderService().requestState(token, DEFAULT_DEVICE_STATE.getIdentifier(),
-                0 /* flags */);
+        mService.getBinderService()
+                .requestState(token, DEFAULT_DEVICE_STATE_IDENTIFIER, 0 /* flags */);
         flushHandler();
 
-        assertEquals(callback.getLastNotifiedStatus(token),
-                TestDeviceStateManagerCallback.STATUS_ACTIVE);
+        assertThat(callback.getLastNotifiedStatus(token))
+                .isEqualTo(TestDeviceStateManagerCallback.STATUS_ACTIVE);
     }
 
     @Test
     public void requestState_flagCancelWhenBaseChanges() throws RemoteException {
-        TestDeviceStateManagerCallback callback = new TestDeviceStateManagerCallback();
+        final TestDeviceStateManagerCallback callback = new TestDeviceStateManagerCallback();
         mService.getBinderService().registerCallback(callback);
-        flushHandler();
+        if (!Flags.wlinfoOncreate()) {
+            flushHandler();
+        }
 
         final IBinder token = new Binder();
-        assertEquals(callback.getLastNotifiedStatus(token),
-                TestDeviceStateManagerCallback.STATUS_UNKNOWN);
+        assertThat(callback.getLastNotifiedStatus(token))
+                .isEqualTo(TestDeviceStateManagerCallback.STATUS_UNKNOWN);
 
-        mService.getBinderService().requestState(token, OTHER_DEVICE_STATE.getIdentifier(),
+        mService.getBinderService().requestState(token, OTHER_DEVICE_STATE_IDENTIFIER,
                 DeviceStateRequest.FLAG_CANCEL_WHEN_BASE_CHANGES);
         // Flush the handler twice. The first flush ensures the request is added and the policy is
         // notified, while the second flush ensures the callback is notified once the change is
         // committed.
         flushHandler(2 /* count */);
 
-        assertEquals(callback.getLastNotifiedStatus(token),
-                TestDeviceStateManagerCallback.STATUS_ACTIVE);
+        assertThat(callback.getLastNotifiedStatus(token))
+                .isEqualTo(TestDeviceStateManagerCallback.STATUS_ACTIVE);
 
         // Committed state changes as there is a requested override.
-        assertEquals(mService.getCommittedState(), Optional.of(OTHER_DEVICE_STATE));
-        assertEquals(mService.getBaseState(), Optional.of(DEFAULT_DEVICE_STATE));
-        assertEquals(mSysPropSetter.getValue(),
-                OTHER_DEVICE_STATE.getIdentifier() + ":" + OTHER_DEVICE_STATE.getName());
-        assertEquals(mService.getOverrideState().get(), OTHER_DEVICE_STATE);
-        assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(),
-                OTHER_DEVICE_STATE.getIdentifier());
+        assertThat(mService.getCommittedState()).hasValue(OTHER_DEVICE_STATE);
+        assertThat(mService.getBaseState()).hasValue(DEFAULT_DEVICE_STATE);
+        assertThat(mSysPropSetter.getValue()).isEqualTo(OTHER_DEVICE_STATE_TRACE_STRING);
+        assertThat(mService.getOverrideState()).hasValue(OTHER_DEVICE_STATE);
+        assertThat(mPolicy.getMostRecentRequestedStateToConfigure())
+                .isEqualTo(OTHER_DEVICE_STATE_IDENTIFIER);
 
-        mProvider.setState(OTHER_DEVICE_STATE.getIdentifier());
+        mProvider.setState(OTHER_DEVICE_STATE_IDENTIFIER);
         flushHandler();
 
         // Request is canceled because the base state changed.
-        assertEquals(callback.getLastNotifiedStatus(token),
-                TestDeviceStateManagerCallback.STATUS_CANCELED);
+        assertThat(callback.getLastNotifiedStatus(token))
+                .isEqualTo(TestDeviceStateManagerCallback.STATUS_CANCELED);
         // Committed state is set back to the requested state once the override is cleared.
-        assertEquals(mService.getCommittedState(), Optional.of(OTHER_DEVICE_STATE));
-        assertEquals(mService.getBaseState(), Optional.of(OTHER_DEVICE_STATE));
-        assertEquals(mSysPropSetter.getValue(),
-                OTHER_DEVICE_STATE.getIdentifier() + ":" + OTHER_DEVICE_STATE.getName());
-        assertFalse(mService.getOverrideState().isPresent());
-        assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(),
-                OTHER_DEVICE_STATE.getIdentifier());
+        assertThat(mService.getCommittedState()).hasValue(OTHER_DEVICE_STATE);
+        assertThat(mService.getBaseState()).hasValue(OTHER_DEVICE_STATE);
+        assertThat(mSysPropSetter.getValue()).isEqualTo(OTHER_DEVICE_STATE_TRACE_STRING);
+        assertThat(mService.getOverrideState()).isEmpty();
+        assertThat(mPolicy.getMostRecentRequestedStateToConfigure())
+                .isEqualTo(OTHER_DEVICE_STATE_IDENTIFIER);
     }
 
     @Test
@@ -581,8 +631,8 @@
         requestState_flagCancelWhenRequesterNotOnTop_common(
                 // When the app is foreground, the state should not change
                 () -> {
-                    int pid = Binder.getCallingPid();
-                    int uid = Binder.getCallingUid();
+                    final int pid = Binder.getCallingPid();
+                    final int uid = Binder.getCallingUid();
                     try {
                         mService.mProcessObserver.onForegroundActivitiesChanged(pid, uid,
                                 true /* foregroundActivities */);
@@ -594,8 +644,8 @@
                 () -> {
                     when(mWindowProcessController.getPid()).thenReturn(FAKE_PROCESS_ID);
                     try {
-                        int pid = Binder.getCallingPid();
-                        int uid = Binder.getCallingUid();
+                        final int pid = Binder.getCallingPid();
+                        final int uid = Binder.getCallingUid();
                         mService.mProcessObserver.onForegroundActivitiesChanged(pid, uid,
                                 false /* foregroundActivities */);
 
@@ -609,68 +659,68 @@
     @FlakyTest(bugId = 200332057)
     @Test
     public void requestState_becomesUnsupported() throws RemoteException {
-        TestDeviceStateManagerCallback callback = new TestDeviceStateManagerCallback();
+        final TestDeviceStateManagerCallback callback = new TestDeviceStateManagerCallback();
         mService.getBinderService().registerCallback(callback);
-        flushHandler();
+        if (!Flags.wlinfoOncreate()) {
+            flushHandler();
+        }
 
         final IBinder token = new Binder();
-        assertEquals(callback.getLastNotifiedStatus(token),
-                TestDeviceStateManagerCallback.STATUS_UNKNOWN);
+        assertThat(callback.getLastNotifiedStatus(token))
+                .isEqualTo(TestDeviceStateManagerCallback.STATUS_UNKNOWN);
 
-        mService.getBinderService().requestState(token, OTHER_DEVICE_STATE.getIdentifier(),
-                0 /* flags */);
+        mService.getBinderService()
+                .requestState(token, OTHER_DEVICE_STATE_IDENTIFIER, 0 /* flags */);
         flushHandler();
 
-        assertEquals(callback.getLastNotifiedStatus(token),
-                TestDeviceStateManagerCallback.STATUS_ACTIVE);
+        assertThat(callback.getLastNotifiedStatus(token))
+                .isEqualTo(TestDeviceStateManagerCallback.STATUS_ACTIVE);
         // Committed state changes as there is a requested override.
-        assertEquals(mService.getCommittedState(), Optional.of(OTHER_DEVICE_STATE));
-        assertEquals(mSysPropSetter.getValue(),
-                OTHER_DEVICE_STATE.getIdentifier() + ":" + OTHER_DEVICE_STATE.getName());
-        assertEquals(mService.getBaseState(), Optional.of(DEFAULT_DEVICE_STATE));
-        assertEquals(mService.getOverrideState().get(), OTHER_DEVICE_STATE);
-        assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(),
-                OTHER_DEVICE_STATE.getIdentifier());
+        assertThat(mService.getCommittedState()).hasValue(OTHER_DEVICE_STATE);
+        assertThat(mSysPropSetter.getValue()).isEqualTo(OTHER_DEVICE_STATE_TRACE_STRING);
+        assertThat(mService.getBaseState()).hasValue(DEFAULT_DEVICE_STATE);
+        assertThat(mService.getOverrideState()).hasValue(OTHER_DEVICE_STATE);
+        assertThat(mPolicy.getMostRecentRequestedStateToConfigure())
+                .isEqualTo(OTHER_DEVICE_STATE_IDENTIFIER);
 
         mProvider.notifySupportedDeviceStates(
                 new DeviceState[]{DEFAULT_DEVICE_STATE});
         flushHandler();
 
         // Request is canceled because the state is no longer supported.
-        assertEquals(callback.getLastNotifiedStatus(token),
-                TestDeviceStateManagerCallback.STATUS_CANCELED);
+        assertThat(callback.getLastNotifiedStatus(token))
+                .isEqualTo(TestDeviceStateManagerCallback.STATUS_CANCELED);
         // Committed state is set back to the requested state as the override state is no longer
         // supported.
-        assertEquals(mService.getCommittedState(), Optional.of(DEFAULT_DEVICE_STATE));
-        assertEquals(mSysPropSetter.getValue(),
-                DEFAULT_DEVICE_STATE.getIdentifier() + ":" + DEFAULT_DEVICE_STATE.getName());
-        assertEquals(mService.getBaseState(), Optional.of(DEFAULT_DEVICE_STATE));
-        assertFalse(mService.getOverrideState().isPresent());
-        assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(),
-                DEFAULT_DEVICE_STATE.getIdentifier());
+        assertThat(mService.getCommittedState()).hasValue(DEFAULT_DEVICE_STATE);
+        assertThat(mSysPropSetter.getValue()).isEqualTo(DEFAULT_DEVICE_STATE_TRACE_STRING);
+        assertThat(mService.getBaseState()).hasValue(DEFAULT_DEVICE_STATE);
+        assertThat(mService.getOverrideState()).isEmpty();
+        assertThat(mPolicy.getMostRecentRequestedStateToConfigure())
+                .isEqualTo(DEFAULT_DEVICE_STATE_IDENTIFIER);
     }
 
     @Test
     public void requestState_unsupportedState() throws RemoteException {
-        TestDeviceStateManagerCallback callback = new TestDeviceStateManagerCallback();
+        final TestDeviceStateManagerCallback callback = new TestDeviceStateManagerCallback();
         mService.getBinderService().registerCallback(callback);
 
         assertThrows(IllegalArgumentException.class, () -> {
             final IBinder token = new Binder();
-            mService.getBinderService().requestState(token,
-                    UNSUPPORTED_DEVICE_STATE.getIdentifier(), 0 /* flags */);
+            mService.getBinderService()
+                    .requestState(token, UNSUPPORTED_DEVICE_STATE.getIdentifier(), 0 /* flags */);
         });
     }
 
     @Test
     public void requestState_invalidState() throws RemoteException {
-        TestDeviceStateManagerCallback callback = new TestDeviceStateManagerCallback();
+        final TestDeviceStateManagerCallback callback = new TestDeviceStateManagerCallback();
         mService.getBinderService().registerCallback(callback);
 
         assertThrows(IllegalArgumentException.class, () -> {
             final IBinder token = new Binder();
-            mService.getBinderService().requestState(token, INVALID_DEVICE_STATE_IDENTIFIER,
-                    0 /* flags */);
+            mService.getBinderService()
+                    .requestState(token, INVALID_DEVICE_STATE_IDENTIFIER, 0 /* flags */);
         });
     }
 
@@ -678,40 +728,41 @@
     public void requestState_beforeRegisteringCallback() {
         assertThrows(IllegalStateException.class, () -> {
             final IBinder token = new Binder();
-            mService.getBinderService().requestState(token, DEFAULT_DEVICE_STATE.getIdentifier(),
-                    0 /* flags */);
+            mService.getBinderService()
+                    .requestState(token, DEFAULT_DEVICE_STATE_IDENTIFIER, 0 /* flags */);
         });
     }
 
     @Test
     public void requestBaseStateOverride() throws RemoteException {
-        TestDeviceStateManagerCallback callback = new TestDeviceStateManagerCallback();
+        final TestDeviceStateManagerCallback callback = new TestDeviceStateManagerCallback();
         mService.getBinderService().registerCallback(callback);
-        flushHandler();
+        if (!Flags.wlinfoOncreate()) {
+            flushHandler();
+        }
 
         final IBinder token = new Binder();
-        assertEquals(callback.getLastNotifiedStatus(token),
-                TestDeviceStateManagerCallback.STATUS_UNKNOWN);
+        assertThat(callback.getLastNotifiedStatus(token))
+                .isEqualTo(TestDeviceStateManagerCallback.STATUS_UNKNOWN);
 
         mService.getBinderService().requestBaseStateOverride(token,
-                OTHER_DEVICE_STATE.getIdentifier(),
+                OTHER_DEVICE_STATE_IDENTIFIER,
                 0 /* flags */);
 
         waitAndAssert(() -> callback.getLastNotifiedStatus(token)
                 == TestDeviceStateManagerCallback.STATUS_ACTIVE);
         // Committed state changes as there is a requested override.
-        assertEquals(mService.getCommittedState(), Optional.of(OTHER_DEVICE_STATE));
-        assertEquals(mSysPropSetter.getValue(),
-                OTHER_DEVICE_STATE.getIdentifier() + ":" + OTHER_DEVICE_STATE.getName());
-        assertEquals(mService.getBaseState(), Optional.of(OTHER_DEVICE_STATE));
-        assertEquals(mService.getOverrideBaseState().get(), OTHER_DEVICE_STATE);
-        assertFalse(mService.getOverrideState().isPresent());
-        assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(),
-                OTHER_DEVICE_STATE.getIdentifier());
+        assertThat(mService.getCommittedState()).hasValue(OTHER_DEVICE_STATE);
+        assertThat(mSysPropSetter.getValue()).isEqualTo(OTHER_DEVICE_STATE_TRACE_STRING);
+        assertThat(mService.getBaseState()).hasValue(OTHER_DEVICE_STATE);
+        assertThat(mService.getOverrideBaseState()).hasValue(OTHER_DEVICE_STATE);
+        assertThat(mService.getOverrideState()).isEmpty();
+        assertThat(mPolicy.getMostRecentRequestedStateToConfigure())
+                .isEqualTo(OTHER_DEVICE_STATE_IDENTIFIER);
 
-        assertNotNull(callback.getLastNotifiedInfo());
-        assertEquals(callback.getLastNotifiedInfo().baseState, OTHER_DEVICE_STATE);
-        assertEquals(callback.getLastNotifiedInfo().currentState, OTHER_DEVICE_STATE);
+        assertThat(callback.getLastNotifiedInfo()).isNotNull();
+        assertThat(callback.getLastNotifiedInfo().baseState).isEqualTo(OTHER_DEVICE_STATE);
+        assertThat(callback.getLastNotifiedInfo().currentState).isEqualTo(OTHER_DEVICE_STATE);
 
         mService.getBinderService().cancelBaseStateOverride();
 
@@ -719,52 +770,50 @@
                 == TestDeviceStateManagerCallback.STATUS_CANCELED);
         // Committed state is set back to the requested state once the override is cleared.
         waitAndAssert(() -> mService.getCommittedState().equals(Optional.of(DEFAULT_DEVICE_STATE)));
-        assertEquals(mSysPropSetter.getValue(),
-                DEFAULT_DEVICE_STATE.getIdentifier() + ":" + DEFAULT_DEVICE_STATE.getName());
-        assertEquals(mService.getBaseState(), Optional.of(DEFAULT_DEVICE_STATE));
-        assertFalse(mService.getOverrideBaseState().isPresent());
-        assertFalse(mService.getOverrideState().isPresent());
-        assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(),
-                DEFAULT_DEVICE_STATE.getIdentifier());
+        assertThat(mSysPropSetter.getValue()).isEqualTo(DEFAULT_DEVICE_STATE_TRACE_STRING);
+        assertThat(mService.getBaseState()).hasValue(DEFAULT_DEVICE_STATE);
+        assertThat(mService.getOverrideBaseState()).isEmpty();
+        assertThat(mService.getOverrideState()).isEmpty();
+        assertThat(mPolicy.getMostRecentRequestedStateToConfigure())
+                .isEqualTo(DEFAULT_DEVICE_STATE_IDENTIFIER);
 
         waitAndAssert(() -> callback.getLastNotifiedInfo().baseState.getIdentifier()
-                == DEFAULT_DEVICE_STATE.getIdentifier());
-        assertEquals(callback.getLastNotifiedInfo().currentState, DEFAULT_DEVICE_STATE);
+                == DEFAULT_DEVICE_STATE_IDENTIFIER);
+        assertThat(callback.getLastNotifiedInfo().currentState).isEqualTo(DEFAULT_DEVICE_STATE);
     }
 
     @Test
     public void requestBaseStateOverride_cancelledByBaseStateUpdate() throws RemoteException {
-        final DeviceState testDeviceState = new DeviceState(new DeviceState.Configuration.Builder(2,
-                "TEST").build());
-        TestDeviceStateManagerCallback callback = new TestDeviceStateManagerCallback();
+        final DeviceState testDeviceState = new DeviceState(
+                new DeviceState.Configuration.Builder(2, "TEST").build());
+        final TestDeviceStateManagerCallback callback = new TestDeviceStateManagerCallback();
         mService.getBinderService().registerCallback(callback);
         mProvider.notifySupportedDeviceStates(new DeviceState[]{DEFAULT_DEVICE_STATE,
                 OTHER_DEVICE_STATE, testDeviceState});
         flushHandler();
 
         final IBinder token = new Binder();
-        assertEquals(callback.getLastNotifiedStatus(token),
-                TestDeviceStateManagerCallback.STATUS_UNKNOWN);
+        assertThat(callback.getLastNotifiedStatus(token))
+                .isEqualTo(TestDeviceStateManagerCallback.STATUS_UNKNOWN);
 
         mService.getBinderService().requestBaseStateOverride(token,
-                OTHER_DEVICE_STATE.getIdentifier(),
+                OTHER_DEVICE_STATE_IDENTIFIER,
                 0 /* flags */);
 
         waitAndAssert(() -> callback.getLastNotifiedStatus(token)
                 == TestDeviceStateManagerCallback.STATUS_ACTIVE);
         // Committed state changes as there is a requested override.
-        assertEquals(mService.getCommittedState(), Optional.of(OTHER_DEVICE_STATE));
-        assertEquals(mSysPropSetter.getValue(),
-                OTHER_DEVICE_STATE.getIdentifier() + ":" + OTHER_DEVICE_STATE.getName());
-        assertEquals(mService.getBaseState(), Optional.of(OTHER_DEVICE_STATE));
-        assertEquals(mService.getOverrideBaseState().get(), OTHER_DEVICE_STATE);
-        assertFalse(mService.getOverrideState().isPresent());
-        assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(),
-                OTHER_DEVICE_STATE.getIdentifier());
+        assertThat(mService.getCommittedState()).hasValue(OTHER_DEVICE_STATE);
+        assertThat(mSysPropSetter.getValue()).isEqualTo(OTHER_DEVICE_STATE_TRACE_STRING);
+        assertThat(mService.getBaseState()).hasValue(OTHER_DEVICE_STATE);
+        assertThat(mService.getOverrideBaseState()).hasValue(OTHER_DEVICE_STATE);
+        assertThat(mService.getOverrideState()).isEmpty();
+        assertThat(mPolicy.getMostRecentRequestedStateToConfigure())
+                .isEqualTo(OTHER_DEVICE_STATE_IDENTIFIER);
 
-        assertNotNull(callback.getLastNotifiedInfo());
-        assertEquals(callback.getLastNotifiedInfo().baseState, OTHER_DEVICE_STATE);
-        assertEquals(callback.getLastNotifiedInfo().currentState, OTHER_DEVICE_STATE);
+        assertThat(callback.getLastNotifiedInfo()).isNotNull();
+        assertThat(callback.getLastNotifiedInfo().baseState).isEqualTo(OTHER_DEVICE_STATE);
+        assertThat(callback.getLastNotifiedInfo().currentState).isEqualTo(OTHER_DEVICE_STATE);
 
         mProvider.setState(testDeviceState.getIdentifier());
 
@@ -772,22 +821,22 @@
                 == TestDeviceStateManagerCallback.STATUS_CANCELED);
         // Committed state is set to the new base state once the override is cleared.
         waitAndAssert(() -> mService.getCommittedState().equals(Optional.of(testDeviceState)));
-        assertEquals(mSysPropSetter.getValue(),
-                testDeviceState.getIdentifier() + ":" + testDeviceState.getName());
-        assertEquals(mService.getBaseState(), Optional.of(testDeviceState));
-        assertFalse(mService.getOverrideBaseState().isPresent());
-        assertFalse(mService.getOverrideState().isPresent());
-        assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(),
-                testDeviceState.getIdentifier());
+        assertThat(mSysPropSetter.getValue())
+                .isEqualTo(testDeviceState.getIdentifier() + ":" + testDeviceState.getName());
+        assertThat(mService.getBaseState()).hasValue(testDeviceState);
+        assertThat(mService.getOverrideBaseState()).isEmpty();
+        assertThat(mService.getOverrideState()).isEmpty();
+        assertThat(mPolicy.getMostRecentRequestedStateToConfigure())
+                .isEqualTo(testDeviceState.getIdentifier());
 
         waitAndAssert(() -> callback.getLastNotifiedInfo().baseState.getIdentifier()
                 == testDeviceState.getIdentifier());
-        assertEquals(callback.getLastNotifiedInfo().currentState, testDeviceState);
+        assertThat(callback.getLastNotifiedInfo().currentState).isEqualTo(testDeviceState);
     }
 
     @Test
     public void requestBaseState_unsupportedState() throws RemoteException {
-        TestDeviceStateManagerCallback callback = new TestDeviceStateManagerCallback();
+        final TestDeviceStateManagerCallback callback = new TestDeviceStateManagerCallback();
         mService.getBinderService().registerCallback(callback);
 
         assertThrows(IllegalArgumentException.class, () -> {
@@ -799,7 +848,7 @@
 
     @Test
     public void requestBaseState_invalidState() throws RemoteException {
-        TestDeviceStateManagerCallback callback = new TestDeviceStateManagerCallback();
+        final TestDeviceStateManagerCallback callback = new TestDeviceStateManagerCallback();
         mService.getBinderService().registerCallback(callback);
 
         assertThrows(IllegalArgumentException.class, () -> {
@@ -814,7 +863,7 @@
         assertThrows(IllegalStateException.class, () -> {
             final IBinder token = new Binder();
             mService.getBinderService().requestBaseStateOverride(token,
-                    DEFAULT_DEVICE_STATE.getIdentifier(),
+                    DEFAULT_DEVICE_STATE_IDENTIFIER,
                     0 /* flags */);
         });
     }
@@ -834,21 +883,23 @@
             Runnable noChangeEvent,
             Runnable autoCancelEvent
     ) throws RemoteException {
-        TestDeviceStateManagerCallback callback = new TestDeviceStateManagerCallback();
+        final TestDeviceStateManagerCallback callback = new TestDeviceStateManagerCallback();
         mService.getBinderService().registerCallback(callback);
-        flushHandler();
+        if (!Flags.wlinfoOncreate()) {
+            flushHandler();
+        }
 
         final IBinder token = new Binder();
-        assertEquals(callback.getLastNotifiedStatus(token),
-                TestDeviceStateManagerCallback.STATUS_UNKNOWN);
+        assertThat(callback.getLastNotifiedStatus(token))
+                .isEqualTo(TestDeviceStateManagerCallback.STATUS_UNKNOWN);
 
         mService.getBinderService().requestState(token,
                 DEVICE_STATE_CANCEL_WHEN_REQUESTER_NOT_ON_TOP.getIdentifier(),
                 0 /* flags */);
         flushHandler(2 /* count */);
 
-        assertEquals(callback.getLastNotifiedStatus(token),
-                TestDeviceStateManagerCallback.STATUS_ACTIVE);
+        assertThat(callback.getLastNotifiedStatus(token))
+                .isEqualTo(TestDeviceStateManagerCallback.STATUS_ACTIVE);
 
         // Committed state changes as there is a requested override.
         assertDeviceStateConditions(
@@ -858,8 +909,8 @@
 
         noChangeEvent.run();
         flushHandler();
-        assertEquals(callback.getLastNotifiedStatus(token),
-                TestDeviceStateManagerCallback.STATUS_ACTIVE);
+        assertThat(callback.getLastNotifiedStatus(token))
+                .isEqualTo(TestDeviceStateManagerCallback.STATUS_ACTIVE);
         assertDeviceStateConditions(
                 DEVICE_STATE_CANCEL_WHEN_REQUESTER_NOT_ON_TOP,
                 DEFAULT_DEVICE_STATE, /* base state */
@@ -867,8 +918,8 @@
 
         autoCancelEvent.run();
         flushHandler();
-        assertEquals(callback.getLastNotifiedStatus(token),
-                TestDeviceStateManagerCallback.STATUS_CANCELED);
+        assertThat(callback.getLastNotifiedStatus(token))
+                .isEqualTo(TestDeviceStateManagerCallback.STATUS_CANCELED);
         assertDeviceStateConditions(DEFAULT_DEVICE_STATE, DEFAULT_DEVICE_STATE,
                 false /* isOverrideState */);
     }
@@ -881,20 +932,20 @@
      * @param isOverrideState whether a state override is active.
      */
     private void assertDeviceStateConditions(
-            DeviceState state, DeviceState baseState,
+            @NonNull DeviceState state, @NonNull DeviceState baseState,
             boolean isOverrideState) {
-        assertEquals(mService.getCommittedState(), Optional.of(state));
-        assertEquals(mService.getBaseState(), Optional.of(baseState));
-        assertEquals(mSysPropSetter.getValue(),
-                state.getIdentifier() + ":" + state.getName());
-        assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(),
-                state.getIdentifier());
+        assertThat(mService.getCommittedState()).hasValue(state);
+        assertThat(mService.getBaseState()).hasValue(baseState);
+        assertThat(mSysPropSetter.getValue())
+                .isEqualTo(state.getIdentifier() + ":" + state.getName());
+        assertThat(mPolicy.getMostRecentRequestedStateToConfigure())
+                .isEqualTo(state.getIdentifier());
         if (isOverrideState) {
             // When a state override is active, the committed state should batch the override state.
-            assertEquals(mService.getOverrideState().get(), state);
+            assertThat(mService.getOverrideState()).hasValue(state);
         } else {
             // When there is no state override, the override state should be empty.
-            assertFalse(mService.getOverrideState().isPresent());
+            assertThat(mService.getOverrideState()).isEmpty();
         }
     }
 
@@ -902,10 +953,11 @@
         private final DeviceStateProvider mProvider;
         private int mLastDeviceStateRequestedToConfigure = INVALID_DEVICE_STATE_IDENTIFIER;
         private boolean mConfigureBlocked = false;
+        @Nullable
         private Runnable mPendingConfigureCompleteRunnable;
 
-        TestDeviceStatePolicy(DeviceStateProvider provider) {
-            super(InstrumentationRegistry.getContext());
+        TestDeviceStatePolicy(@NonNull Context context, @NonNull DeviceStateProvider provider) {
+            super(context);
             mProvider = provider;
         }
 
@@ -921,7 +973,7 @@
         public void resumeConfigure() {
             mConfigureBlocked = false;
             if (mPendingConfigureCompleteRunnable != null) {
-                Runnable onComplete = mPendingConfigureCompleteRunnable;
+                final Runnable onComplete = mPendingConfigureCompleteRunnable;
                 mPendingConfigureCompleteRunnable = null;
                 onComplete.run();
             }
@@ -929,7 +981,7 @@
 
         public void resumeConfigureOnce() {
             if (mPendingConfigureCompleteRunnable != null) {
-                Runnable onComplete = mPendingConfigureCompleteRunnable;
+                final Runnable onComplete = mPendingConfigureCompleteRunnable;
                 mPendingConfigureCompleteRunnable = null;
                 onComplete.run();
             }
@@ -940,7 +992,7 @@
         }
 
         @Override
-        public void configureDeviceForState(int state, Runnable onComplete) {
+        public void configureDeviceForState(int state, @NonNull Runnable onComplete) {
             if (mPendingConfigureCompleteRunnable != null) {
                 throw new IllegalStateException("configureDeviceForState() called while configure"
                         + " is pending");
@@ -966,7 +1018,9 @@
                         OTHER_DEVICE_STATE,
                         DEVICE_STATE_CANCEL_WHEN_REQUESTER_NOT_ON_TOP};
 
-        @Nullable private final DeviceState mInitialState;
+        @Nullable
+        private final DeviceState mInitialState;
+        @Nullable
         private Listener mListener;
 
         private TestDeviceStateProvider() {
@@ -991,7 +1045,7 @@
             }
         }
 
-        public void notifySupportedDeviceStates(DeviceState[] supportedDeviceStates) {
+        public void notifySupportedDeviceStates(@NonNull DeviceState[] supportedDeviceStates) {
             mSupportedDeviceStates = supportedDeviceStates;
             mListener.onSupportedDeviceStatesChanged(supportedDeviceStates,
                     SUPPORTED_DEVICE_STATES_CHANGED_INITIALIZED);
@@ -1018,17 +1072,17 @@
         private final HashMap<IBinder, Integer> mLastNotifiedStatus = new HashMap<>();
 
         @Override
-        public void onDeviceStateInfoChanged(DeviceStateInfo info) {
+        public void onDeviceStateInfoChanged(@NonNull DeviceStateInfo info) {
             mLastNotifiedInfo = info;
         }
 
         @Override
-        public void onRequestActive(IBinder token) {
+        public void onRequestActive(@NonNull IBinder token) {
             mLastNotifiedStatus.put(token, STATUS_ACTIVE);
         }
 
         @Override
-        public void onRequestCanceled(IBinder token) {
+        public void onRequestCanceled(@NonNull IBinder token) {
             mLastNotifiedStatus.put(token, STATUS_CANCELED);
         }
 
@@ -1041,20 +1095,22 @@
             mLastNotifiedInfo = null;
         }
 
-        int getLastNotifiedStatus(IBinder requestToken) {
+        int getLastNotifiedStatus(@NonNull IBinder requestToken) {
             return mLastNotifiedStatus.getOrDefault(requestToken, STATUS_UNKNOWN);
         }
     }
 
     private static final class TestSystemPropertySetter implements
             DeviceStateManagerService.SystemPropertySetter {
+        @NonNull
         private String mValue;
 
         @Override
-        public void setDebugTracingDeviceStateProperty(String value) {
+        public void setDebugTracingDeviceStateProperty(@NonNull String value) {
             mValue = value;
         }
 
+        @NonNull
         public String getValue() {
             return mValue;
         }
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/FakePowerManagerWrapper.java b/services/tests/servicestests/src/com/android/server/hdmi/FakePowerManagerWrapper.java
index 04f921f..629f968 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/FakePowerManagerWrapper.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/FakePowerManagerWrapper.java
@@ -26,6 +26,7 @@
     private boolean mInteractive;
     private WakeLockWrapper mWakeLock;
     private boolean mWasWakeLockInstanceCreated = false;
+    private boolean mIsLowPowerStandbyEnabled = false;
 
 
     FakePowerManagerWrapper(@NonNull Context context) {
@@ -60,6 +61,15 @@
     }
 
     @Override
+    boolean isLowPowerStandbyEnabled() {
+        return mIsLowPowerStandbyEnabled;
+    }
+
+    void setIsLowPowerStandbyEnabled(boolean isLowPowerStandbyEnabled) {
+        mIsLowPowerStandbyEnabled = isLowPowerStandbyEnabled;
+    }
+
+    @Override
     WakeLockWrapper newWakeLock(int levelAndFlags, String tag) {
         if (mWakeLock == null) {
             mWakeLock = new FakeWakeLockWrapper();
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java
index 2d95740..935c8b8 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java
@@ -70,6 +70,7 @@
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
+import java.util.Objects;
 import java.util.concurrent.TimeUnit;
 
 @SmallTest
@@ -113,6 +114,10 @@
     private boolean mWokenUp;
     private boolean mEarcBlocksArc;
     private List<DeviceEventListener> mDeviceEventListeners = new ArrayList<>();
+    private List<VendorCommandListener> mVendorCommandListeners = new ArrayList<>();
+    private boolean mDisableCecOnStandbyByLowEnergyMode;
+    private boolean mWasCecDisabledOnStandbyByLowEnergyMode;
+    private boolean mUseHdmiCecPowerStatusController;
 
     private class DeviceEventListener {
         private HdmiDeviceInfo mDevice;
@@ -132,6 +137,30 @@
         }
     }
 
+    private class VendorCommandListener {
+        private boolean mEnabled;
+        private int mReason;
+
+        VendorCommandListener(boolean enabled, int reason) {
+            this.mEnabled = enabled;
+            this.mReason = reason;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (!(obj instanceof VendorCommandListener)) {
+                return false;
+            }
+            VendorCommandListener other = (VendorCommandListener) obj;
+            return other.mReason == mReason && other.mEnabled == mEnabled;
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(mEnabled, mReason);
+        }
+    }
+
     private FakeAudioFramework mAudioFramework;
     private AudioManagerWrapper mAudioManager;
 
@@ -169,6 +198,9 @@
 
                     @Override
                     boolean isPowerStandby() {
+                        if (mUseHdmiCecPowerStatusController) {
+                            return mPowerStatusController.isPowerStatusStandby();
+                        }
                         return false;
                     }
 
@@ -188,6 +220,13 @@
                     }
 
                     @Override
+                    boolean invokeVendorCommandListenersOnControlStateChanged(
+                            boolean enabled, int reason) {
+                        mVendorCommandListeners.add(new VendorCommandListener(enabled, reason));
+                        return true;
+                    }
+
+                    @Override
                     protected boolean earcBlocksArcConnection() {
                         return mEarcBlocksArc;
                     }
@@ -196,6 +235,21 @@
                     protected void sendBroadcastAsUser(@RequiresPermission Intent intent) {
                         // do nothing
                     }
+
+                    @Override
+                    protected boolean getDisableCecOnStandbyByLowEnergyMode() {
+                        return mDisableCecOnStandbyByLowEnergyMode;
+                    }
+
+                    @Override
+                    protected boolean getWasCecDisabledOnStandbyByLowEnergyMode() {
+                        return mWasCecDisabledOnStandbyByLowEnergyMode;
+                    }
+
+                    @Override
+                    protected void setWasCecDisabledOnStandbyByLowEnergyMode(boolean value) {
+                        mWasCecDisabledOnStandbyByLowEnergyMode = value;
+                    }
                 };
 
         mHdmiControlService.setIoLooper(mMyLooper);
@@ -241,6 +295,9 @@
             mHdmiControlService.getHdmiCecConfig().setIntValue(
                     sad, HdmiControlManager.QUERY_SAD_DISABLED);
         }
+        mWasCecDisabledOnStandbyByLowEnergyMode = false;
+        mDisableCecOnStandbyByLowEnergyMode = false;
+        mUseHdmiCecPowerStatusController = false;
         mNativeWrapper.clearResultMessages();
     }
 
@@ -2238,6 +2295,92 @@
         assertThat(mHdmiCecLocalDeviceTv.getActions(SystemAudioActionFromTv.class)).hasSize(1);
     }
 
+    @Test
+    public void lowEnergyMode_disableCecOnStandby_reEnableOnWakeup() {
+        mDisableCecOnStandbyByLowEnergyMode = true;
+        mUseHdmiCecPowerStatusController = true;
+        mPowerManager.setIsLowPowerStandbyEnabled(true);
+
+        assertEquals(mHdmiCecLocalDeviceTv.mService.getHdmiCecConfig().getIntValue(
+                HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED),
+                HdmiControlManager.HDMI_CEC_CONTROL_ENABLED);
+        mHdmiControlService.onStandby(STANDBY_SCREEN_OFF);
+        mTestLooper.dispatchAll();
+
+        assertEquals(mHdmiCecLocalDeviceTv.mService.getHdmiCecConfig().getIntValue(
+                        HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED),
+                HdmiControlManager.HDMI_CEC_CONTROL_DISABLED);
+        assertTrue(mWasCecDisabledOnStandbyByLowEnergyMode);
+        mHdmiControlService.onWakeUp(WAKE_UP_SCREEN_ON);
+        mTestLooper.dispatchAll();
+
+        assertEquals(mHdmiCecLocalDeviceTv.mService.getHdmiCecConfig().getIntValue(
+                        HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED),
+                HdmiControlManager.HDMI_CEC_CONTROL_ENABLED);
+        assertFalse(mWasCecDisabledOnStandbyByLowEnergyMode);
+    }
+
+    @Test
+    public void lowEnergyMode_disableCecBeforeStandby_cecStaysDisabledOnWakeup() {
+        mDisableCecOnStandbyByLowEnergyMode = true;
+        mUseHdmiCecPowerStatusController = true;
+        mPowerManager.setIsLowPowerStandbyEnabled(true);
+
+        assertEquals(mHdmiCecLocalDeviceTv.mService.getHdmiCecConfig().getIntValue(
+                        HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED),
+                HdmiControlManager.HDMI_CEC_CONTROL_ENABLED);
+        mHdmiCecLocalDeviceTv.mService.getHdmiCecConfig().setIntValue(
+                HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED,
+                HdmiControlManager.HDMI_CEC_CONTROL_DISABLED);
+        mTestLooper.dispatchAll();
+
+        mHdmiControlService.onStandby(STANDBY_SCREEN_OFF);
+        mTestLooper.dispatchAll();
+
+        assertEquals(mHdmiCecLocalDeviceTv.mService.getHdmiCecConfig().getIntValue(
+                        HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED),
+                HdmiControlManager.HDMI_CEC_CONTROL_DISABLED);
+        assertFalse(mWasCecDisabledOnStandbyByLowEnergyMode);
+        mHdmiControlService.onWakeUp(WAKE_UP_SCREEN_ON);
+        mTestLooper.dispatchAll();
+
+        assertEquals(mHdmiCecLocalDeviceTv.mService.getHdmiCecConfig().getIntValue(
+                        HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED),
+                HdmiControlManager.HDMI_CEC_CONTROL_DISABLED);
+    }
+
+    @Test
+    public void lowEnergyMode_onWakeUp_reEnableCec_invokeVendorCommandListeners() {
+        mDisableCecOnStandbyByLowEnergyMode = true;
+        mUseHdmiCecPowerStatusController = true;
+        mPowerManager.setIsLowPowerStandbyEnabled(true);
+        VendorCommandListener vendorCommandListenerInvocationWakeup = new VendorCommandListener(
+                true, HdmiControlManager.CONTROL_STATE_CHANGED_REASON_WAKEUP);
+        VendorCommandListener vendorCommandListenerInvocationSettingChange =
+                new VendorCommandListener(true,
+                        HdmiControlManager.CONTROL_STATE_CHANGED_REASON_WAKEUP);
+
+        assertEquals(mHdmiCecLocalDeviceTv.mService.getHdmiCecConfig().getIntValue(
+                        HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED),
+                HdmiControlManager.HDMI_CEC_CONTROL_ENABLED);
+        mHdmiControlService.onStandby(STANDBY_SCREEN_OFF);
+        mTestLooper.dispatchAll();
+
+        assertEquals(mHdmiCecLocalDeviceTv.mService.getHdmiCecConfig().getIntValue(
+                        HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED),
+                HdmiControlManager.HDMI_CEC_CONTROL_DISABLED);
+        assertTrue(mWasCecDisabledOnStandbyByLowEnergyMode);
+        mVendorCommandListeners.clear();
+        mTestLooper.dispatchAll();
+
+        mHdmiControlService.onWakeUp(WAKE_UP_SCREEN_ON);
+        mTestLooper.dispatchAll();
+
+        assertThat(mVendorCommandListeners.size()).isEqualTo(2);
+        assertTrue(mVendorCommandListeners.contains(vendorCommandListenerInvocationWakeup));
+        assertTrue(mVendorCommandListeners.contains(vendorCommandListenerInvocationSettingChange));
+    }
+
     protected static class MockTvDevice extends HdmiCecLocalDeviceTv {
         MockTvDevice(HdmiControlService service) {
             super(service);
diff --git a/services/tests/servicestests/src/com/android/server/integrity/engine/RuleEvaluationEngineTest.java b/services/tests/servicestests/src/com/android/server/integrity/engine/RuleEvaluationEngineTest.java
index 1c860ca..e1ee9c3 100644
--- a/services/tests/servicestests/src/com/android/server/integrity/engine/RuleEvaluationEngineTest.java
+++ b/services/tests/servicestests/src/com/android/server/integrity/engine/RuleEvaluationEngineTest.java
@@ -114,7 +114,7 @@
                         .setInstallerCertificates(Collections.singletonList(INSTALLER_1_CERT))
                         .build();
         assertThat(mEngine.evaluate(appInstallMetadata2).getEffect())
-                .isEqualTo(IntegrityCheckResult.Effect.DENY);
+                .isEqualTo(IntegrityCheckResult.Effect.ALLOW);
 
         AppInstallMetadata appInstallMetadata3 =
                 getAppInstallMetadataBuilder()
@@ -123,7 +123,7 @@
                         .setInstallerCertificates(Collections.singletonList(RANDOM_INSTALLER_CERT))
                         .build();
         assertThat(mEngine.evaluate(appInstallMetadata3).getEffect())
-                .isEqualTo(IntegrityCheckResult.Effect.DENY);
+                .isEqualTo(IntegrityCheckResult.Effect.ALLOW);
 
         AppInstallMetadata appInstallMetadata4 =
                 getAppInstallMetadataBuilder()
@@ -132,7 +132,7 @@
                         .setInstallerCertificates(Collections.singletonList(RANDOM_INSTALLER_CERT))
                         .build();
         assertThat(mEngine.evaluate(appInstallMetadata4).getEffect())
-                .isEqualTo(IntegrityCheckResult.Effect.DENY);
+                .isEqualTo(IntegrityCheckResult.Effect.ALLOW);
     }
 
     @Test
@@ -166,7 +166,7 @@
                         .setInstallerCertificates(Collections.singletonList(INSTALLER_2_CERT))
                         .build();
         assertThat(mEngine.evaluate(appInstallMetadata3).getEffect())
-                .isEqualTo(IntegrityCheckResult.Effect.DENY);
+                .isEqualTo(IntegrityCheckResult.Effect.ALLOW);
 
         AppInstallMetadata appInstallMetadata4 =
                 getAppInstallMetadataBuilder()
@@ -175,7 +175,7 @@
                         .setInstallerCertificates(Collections.singletonList(INSTALLER_1_CERT))
                         .build();
         assertThat(mEngine.evaluate(appInstallMetadata4).getEffect())
-                .isEqualTo(IntegrityCheckResult.Effect.DENY);
+                .isEqualTo(IntegrityCheckResult.Effect.ALLOW);
     }
 
     /** Returns a builder with all fields filled with some placeholder data. */
diff --git a/services/tests/servicestests/src/com/android/server/integrity/engine/RuleEvaluatorTest.java b/services/tests/servicestests/src/com/android/server/integrity/engine/RuleEvaluatorTest.java
deleted file mode 100644
index 5089f74..0000000
--- a/services/tests/servicestests/src/com/android/server/integrity/engine/RuleEvaluatorTest.java
+++ /dev/null
@@ -1,299 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.integrity.engine;
-
-import static com.android.server.integrity.model.IntegrityCheckResult.Effect.ALLOW;
-import static com.android.server.integrity.model.IntegrityCheckResult.Effect.DENY;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import android.content.integrity.AppInstallMetadata;
-import android.content.integrity.AtomicFormula;
-import android.content.integrity.AtomicFormula.LongAtomicFormula;
-import android.content.integrity.AtomicFormula.StringAtomicFormula;
-import android.content.integrity.CompoundFormula;
-import android.content.integrity.Rule;
-
-import com.android.server.integrity.model.IntegrityCheckResult;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-
-@RunWith(JUnit4.class)
-public class RuleEvaluatorTest {
-
-    private static final String PACKAGE_NAME_1 = "com.test.app";
-    private static final String PACKAGE_NAME_2 = "com.test.app2";
-    private static final String APP_CERTIFICATE = "test_cert";
-    private static final AppInstallMetadata APP_INSTALL_METADATA =
-            new AppInstallMetadata.Builder()
-                    .setPackageName(PACKAGE_NAME_1)
-                    .setAppCertificates(Collections.singletonList(APP_CERTIFICATE))
-                    .setAppCertificateLineage(Collections.singletonList(APP_CERTIFICATE))
-                    .setVersionCode(2)
-                    .build();
-
-    @Test
-    public void testEvaluateRules_noRules_allow() {
-        List<Rule> rules = new ArrayList<>();
-
-        IntegrityCheckResult result = RuleEvaluator.evaluateRules(rules, APP_INSTALL_METADATA);
-
-        assertThat(result.getEffect()).isEqualTo(ALLOW);
-    }
-
-    @Test
-    public void testEvaluateRules_noMatchedRules_allow() {
-        Rule rule =
-                new Rule(
-                        new StringAtomicFormula(
-                                AtomicFormula.PACKAGE_NAME,
-                                PACKAGE_NAME_2,
-                                /* isHashedValue= */ false),
-                        Rule.DENY);
-
-        IntegrityCheckResult result =
-                RuleEvaluator.evaluateRules(Collections.singletonList(rule), APP_INSTALL_METADATA);
-
-        assertThat(result.getEffect()).isEqualTo(ALLOW);
-    }
-
-    @Test
-    public void testEvaluateRules_oneMatch_deny() {
-        Rule rule1 =
-                new Rule(
-                        new StringAtomicFormula(
-                                AtomicFormula.PACKAGE_NAME,
-                                PACKAGE_NAME_1,
-                                /* isHashedValue= */ false),
-                        Rule.DENY);
-        Rule rule2 =
-                new Rule(
-                        new StringAtomicFormula(
-                                AtomicFormula.PACKAGE_NAME,
-                                PACKAGE_NAME_2,
-                                /* isHashedValue= */ false),
-                        Rule.DENY);
-
-        IntegrityCheckResult result =
-                RuleEvaluator.evaluateRules(Arrays.asList(rule1, rule2), APP_INSTALL_METADATA);
-
-        assertThat(result.getEffect()).isEqualTo(DENY);
-        assertThat(result.getMatchedRules()).containsExactly(rule1);
-    }
-
-    @Test
-    public void testEvaluateRules_multipleMatches_deny() {
-        Rule rule1 =
-                new Rule(
-                        new StringAtomicFormula(
-                                AtomicFormula.PACKAGE_NAME,
-                                PACKAGE_NAME_1,
-                                /* isHashedValue= */ false),
-                        Rule.DENY);
-        Rule rule2 = new Rule(
-                new CompoundFormula(
-                        CompoundFormula.AND,
-                        Arrays.asList(
-                                new StringAtomicFormula(
-                                        AtomicFormula.PACKAGE_NAME,
-                                        PACKAGE_NAME_1,
-                                        /* isHashedValue= */ false),
-                                new StringAtomicFormula(
-                                        AtomicFormula.APP_CERTIFICATE,
-                                        APP_CERTIFICATE,
-                                        /* isHashedValue= */ false))),
-                Rule.DENY);
-
-        IntegrityCheckResult result =
-                RuleEvaluator.evaluateRules(Arrays.asList(rule1, rule2), APP_INSTALL_METADATA);
-
-        assertThat(result.getEffect()).isEqualTo(DENY);
-        assertThat(result.getMatchedRules()).containsExactly(rule1, rule2);
-    }
-
-    @Test
-    public void testEvaluateRules_ruleWithNot_deny() {
-        Rule rule = new Rule(
-                new CompoundFormula(
-                        CompoundFormula.NOT,
-                        Collections.singletonList(
-                                new StringAtomicFormula(
-                                        AtomicFormula.PACKAGE_NAME,
-                                        PACKAGE_NAME_2,
-                                        /* isHashedValue= */ false))),
-                Rule.DENY);
-
-        IntegrityCheckResult result =
-                RuleEvaluator.evaluateRules(Collections.singletonList(rule), APP_INSTALL_METADATA);
-
-        assertThat(result.getEffect()).isEqualTo(DENY);
-        assertThat(result.getMatchedRules()).containsExactly(rule);
-    }
-
-    @Test
-    public void testEvaluateRules_ruleWithIntegerOperators_deny() {
-        Rule rule =
-                new Rule(
-                        new LongAtomicFormula(AtomicFormula.VERSION_CODE,
-                                AtomicFormula.GT, 1),
-                        Rule.DENY);
-
-        IntegrityCheckResult result =
-                RuleEvaluator.evaluateRules(Collections.singletonList(rule), APP_INSTALL_METADATA);
-
-        assertThat(result.getEffect()).isEqualTo(DENY);
-        assertThat(result.getMatchedRules()).containsExactly(rule);
-    }
-
-    @Test
-    public void testEvaluateRules_validForm_deny() {
-        Rule rule = new Rule(
-                new CompoundFormula(
-                        CompoundFormula.AND,
-                        Arrays.asList(
-                                new StringAtomicFormula(
-                                        AtomicFormula.PACKAGE_NAME,
-                                        PACKAGE_NAME_1,
-                                        /* isHashedValue= */ false),
-                                new StringAtomicFormula(
-                                        AtomicFormula.APP_CERTIFICATE,
-                                        APP_CERTIFICATE,
-                                        /* isHashedValue= */ false))),
-                Rule.DENY);
-
-        IntegrityCheckResult result =
-                RuleEvaluator.evaluateRules(Collections.singletonList(rule), APP_INSTALL_METADATA);
-
-        assertThat(result.getEffect()).isEqualTo(DENY);
-        assertThat(result.getMatchedRules()).containsExactly(rule);
-    }
-
-    @Test
-    public void testEvaluateRules_orRules() {
-        Rule rule = new Rule(
-                new CompoundFormula(
-                        CompoundFormula.OR,
-                        Arrays.asList(
-                                new StringAtomicFormula(
-                                        AtomicFormula.PACKAGE_NAME,
-                                        PACKAGE_NAME_1,
-                                        /* isHashedValue= */ false),
-                                new StringAtomicFormula(
-                                        AtomicFormula.APP_CERTIFICATE,
-                                        APP_CERTIFICATE,
-                                        /* isHashedValue= */ false))),
-                Rule.DENY);
-
-        IntegrityCheckResult result =
-                RuleEvaluator.evaluateRules(Collections.singletonList(rule), APP_INSTALL_METADATA);
-
-        assertThat(result.getEffect()).isEqualTo(DENY);
-        assertThat(result.getMatchedRules()).containsExactly(rule);
-    }
-
-    @Test
-    public void testEvaluateRules_compoundFormulaWithNot_deny() {
-        CompoundFormula openSubFormula =
-                new CompoundFormula(
-                        CompoundFormula.AND,
-                        Arrays.asList(
-                                new StringAtomicFormula(
-                                        AtomicFormula.PACKAGE_NAME,
-                                        PACKAGE_NAME_2,
-                                        /* isHashedValue= */ false),
-                                new StringAtomicFormula(
-                                        AtomicFormula.APP_CERTIFICATE,
-                                        APP_CERTIFICATE,
-                                        /* isHashedValue= */ false)));
-        CompoundFormula compoundFormula =
-                new CompoundFormula(CompoundFormula.NOT, Collections.singletonList(openSubFormula));
-        Rule rule = new Rule(compoundFormula, Rule.DENY);
-
-        IntegrityCheckResult result =
-                RuleEvaluator.evaluateRules(Collections.singletonList(rule), APP_INSTALL_METADATA);
-
-        assertThat(result.getEffect()).isEqualTo(DENY);
-        assertThat(result.getMatchedRules()).containsExactly(rule);
-    }
-
-    @Test
-    public void testEvaluateRules_forceAllow() {
-        Rule rule1 =
-                new Rule(
-                        new StringAtomicFormula(
-                                AtomicFormula.PACKAGE_NAME,
-                                PACKAGE_NAME_1,
-                                /* isHashedValue= */ false),
-                        Rule.FORCE_ALLOW);
-        Rule rule2 = new Rule(
-                new CompoundFormula(
-                        CompoundFormula.AND,
-                        Arrays.asList(
-                                new StringAtomicFormula(
-                                        AtomicFormula.PACKAGE_NAME,
-                                        PACKAGE_NAME_1,
-                                        /* isHashedValue= */ false),
-                                new StringAtomicFormula(
-                                        AtomicFormula.APP_CERTIFICATE,
-                                        APP_CERTIFICATE,
-                                        /* isHashedValue= */ false))),
-                Rule.DENY);
-
-        IntegrityCheckResult result =
-                RuleEvaluator.evaluateRules(Arrays.asList(rule1, rule2), APP_INSTALL_METADATA);
-
-        assertThat(result.getEffect()).isEqualTo(ALLOW);
-        assertThat(result.getMatchedRules()).containsExactly(rule1);
-    }
-
-    @Test
-    public void testEvaluateRules_multipleMatches_forceAllow() {
-        Rule rule1 =
-                new Rule(
-                        new StringAtomicFormula(
-                                AtomicFormula.PACKAGE_NAME,
-                                PACKAGE_NAME_1,
-                                /* isHashedValue= */ false),
-                        Rule.FORCE_ALLOW);
-        Rule rule2 = new Rule(
-                new CompoundFormula(
-                        CompoundFormula.AND,
-                        Arrays.asList(
-                                new StringAtomicFormula(
-                                        AtomicFormula.PACKAGE_NAME,
-                                        PACKAGE_NAME_1,
-                                        /* isHashedValue= */ false),
-                                new StringAtomicFormula(
-                                        AtomicFormula.APP_CERTIFICATE,
-                                        APP_CERTIFICATE,
-                                        /* isHashedValue= */ false))),
-                Rule.FORCE_ALLOW);
-
-        IntegrityCheckResult result =
-                RuleEvaluator.evaluateRules(Arrays.asList(rule1, rule2), APP_INSTALL_METADATA);
-
-        assertThat(result.getEffect()).isEqualTo(ALLOW);
-        assertThat(result.getMatchedRules()).containsExactly(rule1, rule2);
-    }
-}
\ No newline at end of file
diff --git a/services/tests/servicestests/src/com/android/server/integrity/model/IntegrityCheckResultTest.java b/services/tests/servicestests/src/com/android/server/integrity/model/IntegrityCheckResultTest.java
index 6c23ff6..d31ed68 100644
--- a/services/tests/servicestests/src/com/android/server/integrity/model/IntegrityCheckResultTest.java
+++ b/services/tests/servicestests/src/com/android/server/integrity/model/IntegrityCheckResultTest.java
@@ -22,8 +22,6 @@
 import android.content.integrity.CompoundFormula;
 import android.content.integrity.Rule;
 
-import com.android.internal.util.FrameworkStatsLog;
-
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
@@ -40,8 +38,6 @@
 
         assertThat(allowResult.getEffect()).isEqualTo(IntegrityCheckResult.Effect.ALLOW);
         assertThat(allowResult.getMatchedRules()).isEmpty();
-        assertThat(allowResult.getLoggingResponse())
-                .isEqualTo(FrameworkStatsLog.INTEGRITY_CHECK_RESULT_REPORTED__RESPONSE__ALLOWED);
     }
 
     @Test
@@ -58,9 +54,6 @@
 
         assertThat(allowResult.getEffect()).isEqualTo(IntegrityCheckResult.Effect.ALLOW);
         assertThat(allowResult.getMatchedRules()).containsExactly(forceAllowRule);
-        assertThat(allowResult.getLoggingResponse())
-                .isEqualTo(
-                        FrameworkStatsLog.INTEGRITY_CHECK_RESULT_REPORTED__RESPONSE__FORCE_ALLOWED);
     }
 
     @Test
@@ -77,8 +70,6 @@
 
         assertThat(denyResult.getEffect()).isEqualTo(IntegrityCheckResult.Effect.DENY);
         assertThat(denyResult.getMatchedRules()).containsExactly(failedRule);
-        assertThat(denyResult.getLoggingResponse())
-                .isEqualTo(FrameworkStatsLog.INTEGRITY_CHECK_RESULT_REPORTED__RESPONSE__REJECTED);
     }
 
     @Test
diff --git a/services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionManagerServiceTest.java
index 425bb15..7e22d74 100644
--- a/services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionManagerServiceTest.java
@@ -1256,7 +1256,8 @@
                     Manifest.permission.BYPASS_ROLE_QUALIFICATION);
 
             roleManager.setBypassingRoleQualification(true);
-            roleManager.addRoleHolderAsUser(role, packageName, /*  flags = */ 0, user,
+            roleManager.addRoleHolderAsUser(role, packageName,
+                    /* flags= */ RoleManager.MANAGE_HOLDERS_FLAG_DONT_KILL_APP, user,
                     mContext.getMainExecutor(), success -> {
                         if (success) {
                             latch.countDown();
@@ -1271,9 +1272,9 @@
         } catch (InterruptedException e) {
             throw new RuntimeException(e);
         } finally {
-            roleManager.removeRoleHolderAsUser(role, packageName, 0, user,
-                    mContext.getMainExecutor(), (aBool) -> {
-                    });
+            roleManager.removeRoleHolderAsUser(role, packageName,
+                    /* flags= */ RoleManager.MANAGE_HOLDERS_FLAG_DONT_KILL_APP, user,
+                    mContext.getMainExecutor(), (aBool) -> {});
             roleManager.setBypassingRoleQualification(false);
             instrumentation.getUiAutomation()
                     .dropShellPermissionIdentity();
diff --git a/services/tests/servicestests/src/com/android/server/stats/pull/netstats/NetworkStatsAccumulatorTest.kt b/services/tests/servicestests/src/com/android/server/stats/pull/netstats/NetworkStatsAccumulatorTest.kt
new file mode 100644
index 0000000..8cf0e82
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/stats/pull/netstats/NetworkStatsAccumulatorTest.kt
@@ -0,0 +1,189 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.stats.pull.netstats
+
+import android.net.NetworkStats
+import android.net.NetworkStats.DEFAULT_NETWORK_YES
+import android.net.NetworkStats.METERED_NO
+import android.net.NetworkStats.ROAMING_NO
+import android.net.NetworkStats.SET_DEFAULT
+import android.net.NetworkStats.TAG_NONE
+import android.net.NetworkTemplate
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.testutils.assertNetworkStatsEquals
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+class NetworkStatsAccumulatorTest {
+
+    @Test
+    fun hasEqualParameters_differentParameters_returnsFalse() {
+        val wifiTemplate = NetworkTemplate.Builder(NetworkTemplate.MATCH_WIFI).build()
+        val mobileTemplate = NetworkTemplate.Builder(NetworkTemplate.MATCH_MOBILE).build()
+
+        val snapshot = NetworkStatsAccumulator(wifiTemplate, false, 0, 0)
+
+        assertThat(snapshot.hasEqualParameters(mobileTemplate, false)).isFalse()
+        assertThat(snapshot.hasEqualParameters(wifiTemplate, true)).isFalse()
+    }
+
+    @Test
+    fun hasSameParameters_equalParameters_returnsTrue() {
+        val wifiTemplate1 = NetworkTemplate.Builder(NetworkTemplate.MATCH_WIFI).build()
+        val wifiTemplate2 = NetworkTemplate.Builder(NetworkTemplate.MATCH_WIFI).build()
+
+        val snapshot = NetworkStatsAccumulator(wifiTemplate1, false, 0, 0)
+
+        assertThat(snapshot.hasEqualParameters(wifiTemplate1, false)).isTrue()
+        assertThat(snapshot.hasEqualParameters(wifiTemplate2, false)).isTrue()
+    }
+
+    @Test
+    fun queryStats_lessThanOneBucketFromSnapshotEndTime_returnsAllStats() {
+        val snapshot = NetworkStatsAccumulator(TEMPLATE, false, 200, 1000)
+
+        // Accumulator has data until 1000 (= 0), and its end-point is still in the history period.
+        // Current time is less than one bucket away from snapshot end-point: 1050 - 1000 < 200
+        val stats = snapshot.queryStats(1050, FakeStats(500, 1050, 1))
+
+        // After the query at 1050, accumulator should have 1 * (1050 - 1000) = 50 bytes.
+        assertNetworkStatsEquals(stats, networkStatsWithBytes(50))
+    }
+
+    @Test
+    fun queryStats_oneBucketFromSnapshotEndTime_returnsCumulativeStats() {
+        val snapshot = NetworkStatsAccumulator(TEMPLATE, false, 200, 1000)
+
+        // Accumulator has data until 1000 (= 0), and its end-point is still in the history period.
+        // Current time is one bucket away from snapshot end-point: 1250 - 1000 > 200
+        val stats = snapshot.queryStats(1250, FakeStats(550, 1250, 2))
+
+        // After the query at 1250, accumulator should have 2 * (1250 - 1000) = 500 bytes.
+        assertNetworkStatsEquals(stats, networkStatsWithBytes(500))
+    }
+
+    @Test
+    fun queryStats_twoBucketsFromSnapshotEndTime_returnsCumulativeStats() {
+        val snapshot = NetworkStatsAccumulator(TEMPLATE, false, 200, 1000)
+
+        // Accumulator has data until 1000 (= 0), and its end-point is in the history period.
+        // Current time is two buckets away from snapshot end-point: 1450 - 1000 > 2*200
+        val stats = snapshot.queryStats(1450, FakeStats(600, 1450, 3))
+
+        // After the query at 1450, accumulator should have 3 * (1450 - 1000) = 1350 bytes.
+        assertNetworkStatsEquals(stats, networkStatsWithBytes(1350))
+    }
+
+    @Test
+    fun queryStats_manyBucketsFromSnapshotEndTime_returnsCumulativeStats() {
+        val snapshot = NetworkStatsAccumulator(TEMPLATE, false, 200, 1000)
+
+        // Accumulator has data until 1000 (= 0), and its end-point is still in the history period.
+        // Current time is many buckets away from snapshot end-point
+        val stats = snapshot.queryStats(6100, FakeStats(900, 6100, 1))
+
+        // After the query at 6100, accumulator should have 1 * (6100 - 1000) = 5100 bytes.
+        assertNetworkStatsEquals(stats, networkStatsWithBytes(5100))
+    }
+
+    @Test
+    fun queryStats_multipleQueriesAndSameHistoryWindow_returnsCumulativeStats() {
+        val snapshot = NetworkStatsAccumulator(TEMPLATE, false, 200, 1000)
+
+        // Accumulator is queried within the history period, whose starting point stays the same.
+        // After each query, accumulator should contain bytes from the initial end-point until now.
+        val stats1 = snapshot.queryStats(5100, FakeStats(900, 5100, 1))
+        val stats2 = snapshot.queryStats(10100, FakeStats(900, 10100, 1))
+        val stats3 = snapshot.queryStats(15100, FakeStats(900, 15100, 1))
+
+        assertNetworkStatsEquals(stats1, networkStatsWithBytes(4100))
+        assertNetworkStatsEquals(stats2, networkStatsWithBytes(9100))
+        assertNetworkStatsEquals(stats3, networkStatsWithBytes(14100))
+    }
+
+    @Test
+    fun queryStats_multipleQueriesAndSlidingHistoryWindow_returnsCumulativeStats() {
+        val snapshot = NetworkStatsAccumulator(TEMPLATE, false, 200, 1000)
+
+        // Accumulator is queried within the history period, whose starting point is moving.
+        // After each query, accumulator should contain bytes from the initial end-point until now.
+        val stats1 = snapshot.queryStats(5100, FakeStats(900, 5100, 1))
+        val stats2 = snapshot.queryStats(10100, FakeStats(4000, 10100, 1))
+        val stats3 = snapshot.queryStats(15100, FakeStats(7000, 15100, 1))
+
+        assertNetworkStatsEquals(stats1, networkStatsWithBytes(4100))
+        assertNetworkStatsEquals(stats2, networkStatsWithBytes(9100))
+        assertNetworkStatsEquals(stats3, networkStatsWithBytes(14100))
+    }
+
+    @Test
+    fun queryStats_withSnapshotEndTimeBeforeHistoryStart_addsOnlyStatsWithinHistory() {
+        val snapshot = NetworkStatsAccumulator(TEMPLATE, false, 200, 1900)
+
+        // Accumulator has data until 1000 (= 0), but its end-point is not in the history period.
+        // After the query, accumulator should add only those bytes that are covered by the history.
+        val stats = snapshot.queryStats(2700, FakeStats(2200, 2700, 1))
+
+        assertNetworkStatsEquals(stats, networkStatsWithBytes(500))
+    }
+
+    /**
+     * Simulates equally distributed traffic stats persisted over a set period of time.
+     */
+    private class FakeStats(
+        val historyStartMillis: Long, val currentTimeMillis: Long, val bytesPerMilli: Long
+    ) : NetworkStatsAccumulator.StatsQueryFunction {
+
+        override fun queryNetworkStats(
+            template: NetworkTemplate, includeTags: Boolean, startTime: Long, endTime: Long
+        ): NetworkStats {
+            val overlap = overlap(startTime, endTime, historyStartMillis, currentTimeMillis)
+            return networkStatsWithBytes(overlap * bytesPerMilli)
+        }
+    }
+
+    companion object {
+
+        private val TEMPLATE = NetworkTemplate.Builder(NetworkTemplate.MATCH_WIFI).build()
+
+        fun networkStatsWithBytes(bytes: Long): NetworkStats {
+            val stats = NetworkStats(0, 1).addEntry(
+                NetworkStats.Entry(
+                    null,
+                    0,
+                    SET_DEFAULT,
+                    TAG_NONE,
+                    METERED_NO,
+                    ROAMING_NO,
+                    DEFAULT_NETWORK_YES,
+                    bytes,
+                    bytes / 100,
+                    bytes,
+                    bytes / 100,
+                    0
+                )
+            )
+            return stats
+        }
+
+        fun overlap(aStart: Long, aEnd: Long, bStart: Long, bEnd: Long): Long {
+            return maxOf(0L, minOf(aEnd, bEnd) - maxOf(aStart, bStart))
+        }
+    }
+}
\ No newline at end of file
diff --git a/services/tests/servicestests/src/com/android/server/tv/tunerresourcemanager/TunerResourceManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/tv/tunerresourcemanager/TunerResourceManagerServiceTest.java
index bf58443..a222ef0 100644
--- a/services/tests/servicestests/src/com/android/server/tv/tunerresourcemanager/TunerResourceManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/tv/tunerresourcemanager/TunerResourceManagerServiceTest.java
@@ -175,8 +175,7 @@
                 tunerFrontendInfo(1 /*handle*/, FrontendSettings.TYPE_DVBT, 1 /*exclusiveGroupId*/);
         mTunerResourceManagerService.setFrontendInfoListInternal(infos);
 
-        Map<Integer, FrontendResource> resources =
-                mTunerResourceManagerService.getFrontendResources();
+        Map<Long, FrontendResource> resources = mTunerResourceManagerService.getFrontendResources();
         for (int id = 0; id < infos.length; id++) {
             assertThat(resources.get(infos[id].handle)
                     .getExclusiveGroupMemberFeHandles().size()).isEqualTo(0);
@@ -203,15 +202,14 @@
                 tunerFrontendInfo(3 /*handle*/, FrontendSettings.TYPE_ATSC, 1 /*exclusiveGroupId*/);
         mTunerResourceManagerService.setFrontendInfoListInternal(infos);
 
-        Map<Integer, FrontendResource> resources =
-                mTunerResourceManagerService.getFrontendResources();
+        Map<Long, FrontendResource> resources = mTunerResourceManagerService.getFrontendResources();
         assertThat(resources.values()).comparingElementsUsing(FR_TFI_COMPARE)
                 .containsExactlyElementsIn(Arrays.asList(infos));
 
-        assertThat(resources.get(0).getExclusiveGroupMemberFeHandles()).isEmpty();
-        assertThat(resources.get(1).getExclusiveGroupMemberFeHandles()).containsExactly(2, 3);
-        assertThat(resources.get(2).getExclusiveGroupMemberFeHandles()).containsExactly(1, 3);
-        assertThat(resources.get(3).getExclusiveGroupMemberFeHandles()).containsExactly(1, 2);
+        assertThat(resources.get(0L).getExclusiveGroupMemberFeHandles()).isEmpty();
+        assertThat(resources.get(1L).getExclusiveGroupMemberFeHandles()).containsExactly(2L, 3L);
+        assertThat(resources.get(2L).getExclusiveGroupMemberFeHandles()).containsExactly(1L, 3L);
+        assertThat(resources.get(3L).getExclusiveGroupMemberFeHandles()).containsExactly(1L, 2L);
     }
 
     @Test
@@ -224,11 +222,11 @@
                 tunerFrontendInfo(1 /*handle*/, FrontendSettings.TYPE_DVBS, 1 /*exclusiveGroupId*/);
 
         mTunerResourceManagerService.setFrontendInfoListInternal(infos);
-        Map<Integer, FrontendResource> resources0 =
+        Map<Long, FrontendResource> resources0 =
                 mTunerResourceManagerService.getFrontendResources();
 
         mTunerResourceManagerService.setFrontendInfoListInternal(infos);
-        Map<Integer, FrontendResource> resources1 =
+        Map<Long, FrontendResource> resources1 =
                 mTunerResourceManagerService.getFrontendResources();
 
         assertThat(resources0).isEqualTo(resources1);
@@ -251,8 +249,7 @@
                 tunerFrontendInfo(1 /*handle*/, FrontendSettings.TYPE_DVBT, 1 /*exclusiveGroupId*/);
         mTunerResourceManagerService.setFrontendInfoListInternal(infos1);
 
-        Map<Integer, FrontendResource> resources =
-                mTunerResourceManagerService.getFrontendResources();
+        Map<Long, FrontendResource> resources = mTunerResourceManagerService.getFrontendResources();
         for (int id = 0; id < infos1.length; id++) {
             assertThat(resources.get(infos1[id].handle)
                     .getExclusiveGroupMemberFeHandles().size()).isEqualTo(0);
@@ -278,8 +275,7 @@
                 tunerFrontendInfo(1 /*handle*/, FrontendSettings.TYPE_DVBT, 1 /*exclusiveGroupId*/);
         mTunerResourceManagerService.setFrontendInfoListInternal(infos1);
 
-        Map<Integer, FrontendResource> resources =
-                mTunerResourceManagerService.getFrontendResources();
+        Map<Long, FrontendResource> resources = mTunerResourceManagerService.getFrontendResources();
         for (int id = 0; id < infos1.length; id++) {
             assertThat(resources.get(infos1[id].handle)
                     .getExclusiveGroupMemberFeHandles().size()).isEqualTo(0);
@@ -296,7 +292,7 @@
         mTunerResourceManagerService.setFrontendInfoListInternal(infos0);
         TunerFrontendRequest request =
                 tunerFrontendRequest(0 /*clientId*/, FrontendSettings.TYPE_DVBT);
-        int[] frontendHandle = new int[1];
+        long[] frontendHandle = new long[1];
         assertThat(mTunerResourceManagerService
                 .requestFrontendInternal(request, frontendHandle)).isFalse();
         assertThat(frontendHandle[0]).isEqualTo(TunerResourceManager.INVALID_RESOURCE_HANDLE);
@@ -317,7 +313,7 @@
 
         TunerFrontendRequest request =
                 tunerFrontendRequest(client0.getId() /*clientId*/, FrontendSettings.TYPE_DVBT);
-        int[] frontendHandle = new int[1];
+        long[] frontendHandle = new long[1];
         assertThat(mTunerResourceManagerService
                 .requestFrontendInternal(request, frontendHandle)).isFalse();
         assertThat(frontendHandle[0]).isEqualTo(TunerResourceManager.INVALID_RESOURCE_HANDLE);
@@ -349,7 +345,7 @@
 
         TunerFrontendRequest request =
                 tunerFrontendRequest(client0.getId() /*clientId*/, FrontendSettings.TYPE_DVBT);
-        int[] frontendHandle = new int[1];
+        long[] frontendHandle = new long[1];
         assertThat(mTunerResourceManagerService
                 .requestFrontendInternal(request, frontendHandle)).isTrue();
         assertThat(frontendHandle[0]).isEqualTo(0);
@@ -382,7 +378,7 @@
                 1 /*exclusiveGroupId*/);
         mTunerResourceManagerService.setFrontendInfoListInternal(infos);
 
-        int[] frontendHandle = new int[1];
+        long[] frontendHandle = new long[1];
         TunerFrontendRequest request =
                 tunerFrontendRequest(client1.getId() /*clientId*/, FrontendSettings.TYPE_DVBT);
         assertThat(mTunerResourceManagerService
@@ -423,7 +419,7 @@
 
         TunerFrontendRequest request =
                 tunerFrontendRequest(client0.getId() /*clientId*/, FrontendSettings.TYPE_DVBT);
-        int[] frontendHandle = new int[1];
+        long[] frontendHandle = new long[1];
         assertThat(mTunerResourceManagerService
                 .requestFrontendInternal(request, frontendHandle)).isTrue();
 
@@ -463,12 +459,12 @@
 
         TunerFrontendRequest request =
                 tunerFrontendRequest(client0.getId() /*clientId*/, FrontendSettings.TYPE_DVBT);
-        int[] frontendHandle = new int[1];
+        long[] frontendHandle = new long[1];
         assertThat(mTunerResourceManagerService
                 .requestFrontendInternal(request, frontendHandle)).isTrue();
         assertThat(frontendHandle[0]).isEqualTo(infos[0].handle);
         assertThat(client0.getProfile().getInUseFrontendHandles())
-                .isEqualTo(new HashSet<Integer>(Arrays.asList(infos[0].handle, infos[1].handle)));
+                .isEqualTo(new HashSet<Long>(Arrays.asList(infos[0].handle, infos[1].handle)));
 
         request =
                 tunerFrontendRequest(client1.getId() /*clientId*/, FrontendSettings.TYPE_DVBS);
@@ -505,7 +501,7 @@
 
         TunerFrontendRequest request =
                 tunerFrontendRequest(client0.getId() /*clientId*/, FrontendSettings.TYPE_DVBT);
-        int[] frontendHandle = new int[1];
+        long[] frontendHandle = new long[1];
         assertThat(mTunerResourceManagerService
                 .requestFrontendInternal(request, frontendHandle)).isTrue();
         assertThat(frontendHandle[0]).isEqualTo(infos[0].handle);
@@ -536,7 +532,7 @@
         mTunerResourceManagerService.updateCasInfoInternal(1 /*casSystemId*/, 2 /*maxSessionNum*/);
 
         CasSessionRequest request = casSessionRequest(client0.getId(), 1 /*casSystemId*/);
-        int[] casSessionHandle = new int[1];
+        long[] casSessionHandle = new long[1];
         // Request for 2 cas sessions.
         assertThat(mTunerResourceManagerService
                 .requestCasSessionInternal(request, casSessionHandle)).isTrue();
@@ -583,7 +579,7 @@
         mTunerResourceManagerService.updateCasInfoInternal(1 /*casSystemId*/, 2 /*maxSessionNum*/);
 
         TunerCiCamRequest request = tunerCiCamRequest(client0.getId(), 1 /*ciCamId*/);
-        int[] ciCamHandle = new int[1];
+        long[] ciCamHandle = new long[1];
         // Request for 2 ciCam sessions.
         assertThat(mTunerResourceManagerService
                 .requestCiCamInternal(request, ciCamHandle)).isTrue();
@@ -626,7 +622,7 @@
         mTunerResourceManagerService.updateCasInfoInternal(1 /*casSystemId*/, 2 /*maxSessionNum*/);
 
         CasSessionRequest request = casSessionRequest(client0.getId(), 1 /*casSystemId*/);
-        int[] casSessionHandle = new int[1];
+        long[] casSessionHandle = new long[1];
         // Request for 1 cas sessions.
         assertThat(mTunerResourceManagerService
                 .requestCasSessionInternal(request, casSessionHandle)).isTrue();
@@ -660,7 +656,7 @@
         mTunerResourceManagerService.updateCasInfoInternal(1 /*casSystemId*/, 2 /*maxSessionNum*/);
 
         TunerCiCamRequest request = tunerCiCamRequest(client0.getId(), 1 /*ciCamId*/);
-        int[] ciCamHandle = new int[1];
+        long[] ciCamHandle = new long[1];
         // Request for 1 ciCam sessions.
         assertThat(mTunerResourceManagerService
                 .requestCiCamInternal(request, ciCamHandle)).isTrue();
@@ -696,17 +692,17 @@
                         TvInputService.PRIORITY_HINT_USE_CASE_TYPE_PLAYBACK, 500);
 
         // Init lnb resources.
-        int[] lnbHandles = {1};
+        long[] lnbHandles = {1};
         mTunerResourceManagerService.setLnbInfoListInternal(lnbHandles);
 
         TunerLnbRequest request = new TunerLnbRequest();
         request.clientId = client0.getId();
-        int[] lnbHandle = new int[1];
+        long[] lnbHandle = new long[1];
         assertThat(mTunerResourceManagerService
                 .requestLnbInternal(request, lnbHandle)).isTrue();
         assertThat(lnbHandle[0]).isEqualTo(lnbHandles[0]);
         assertThat(client0.getProfile().getInUseLnbHandles())
-                .isEqualTo(new HashSet<Integer>(Arrays.asList(lnbHandles[0])));
+                .isEqualTo(new HashSet<Long>(Arrays.asList(lnbHandles[0])));
 
         request = new TunerLnbRequest();
         request.clientId = client1.getId();
@@ -732,12 +728,12 @@
                         TvInputService.PRIORITY_HINT_USE_CASE_TYPE_PLAYBACK);
 
         // Init lnb resources.
-        int[] lnbHandles = {0};
+        long[] lnbHandles = {0};
         mTunerResourceManagerService.setLnbInfoListInternal(lnbHandles);
 
         TunerLnbRequest request = new TunerLnbRequest();
         request.clientId = client0.getId();
-        int[] lnbHandle = new int[1];
+        long[] lnbHandle = new long[1];
         assertThat(mTunerResourceManagerService
                 .requestLnbInternal(request, lnbHandle)).isTrue();
         assertThat(lnbHandle[0]).isEqualTo(lnbHandles[0]);
@@ -768,7 +764,7 @@
 
         TunerFrontendRequest request =
                 tunerFrontendRequest(client0.getId() /*clientId*/, FrontendSettings.TYPE_DVBT);
-        int[] frontendHandle = new int[1];
+        long[] frontendHandle = new long[1];
         assertThat(mTunerResourceManagerService
                 .requestFrontendInternal(request, frontendHandle)).isTrue();
         assertThat(frontendHandle[0]).isEqualTo(infos[0].handle);
@@ -799,12 +795,12 @@
         infos[2] = tunerDemuxInfo(2 /* handle */, Filter.TYPE_TS);
         mTunerResourceManagerService.setDemuxInfoListInternal(infos);
 
-        int[] demuxHandle0 = new int[1];
+        long[] demuxHandle0 = new long[1];
         // first with undefined type (should be the first one with least # of caps)
         TunerDemuxRequest request = tunerDemuxRequest(client0.getId(), Filter.TYPE_UNDEFINED);
         assertThat(mTunerResourceManagerService.requestDemuxInternal(request, demuxHandle0))
                 .isTrue();
-        assertThat(demuxHandle0[0]).isEqualTo(1);
+        assertThat(demuxHandle0[0]).isEqualTo(1L);
         DemuxResource dr = mTunerResourceManagerService.getDemuxResource(demuxHandle0[0]);
         mTunerResourceManagerService.releaseDemuxInternal(dr);
 
@@ -813,20 +809,20 @@
         demuxHandle0[0] = -1;
         assertThat(mTunerResourceManagerService.requestDemuxInternal(request, demuxHandle0))
                 .isFalse();
-        assertThat(demuxHandle0[0]).isEqualTo(-1);
+        assertThat(demuxHandle0[0]).isEqualTo(-1L);
 
         // now with TS (should be the one with least # of caps that supports TS)
         request.desiredFilterTypes = Filter.TYPE_TS;
         assertThat(mTunerResourceManagerService.requestDemuxInternal(request, demuxHandle0))
                 .isTrue();
-        assertThat(demuxHandle0[0]).isEqualTo(2);
+        assertThat(demuxHandle0[0]).isEqualTo(2L);
 
         // request for another TS
         TunerClient client1 = new TunerClient();
         client1.register("1" /*sessionId*/,
                         TvInputService.PRIORITY_HINT_USE_CASE_TYPE_PLAYBACK);
 
-        int[] demuxHandle1 = new int[1];
+        long[] demuxHandle1 = new long[1];
         TunerDemuxRequest request1 = tunerDemuxRequest(client1.getId(), Filter.TYPE_TS);
         assertThat(mTunerResourceManagerService.requestDemuxInternal(request1, demuxHandle1))
                 .isTrue();
@@ -865,14 +861,14 @@
 
         // let client0(prio:100) request for IP - should succeed
         TunerDemuxRequest request0 = tunerDemuxRequest(client0.getId(), Filter.TYPE_IP);
-        int[] demuxHandle0 = new int[1];
+        long[] demuxHandle0 = new long[1];
         assertThat(mTunerResourceManagerService
                 .requestDemuxInternal(request0, demuxHandle0)).isTrue();
         assertThat(demuxHandle0[0]).isEqualTo(0);
 
         // let client1(prio:50) request for IP - should fail
         TunerDemuxRequest request1 = tunerDemuxRequest(client1.getId(), Filter.TYPE_IP);
-        int[] demuxHandle1 = new int[1];
+        long[] demuxHandle1 = new long[1];
         demuxHandle1[0] = -1;
         assertThat(mTunerResourceManagerService
                 .requestDemuxInternal(request1, demuxHandle1)).isFalse();
@@ -892,7 +888,7 @@
 
         // let client2(prio:50) request for TS - should succeed
         TunerDemuxRequest request2 = tunerDemuxRequest(client2.getId(), Filter.TYPE_TS);
-        int[] demuxHandle2 = new int[1];
+        long[] demuxHandle2 = new long[1];
         assertThat(mTunerResourceManagerService
                 .requestDemuxInternal(request2, demuxHandle2)).isTrue();
         assertThat(demuxHandle2[0]).isEqualTo(0);
@@ -917,7 +913,7 @@
         client0.register("0" /*sessionId*/,
                         TvInputService.PRIORITY_HINT_USE_CASE_TYPE_PLAYBACK);
 
-        int[] desHandle = new int[1];
+        long[] desHandle = new long[1];
         TunerDescramblerRequest request = new TunerDescramblerRequest();
         request.clientId = client0.getId();
         assertThat(mTunerResourceManagerService.requestDescramblerInternal(request, desHandle))
@@ -980,7 +976,7 @@
                 1 /*exclusiveGroupId*/);
 
         /**** Init Lnb Resources ****/
-        int[] lnbHandles = {1};
+        long[] lnbHandles = {1};
         mTunerResourceManagerService.setLnbInfoListInternal(lnbHandles);
 
         // Update frontend list in TRM
@@ -989,7 +985,7 @@
         /**** Request Frontend ****/
 
         // Predefined frontend request and array to save returned frontend handle
-        int[] frontendHandle = new int[1];
+        long[] frontendHandle = new long[1];
         TunerFrontendRequest request = tunerFrontendRequest(
                 ownerClient0.getId() /*clientId*/,
                 FrontendSettings.TYPE_DVBT);
@@ -1000,7 +996,7 @@
                 .isTrue();
         assertThat(frontendHandle[0]).isEqualTo(infos[0].handle);
         assertThat(ownerClient0.getProfile().getInUseFrontendHandles())
-                .isEqualTo(new HashSet<Integer>(Arrays.asList(
+                .isEqualTo(new HashSet<Long>(Arrays.asList(
                         infos[0].handle,
                         infos[1].handle)));
 
@@ -1030,15 +1026,15 @@
                         shareClient1.getId())));
         // Verify in use frontend list in all the primary owner and share owner clients
         assertThat(ownerClient0.getProfile().getInUseFrontendHandles())
-                .isEqualTo(new HashSet<Integer>(Arrays.asList(
+                .isEqualTo(new HashSet<Long>(Arrays.asList(
                         infos[0].handle,
                         infos[1].handle)));
         assertThat(shareClient0.getProfile().getInUseFrontendHandles())
-                .isEqualTo(new HashSet<Integer>(Arrays.asList(
+                .isEqualTo(new HashSet<Long>(Arrays.asList(
                         infos[0].handle,
                         infos[1].handle)));
         assertThat(shareClient1.getProfile().getInUseFrontendHandles())
-                .isEqualTo(new HashSet<Integer>(Arrays.asList(
+                .isEqualTo(new HashSet<Long>(Arrays.asList(
                         infos[0].handle,
                         infos[1].handle)));
 
@@ -1052,12 +1048,12 @@
                 .isEqualTo(new HashSet<Integer>(Arrays.asList(
                         shareClient0.getId())));
         assertThat(ownerClient0.getProfile().getInUseFrontendHandles())
-                .isEqualTo(new HashSet<Integer>(Arrays.asList(
+                .isEqualTo(new HashSet<Long>(Arrays.asList(
                         infos[0].handle,
                         infos[1].handle)));
         assertThat(shareClient0.getProfile()
                 .getInUseFrontendHandles())
-                .isEqualTo(new HashSet<Integer>(Arrays.asList(
+                .isEqualTo(new HashSet<Long>(Arrays.asList(
                         infos[0].handle,
                         infos[1].handle)));
 
@@ -1080,7 +1076,7 @@
         assertThat(mTunerResourceManagerService.getFrontendResource(infos[1].handle)
                 .getOwnerClientId()).isEqualTo(ownerClient1.getId());
         assertThat(ownerClient1.getProfile().getInUseFrontendHandles())
-                .isEqualTo(new HashSet<Integer>(Arrays.asList(
+                .isEqualTo(new HashSet<Long>(Arrays.asList(
                         infos[0].handle,
                         infos[1].handle)));
         assertThat(ownerClient0.getProfile().getInUseFrontendHandles()
@@ -1127,7 +1123,7 @@
         // Predefined Lnb request and handle array
         TunerLnbRequest requestLnb = new TunerLnbRequest();
         requestLnb.clientId = shareClient0.getId();
-        int[] lnbHandle = new int[1];
+        long[] lnbHandle = new long[1];
 
         // Request for an Lnb
         assertThat(mTunerResourceManagerService
@@ -1155,7 +1151,7 @@
                 .isEmpty())
                 .isTrue();
         assertThat(shareClient0.getProfile().getInUseLnbHandles())
-                .isEqualTo(new HashSet<Integer>(Arrays.asList(
+                .isEqualTo(new HashSet<Long>(Arrays.asList(
                         lnbHandles[0])));
 
         ownerClient0.unregister();
@@ -1163,7 +1159,7 @@
     }
 
     private TunerFrontendInfo tunerFrontendInfo(
-            int handle, int frontendType, int exclusiveGroupId) {
+            long handle, int frontendType, int exclusiveGroupId) {
         TunerFrontendInfo info = new TunerFrontendInfo();
         info.handle = handle;
         info.type = frontendType;
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationAssistantsTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationAssistantsTest.java
index 797b95b5..eef3b25 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationAssistantsTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationAssistantsTest.java
@@ -145,7 +145,8 @@
         mContext.setMockPackageManager(mPm);
         mContext.addMockSystemService(Context.USER_SERVICE, mUm);
         mContext.getOrCreateTestableResources().addOverride(
-                com.android.internal.R.string.config_defaultAssistantAccessComponent, "a/a");
+                com.android.internal.R.string.config_defaultAssistantAccessComponent,
+                mCn.flattenToString());
         mAssistants = spy(mNm.new NotificationAssistants(mContext, mLock, mUserProfiles, miPm));
         when(mNm.getBinderService()).thenReturn(mINm);
         mContext.ensureTestableResources();
@@ -207,7 +208,8 @@
 
         writeXmlAndReload(USER_ALL);
 
-        ArrayMap<Boolean, ArraySet<String>> approved = mAssistants.mApproved.get(0);
+        ArrayMap<Boolean, ArraySet<String>> approved =
+                mAssistants.mApproved.get(ActivityManager.getCurrentUser());
         // approved should not be null
         assertNotNull(approved);
         assertEquals(new ArraySet<>(), approved.get(true));
@@ -217,6 +219,35 @@
     }
 
     @Test
+    public void testWriteXml_userTurnedOffNAS_backup() throws Exception {
+        int userId = 10;
+
+        mAssistants.loadDefaultsFromConfig(true);
+
+        mAssistants.setPackageOrComponentEnabled(mCn.flattenToString(), userId, true,
+                true, true);
+
+        ComponentName current = CollectionUtils.firstOrNull(
+                mAssistants.getAllowedComponents(userId));
+        mAssistants.setUserSet(userId, true);
+        mAssistants.setPackageOrComponentEnabled(current.flattenToString(), userId, true, false,
+                true);
+        assertTrue(mAssistants.mIsUserChanged.get(userId));
+        assertThat(mAssistants.getApproved(userId, true)).isEmpty();
+
+        writeXmlAndReload(userId);
+
+        ArrayMap<Boolean, ArraySet<String>> approved = mAssistants.mApproved.get(userId);
+        // approved should not be null
+        assertNotNull(approved);
+        assertEquals(new ArraySet<>(), approved.get(true));
+
+        // user set is maintained
+        assertTrue(mAssistants.mIsUserChanged.get(userId));
+        assertThat(mAssistants.getApproved(userId, true)).isEmpty();
+    }
+
+    @Test
     public void testReadXml_userDisabled() throws Exception {
         String xml = "<enabled_assistants version=\"4\" defaults=\"b/b\">"
                 + "<service_listing approved=\"\" user=\"0\" primary=\"true\""
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 03cad24..592eec5 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationAttentionHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationAttentionHelperTest.java
@@ -2291,10 +2291,7 @@
         flagResolver.setFlagOverride(NotificationFlags.NOTIF_VOLUME2, 0);
         initAttentionHelper(flagResolver);
 
-        // Trigger avalanche trigger intent
-        final Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
-        intent.putExtra("state", false);
-        mAvalancheBroadcastReceiver.onReceive(getContext(), intent);
+        triggerAvalancheEvent();
 
         NotificationRecord r = getBeepyNotification();
 
@@ -2338,10 +2335,7 @@
         flagResolver.setFlagOverride(NotificationFlags.NOTIF_VOLUME2, 0);
         initAttentionHelper(flagResolver);
 
-        // Trigger avalanche trigger intent
-        final Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
-        intent.putExtra("state", false);
-        mAvalancheBroadcastReceiver.onReceive(getContext(), intent);
+        triggerAvalancheEvent();
 
         NotificationRecord r = getBeepyNotification();
 
@@ -2379,10 +2373,7 @@
         flagResolver.setFlagOverride(NotificationFlags.NOTIF_VOLUME2, 0);
         initAttentionHelper(flagResolver);
 
-        // Trigger avalanche trigger intent
-        final Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
-        intent.putExtra("state", false);
-        mAvalancheBroadcastReceiver.onReceive(getContext(), intent);
+        triggerAvalancheEvent();
 
         NotificationRecord r = getBeepyNotification();
 
@@ -2428,10 +2419,7 @@
         flagResolver.setFlagOverride(NotificationFlags.NOTIF_VOLUME2, 0);
         initAttentionHelper(flagResolver);
 
-        // Trigger avalanche trigger intent
-        final Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
-        intent.putExtra("state", false);
-        mAvalancheBroadcastReceiver.onReceive(getContext(), intent);
+        triggerAvalancheEvent();
 
         NotificationRecord r = getBeepyNotification();
         r.getNotification().category = Notification.CATEGORY_EVENT;
@@ -2504,10 +2492,7 @@
         flagResolver.setFlagOverride(NotificationFlags.NOTIF_VOLUME2, 0);
         initAttentionHelper(flagResolver);
 
-        // Trigger avalanche trigger intent
-        final Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
-        intent.putExtra("state", false);
-        mAvalancheBroadcastReceiver.onReceive(getContext(), intent);
+        triggerAvalancheEvent();
 
         // Regular notification: should beep at 0% volume
         NotificationRecord r = getBeepyNotification();
@@ -2574,10 +2559,7 @@
         flagResolver.setFlagOverride(NotificationFlags.NOTIF_VOLUME2, 0);
         initAttentionHelper(flagResolver);
 
-        // Trigger avalanche trigger intent
-        final Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
-        intent.putExtra("state", false);
-        mAvalancheBroadcastReceiver.onReceive(getContext(), intent);
+        triggerAvalancheEvent();
 
         NotificationRecord r = getBeepyNotification();
 
@@ -2602,10 +2584,7 @@
         flagResolver.setFlagOverride(NotificationFlags.NOTIF_VOLUME2, 0);
         initAttentionHelper(flagResolver);
 
-        // Trigger avalanche trigger intent
-        final Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
-        intent.putExtra("state", false);
-        mAvalancheBroadcastReceiver.onReceive(getContext(), intent);
+        triggerAvalancheEvent();
 
         // CATEGORY_ALARM is exempted
         NotificationRecord r = getBeepyNotification();
@@ -2646,10 +2625,7 @@
         flagResolver.setFlagOverride(NotificationFlags.NOTIF_VOLUME2, 0);
         initAttentionHelper(flagResolver);
 
-        // Trigger avalanche trigger intent
-        final Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
-        intent.putExtra("state", false);
-        mAvalancheBroadcastReceiver.onReceive(getContext(), intent);
+        triggerAvalancheEvent();
 
         // Create a conversation group with GROUP_ALERT_SUMMARY behavior
         // Where the summary is not MessagingStyle
@@ -2693,6 +2669,16 @@
         assertEquals(-1, summary.getLastAudiblyAlertedMs());
     }
 
+    private void triggerAvalancheEvent() throws Exception {
+        // Trigger avalanche trigger intent
+        final Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
+        intent.putExtra("state", false);
+        mAvalancheBroadcastReceiver.onReceive(getContext(), intent);
+        // Wait after avalanche trigger before posting notifications
+        // so that notification#getWhen() is not the same value
+        Thread.sleep(100);
+    }
+
     @Test
     public void testBeepVolume_politeNotif_exemptEmergency() throws Exception {
         mSetFlagsRule.enableFlags(Flags.FLAG_POLITE_NOTIFICATIONS);
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenersTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenersTest.java
index 983e694..b34b1fb 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenersTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenersTest.java
@@ -835,7 +835,7 @@
     }
 
     @Test
-    public void testListenerPost_UpdateLifetimeExtended() throws Exception {
+    public void testListenerPostLifetimeExtended_UpdatesOnlySysui() throws Exception {
         mSetFlagsRule.enableFlags(android.app.Flags.FLAG_LIFETIME_EXTENSION_REFACTOR);
 
         // Create original notification, with FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY.
@@ -856,31 +856,51 @@
         Notification.Builder nb2 = new Notification.Builder(mContext, channel.getId())
                 .setContentTitle("new title")
                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
-                .setFlag(Notification.FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY, false);
+                .setFlag(Notification.FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY, true);
         StatusBarNotification sbn2 = new StatusBarNotification(pkg, pkg, 8, "tag", uid, 0,
                 nb2.build(), userHandle, null, 0);
         NotificationRecord toPost = new NotificationRecord(mContext, sbn2, channel);
 
         // Create system ui-like service.
-        ManagedServices.ManagedServiceInfo info = mListeners.new ManagedServiceInfo(
+        ManagedServices.ManagedServiceInfo sysuiInfo = mListeners.new ManagedServiceInfo(
                 null, new ComponentName("a", "a"), sbn2.getUserId(), false, null, 33, 33);
-        info.isSystemUi = true;
-        INotificationListener l1 = mock(INotificationListener.class);
-        info.service = l1;
-        List<ManagedServices.ManagedServiceInfo> services = ImmutableList.of(info);
+        sysuiInfo.isSystemUi = true;
+        INotificationListener sysuiListener = mock(INotificationListener.class);
+        sysuiInfo.service = sysuiListener;
+
+        // Create two non-system ui-like services.
+        ManagedServices.ManagedServiceInfo otherInfo1 = mListeners.new ManagedServiceInfo(
+                null, new ComponentName("b", "b"), sbn2.getUserId(), false, null, 33, 33);
+        otherInfo1.isSystemUi = false;
+        INotificationListener otherListener1 = mock(INotificationListener.class);
+        otherInfo1.service = otherListener1;
+
+        ManagedServices.ManagedServiceInfo otherInfo2 = mListeners.new ManagedServiceInfo(
+                null, new ComponentName("c", "c"), sbn2.getUserId(), false, null, 33, 33);
+        otherInfo2.isSystemUi = false;
+        INotificationListener otherListener2 = mock(INotificationListener.class);
+        otherInfo2.service = otherListener2;
+
+        List<ManagedServices.ManagedServiceInfo> services = ImmutableList.of(otherInfo1, sysuiInfo,
+                otherInfo2);
         when(mListeners.getServices()).thenReturn(services);
 
         FieldSetter.setField(mNm,
                 NotificationManagerService.class.getDeclaredField("mHandler"),
                 mock(NotificationManagerService.WorkerHandler.class));
         doReturn(true).when(mNm).isVisibleToListener(any(), anyInt(), any());
-        doReturn(mock(NotificationRankingUpdate.class)).when(mNm).makeRankingUpdateLocked(info);
+        doReturn(mock(NotificationRankingUpdate.class)).when(mNm)
+                .makeRankingUpdateLocked(sysuiInfo);
+        doReturn(mock(NotificationRankingUpdate.class)).when(mNm)
+                .makeRankingUpdateLocked(otherInfo1);
+        doReturn(mock(NotificationRankingUpdate.class)).when(mNm)
+                .makeRankingUpdateLocked(otherInfo2);
         doReturn(false).when(mNm).isInLockDownMode(anyInt());
         doNothing().when(mNm).updateUriPermissions(any(), any(), any(), anyInt());
         doReturn(sbn2).when(mListeners).redactStatusBarNotification(sbn2);
         doReturn(sbn2).when(mListeners).redactStatusBarNotification(any());
 
-        // The notification change is posted to the service listener.
+        // Post notification change to the service listeners.
         mListeners.notifyPostedLocked(toPost, old);
 
         // Verify that the post occcurs with the updated notification value.
@@ -889,11 +909,190 @@
         runnableCaptor.getValue().run();
         ArgumentCaptor<IStatusBarNotificationHolder> sbnCaptor =
                 ArgumentCaptor.forClass(IStatusBarNotificationHolder.class);
-        verify(l1, times(1)).onNotificationPosted(sbnCaptor.capture(), any());
+        verify(sysuiListener, times(1)).onNotificationPosted(sbnCaptor.capture(), any());
         StatusBarNotification sbnResult = sbnCaptor.getValue().get();
         assertThat(sbnResult.getNotification()
                 .extras.getCharSequence(Notification.EXTRA_TITLE).toString())
                 .isEqualTo("new title");
+
+        verify(otherListener1, never()).onNotificationPosted(any(), any());
+        verify(otherListener2, never()).onNotificationPosted(any(), any());
+    }
+
+    @Test
+    public void testListenerPostLifeimteExtension_postsToAppropriateListeners() throws Exception {
+        mSetFlagsRule.enableFlags(android.app.Flags.FLAG_LIFETIME_EXTENSION_REFACTOR);
+
+        // Create original notification, with FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY.
+        String pkg = "pkg";
+        int uid = 9;
+        UserHandle userHandle = UserHandle.getUserHandleForUid(uid);
+        NotificationChannel channel = new NotificationChannel("id", "name",
+                NotificationManager.IMPORTANCE_HIGH);
+        Notification.Builder nb = new Notification.Builder(mContext, channel.getId())
+                .setContentTitle("foo")
+                .setSmallIcon(android.R.drawable.sym_def_app_icon)
+                .setFlag(Notification.FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY, true);
+        StatusBarNotification sbn = new StatusBarNotification(pkg, pkg, 8, "tag", uid, 0,
+                nb.build(), userHandle, null, 0);
+        NotificationRecord leRecord = new NotificationRecord(mContext, sbn, channel);
+
+        // Creates updated notification (without FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY)
+        Notification.Builder nb2 = new Notification.Builder(mContext, channel.getId())
+                .setContentTitle("new title")
+                .setSmallIcon(android.R.drawable.sym_def_app_icon)
+                .setFlag(Notification.FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY, false);
+        StatusBarNotification sbn2 = new StatusBarNotification(pkg, pkg, 8, "tag", uid, 0,
+                nb2.build(), userHandle, null, 0);
+        NotificationRecord nonLeRecord = new NotificationRecord(mContext, sbn2, channel);
+
+        // Create system ui-like service.
+        ManagedServices.ManagedServiceInfo sysuiInfo = mListeners.new ManagedServiceInfo(
+                null, new ComponentName("a", "a"), sbn2.getUserId(), false, null, 33, 33);
+        sysuiInfo.isSystemUi = true;
+        INotificationListener sysuiListener = mock(INotificationListener.class);
+        sysuiInfo.service = sysuiListener;
+
+        // Create two non-system ui-like services.
+        ManagedServices.ManagedServiceInfo otherInfo1 = mListeners.new ManagedServiceInfo(
+                null, new ComponentName("b", "b"), sbn2.getUserId(), false, null, 33, 33);
+        otherInfo1.isSystemUi = false;
+        INotificationListener otherListener1 = mock(INotificationListener.class);
+        otherInfo1.service = otherListener1;
+
+        ManagedServices.ManagedServiceInfo otherInfo2 = mListeners.new ManagedServiceInfo(
+                null, new ComponentName("c", "c"), sbn2.getUserId(), false, null, 33, 33);
+        otherInfo2.isSystemUi = false;
+        INotificationListener otherListener2 = mock(INotificationListener.class);
+        otherInfo2.service = otherListener2;
+
+        List<ManagedServices.ManagedServiceInfo> services = ImmutableList.of(otherInfo1, sysuiInfo,
+                otherInfo2);
+        when(mListeners.getServices()).thenReturn(services);
+
+        FieldSetter.setField(mNm,
+                NotificationManagerService.class.getDeclaredField("mHandler"),
+                mock(NotificationManagerService.WorkerHandler.class));
+        doReturn(true).when(mNm).isVisibleToListener(any(), anyInt(), any());
+        doReturn(mock(NotificationRankingUpdate.class)).when(mNm)
+                .makeRankingUpdateLocked(sysuiInfo);
+        doReturn(mock(NotificationRankingUpdate.class)).when(mNm)
+                .makeRankingUpdateLocked(otherInfo1);
+        doReturn(mock(NotificationRankingUpdate.class)).when(mNm)
+                .makeRankingUpdateLocked(otherInfo2);
+        doReturn(false).when(mNm).isInLockDownMode(anyInt());
+        doNothing().when(mNm).updateUriPermissions(any(), any(), any(), anyInt());
+        doReturn(sbn2).when(mListeners).redactStatusBarNotification(sbn2);
+        doReturn(sbn2).when(mListeners).redactStatusBarNotification(any());
+
+        // The notification change is posted to the service listener.
+        // NonLE to LE should never happen, as LE can't be set in an update by the app.
+        // So we just want to test LE to NonLE.
+        mListeners.notifyPostedLocked(nonLeRecord /*=toPost*/, leRecord /*=old*/);
+
+        // Verify that the post occcurs with the updated notification value.
+        ArgumentCaptor<Runnable> runnableCaptor = ArgumentCaptor.forClass(Runnable.class);
+        verify(mNm.mHandler, times(3)).post(runnableCaptor.capture());
+        List<Runnable> capturedRunnable = runnableCaptor.getAllValues();
+        for (Runnable r : capturedRunnable) {
+            r.run();
+        }
+
+        ArgumentCaptor<IStatusBarNotificationHolder> sbnCaptor =
+                ArgumentCaptor.forClass(IStatusBarNotificationHolder.class);
+        verify(sysuiListener, times(1)).onNotificationPosted(sbnCaptor.capture(), any());
+        StatusBarNotification sbnResult = sbnCaptor.getValue().get();
+        assertThat(sbnResult.getNotification()
+                .extras.getCharSequence(Notification.EXTRA_TITLE).toString())
+                .isEqualTo("new title");
+
+        verify(otherListener1, times(1)).onNotificationPosted(any(), any());
+        verify(otherListener2, times(1)).onNotificationPosted(any(), any());
+    }
+
+    @Test
+    public void testNotifyPostedLocked_postsToAppropriateListeners() throws Exception {
+        // Create original notification
+        String pkg = "pkg";
+        int uid = 9;
+        UserHandle userHandle = UserHandle.getUserHandleForUid(uid);
+        NotificationChannel channel = new NotificationChannel("id", "name",
+                NotificationManager.IMPORTANCE_HIGH);
+        Notification.Builder nb = new Notification.Builder(mContext, channel.getId())
+                .setContentTitle("foo")
+                .setSmallIcon(android.R.drawable.sym_def_app_icon);
+        StatusBarNotification sbn = new StatusBarNotification(pkg, pkg, 8, "tag", uid, 0,
+                nb.build(), userHandle, null, 0);
+        NotificationRecord oldRecord = new NotificationRecord(mContext, sbn, channel);
+
+        // Creates updated notification
+        Notification.Builder nb2 = new Notification.Builder(mContext, channel.getId())
+                .setContentTitle("new title")
+                .setSmallIcon(android.R.drawable.sym_def_app_icon);
+        StatusBarNotification sbn2 = new StatusBarNotification(pkg, pkg, 8, "tag", uid, 0,
+                nb2.build(), userHandle, null, 0);
+        NotificationRecord newRecord = new NotificationRecord(mContext, sbn2, channel);
+
+        // Create system ui-like service.
+        ManagedServices.ManagedServiceInfo sysuiInfo = mListeners.new ManagedServiceInfo(
+                null, new ComponentName("a", "a"), sbn2.getUserId(), false, null, 33, 33);
+        sysuiInfo.isSystemUi = true;
+        INotificationListener sysuiListener = mock(INotificationListener.class);
+        sysuiInfo.service = sysuiListener;
+
+        // Create two non-system ui-like services.
+        ManagedServices.ManagedServiceInfo otherInfo1 = mListeners.new ManagedServiceInfo(
+                null, new ComponentName("b", "b"), sbn2.getUserId(), false, null, 33, 33);
+        otherInfo1.isSystemUi = false;
+        INotificationListener otherListener1 = mock(INotificationListener.class);
+        otherInfo1.service = otherListener1;
+
+        ManagedServices.ManagedServiceInfo otherInfo2 = mListeners.new ManagedServiceInfo(
+                null, new ComponentName("c", "c"), sbn2.getUserId(), false, null, 33, 33);
+        otherInfo2.isSystemUi = false;
+        INotificationListener otherListener2 = mock(INotificationListener.class);
+        otherInfo2.service = otherListener2;
+
+        List<ManagedServices.ManagedServiceInfo> services = ImmutableList.of(otherInfo1, sysuiInfo,
+                otherInfo2);
+        when(mListeners.getServices()).thenReturn(services);
+
+        FieldSetter.setField(mNm,
+                NotificationManagerService.class.getDeclaredField("mHandler"),
+                mock(NotificationManagerService.WorkerHandler.class));
+        doReturn(true).when(mNm).isVisibleToListener(any(), anyInt(), any());
+        doReturn(mock(NotificationRankingUpdate.class)).when(mNm)
+                .makeRankingUpdateLocked(sysuiInfo);
+        doReturn(mock(NotificationRankingUpdate.class)).when(mNm)
+                .makeRankingUpdateLocked(otherInfo1);
+        doReturn(mock(NotificationRankingUpdate.class)).when(mNm)
+                .makeRankingUpdateLocked(otherInfo2);
+        doReturn(false).when(mNm).isInLockDownMode(anyInt());
+        doNothing().when(mNm).updateUriPermissions(any(), any(), any(), anyInt());
+        doReturn(sbn2).when(mListeners).redactStatusBarNotification(sbn2);
+        doReturn(sbn2).when(mListeners).redactStatusBarNotification(any());
+
+        // The notification change is posted to the service listeners.
+        mListeners.notifyPostedLocked(newRecord, oldRecord);
+
+        // Verify that the post occcurs with the updated notification value.
+        ArgumentCaptor<Runnable> runnableCaptor = ArgumentCaptor.forClass(Runnable.class);
+        verify(mNm.mHandler, times(3)).post(runnableCaptor.capture());
+        List<Runnable> capturedRunnable = runnableCaptor.getAllValues();
+        for (Runnable r : capturedRunnable) {
+            r.run();
+        }
+
+        ArgumentCaptor<IStatusBarNotificationHolder> sbnCaptor =
+                ArgumentCaptor.forClass(IStatusBarNotificationHolder.class);
+        verify(sysuiListener, times(1)).onNotificationPosted(sbnCaptor.capture(), any());
+        StatusBarNotification sbnResult = sbnCaptor.getValue().get();
+        assertThat(sbnResult.getNotification()
+                .extras.getCharSequence(Notification.EXTRA_TITLE).toString())
+                .isEqualTo("new title");
+
+        verify(otherListener1, times(1)).onNotificationPosted(any(), any());
+        verify(otherListener2, times(1)).onNotificationPosted(any(), any());
     }
 
     /**
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
index d64b9e8..404ede6 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
@@ -18,6 +18,7 @@
 import static android.app.AppOpsManager.MODE_ALLOWED;
 import static android.app.AppOpsManager.MODE_DEFAULT;
 import static android.app.AppOpsManager.OP_SYSTEM_ALERT_WINDOW;
+import static android.app.Flags.FLAG_MODES_UI;
 import static android.app.Notification.VISIBILITY_PRIVATE;
 import static android.app.Notification.VISIBILITY_SECRET;
 import static android.app.NotificationChannel.ALLOW_BUBBLE_ON;
@@ -81,6 +82,7 @@
 import static org.junit.Assert.assertThrows;
 import static org.junit.Assert.assertTrue;
 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;
@@ -248,7 +250,7 @@
     @Parameters(name = "{0}")
     public static List<FlagsParameterization> getParams() {
         return FlagsParameterization.allCombinationsOf(
-                FLAG_NOTIFICATION_CLASSIFICATION);
+                FLAG_NOTIFICATION_CLASSIFICATION, FLAG_MODES_UI);
     }
 
     public PreferencesHelperTest(FlagsParameterization flags) {
@@ -2701,7 +2703,11 @@
         mHelper.createNotificationChannel(PKG_N_MR1, uid, channel, true, false,
                 uid, false);
         assertFalse(mHelper.areChannelsBypassingDnd());
-        verify(mMockZenModeHelper, never()).setNotificationPolicy(any(), anyInt(), anyInt());
+        if (android.app.Flags.modesUi()) {
+            verify(mMockZenModeHelper, never()).updateHasPriorityChannels(anyBoolean());
+        } else {
+            verify(mMockZenModeHelper, never()).setNotificationPolicy(any(), anyInt(), anyInt());
+        }
         resetZenModeHelper();
 
         // create notification channel that can bypass dnd
@@ -2711,18 +2717,30 @@
         mHelper.createNotificationChannel(PKG_N_MR1, uid, channel2, true, true,
                 uid, false);
         assertTrue(mHelper.areChannelsBypassingDnd());
-        verify(mMockZenModeHelper, times(1)).setNotificationPolicy(any(), anyInt(), anyInt());
+        if (android.app.Flags.modesUi()) {
+            verify(mMockZenModeHelper, times(1)).updateHasPriorityChannels(eq(true));
+        } else {
+            verify(mMockZenModeHelper, times(1)).setNotificationPolicy(any(), anyInt(), anyInt());
+        }
         resetZenModeHelper();
 
         // delete channels
         mHelper.deleteNotificationChannel(PKG_N_MR1, uid, channel.getId(), uid, false);
         assertTrue(mHelper.areChannelsBypassingDnd()); // channel2 can still bypass DND
-        verify(mMockZenModeHelper, never()).setNotificationPolicy(any(), anyInt(), anyInt());
+        if (android.app.Flags.modesUi()) {
+            verify(mMockZenModeHelper, never()).updateHasPriorityChannels(anyBoolean());
+        } else {
+            verify(mMockZenModeHelper, never()).setNotificationPolicy(any(), anyInt(), anyInt());
+        }
         resetZenModeHelper();
 
         mHelper.deleteNotificationChannel(PKG_N_MR1, uid, channel2.getId(), uid, false);
         assertFalse(mHelper.areChannelsBypassingDnd());
-        verify(mMockZenModeHelper, times(1)).setNotificationPolicy(any(), anyInt(), anyInt());
+        if (android.app.Flags.modesUi()) {
+            verify(mMockZenModeHelper, times(1)).updateHasPriorityChannels(eq(false));
+        } else {
+            verify(mMockZenModeHelper, times(1)).setNotificationPolicy(any(), anyInt(), anyInt());
+        }
         resetZenModeHelper();
     }
 
@@ -2738,7 +2756,11 @@
         mHelper.createNotificationChannel(PKG_N_MR1, uid, channel, true, false,
                 uid, false);
         assertFalse(mHelper.areChannelsBypassingDnd());
-        verify(mMockZenModeHelper, never()).setNotificationPolicy(any(), anyInt(), anyInt());
+        if (android.app.Flags.modesUi()) {
+            verify(mMockZenModeHelper, never()).updateHasPriorityChannels(anyBoolean());
+        } else {
+            verify(mMockZenModeHelper, never()).setNotificationPolicy(any(), anyInt(), anyInt());
+        }
         resetZenModeHelper();
 
         // Recreate a channel & now the app has dnd access granted and can set the bypass dnd field
@@ -2748,7 +2770,11 @@
                 uid, false);
 
         assertTrue(mHelper.areChannelsBypassingDnd());
-        verify(mMockZenModeHelper, times(1)).setNotificationPolicy(any(), anyInt(), anyInt());
+        if (android.app.Flags.modesUi()) {
+            verify(mMockZenModeHelper, times(1)).updateHasPriorityChannels(eq(true));
+        } else {
+            verify(mMockZenModeHelper, times(1)).setNotificationPolicy(any(), anyInt(), anyInt());
+        }
         resetZenModeHelper();
     }
 
@@ -2764,7 +2790,11 @@
         mHelper.createNotificationChannel(PKG_N_MR1, uid, channel, true, false,
                 uid, false);
         assertFalse(mHelper.areChannelsBypassingDnd());
-        verify(mMockZenModeHelper, never()).setNotificationPolicy(any(), anyInt(), anyInt());
+        if (android.app.Flags.modesUi()) {
+            verify(mMockZenModeHelper, never()).updateHasPriorityChannels(anyBoolean());
+        } else {
+            verify(mMockZenModeHelper, never()).setNotificationPolicy(any(), anyInt(), anyInt());
+        }
         resetZenModeHelper();
 
         // create notification channel that can bypass dnd, using local app level settings
@@ -2774,18 +2804,30 @@
         mHelper.createNotificationChannel(PKG_N_MR1, uid, channel2, true, true,
                 uid, false);
         assertTrue(mHelper.areChannelsBypassingDnd());
-        verify(mMockZenModeHelper, times(1)).setNotificationPolicy(any(), anyInt(), anyInt());
+        if (android.app.Flags.modesUi()) {
+            verify(mMockZenModeHelper, times(1)).updateHasPriorityChannels(eq(true));
+        } else {
+            verify(mMockZenModeHelper, times(1)).setNotificationPolicy(any(), anyInt(), anyInt());
+        }
         resetZenModeHelper();
 
         // delete channels
         mHelper.deleteNotificationChannel(PKG_N_MR1, uid, channel.getId(), uid, false);
         assertTrue(mHelper.areChannelsBypassingDnd()); // channel2 can still bypass DND
-        verify(mMockZenModeHelper, never()).setNotificationPolicy(any(), anyInt(), anyInt());
+        if (android.app.Flags.modesUi()) {
+            verify(mMockZenModeHelper, never()).updateHasPriorityChannels(anyBoolean());
+        } else {
+            verify(mMockZenModeHelper, never()).setNotificationPolicy(any(), anyInt(), anyInt());
+        }
         resetZenModeHelper();
 
         mHelper.deleteNotificationChannel(PKG_N_MR1, uid, channel2.getId(), uid, false);
         assertFalse(mHelper.areChannelsBypassingDnd());
-        verify(mMockZenModeHelper, times(1)).setNotificationPolicy(any(), anyInt(), anyInt());
+        if (android.app.Flags.modesUi()) {
+            verify(mMockZenModeHelper, times(1)).updateHasPriorityChannels(eq(false));
+        } else {
+            verify(mMockZenModeHelper, times(1)).setNotificationPolicy(any(), anyInt(), anyInt());
+        }
         resetZenModeHelper();
     }
 
@@ -2812,7 +2854,11 @@
         mHelper.createNotificationChannel(PKG_N_MR1, uid, channel2, true, true,
                 uid, false);
         assertFalse(mHelper.areChannelsBypassingDnd());
-        verify(mMockZenModeHelper, times(1)).setNotificationPolicy(any(), anyInt(), anyInt());
+        if (android.app.Flags.modesUi()) {
+            verify(mMockZenModeHelper, times(1)).updateHasPriorityChannels(eq(false));
+        } else {
+            verify(mMockZenModeHelper, times(1)).setNotificationPolicy(any(), anyInt(), anyInt());
+        }
         resetZenModeHelper();
     }
 
@@ -2834,7 +2880,11 @@
         mHelper.createNotificationChannel(PKG_N_MR1, uid, channel2, true, true,
                 uid, false);
         assertFalse(mHelper.areChannelsBypassingDnd());
-        verify(mMockZenModeHelper, times(1)).setNotificationPolicy(any(), anyInt(), anyInt());
+        if (android.app.Flags.modesUi()) {
+            verify(mMockZenModeHelper, times(1)).updateHasPriorityChannels(eq(false));
+        } else {
+            verify(mMockZenModeHelper, times(1)).setNotificationPolicy(any(), anyInt(), anyInt());
+        }
         resetZenModeHelper();
     }
 
@@ -2856,7 +2906,11 @@
         mHelper.createNotificationChannel(PKG_N_MR1, uid, channel2, true, true,
                 uid, false);
         assertFalse(mHelper.areChannelsBypassingDnd());
-        verify(mMockZenModeHelper, times(1)).setNotificationPolicy(any(), anyInt(), anyInt());
+        if (android.app.Flags.modesUi()) {
+            verify(mMockZenModeHelper, times(1)).updateHasPriorityChannels(eq(false));
+        } else {
+            verify(mMockZenModeHelper, times(1)).setNotificationPolicy(any(), anyInt(), anyInt());
+        }
         resetZenModeHelper();
     }
 
@@ -2872,7 +2926,11 @@
         mHelper.createNotificationChannel(PKG_N_MR1, uid, channel, true, false,
                 uid, false);
         assertFalse(mHelper.areChannelsBypassingDnd());
-        verify(mMockZenModeHelper, never()).setNotificationPolicy(any(), anyInt(), anyInt());
+        if (android.app.Flags.modesUi()) {
+            verify(mMockZenModeHelper, never()).updateHasPriorityChannels(anyBoolean());
+        } else {
+            verify(mMockZenModeHelper, never()).setNotificationPolicy(any(), anyInt(), anyInt());
+        }
         resetZenModeHelper();
 
         // update channel so it CAN bypass dnd:
@@ -2880,7 +2938,11 @@
         channel.setBypassDnd(true);
         mHelper.updateNotificationChannel(PKG_N_MR1, uid, channel, true, SYSTEM_UID, true);
         assertTrue(mHelper.areChannelsBypassingDnd());
-        verify(mMockZenModeHelper, times(1)).setNotificationPolicy(any(), anyInt(), anyInt());
+        if (android.app.Flags.modesUi()) {
+            verify(mMockZenModeHelper, times(1)).updateHasPriorityChannels(eq(true));
+        } else {
+            verify(mMockZenModeHelper, times(1)).setNotificationPolicy(any(), anyInt(), anyInt());
+        }
         resetZenModeHelper();
 
         // update channel so it can't bypass dnd:
@@ -2888,7 +2950,11 @@
         channel.setBypassDnd(false);
         mHelper.updateNotificationChannel(PKG_N_MR1, uid, channel, true, SYSTEM_UID, true);
         assertFalse(mHelper.areChannelsBypassingDnd());
-        verify(mMockZenModeHelper, times(1)).setNotificationPolicy(any(), anyInt(), anyInt());
+        if (android.app.Flags.modesUi()) {
+            verify(mMockZenModeHelper, times(1)).updateHasPriorityChannels(eq(false));
+        } else {
+            verify(mMockZenModeHelper, times(1)).setNotificationPolicy(any(), anyInt(), anyInt());
+        }
         resetZenModeHelper();
     }
 
@@ -2901,7 +2967,11 @@
         when(mMockZenModeHelper.getNotificationPolicy()).thenReturn(mTestNotificationPolicy);
         mHelper.syncChannelsBypassingDnd();
         assertFalse(mHelper.areChannelsBypassingDnd());
-        verify(mMockZenModeHelper, times(1)).setNotificationPolicy(any(), anyInt(), anyInt());
+        if (android.app.Flags.modesUi()) {
+            verify(mMockZenModeHelper, times(1)).updateHasPriorityChannels(eq(false));
+        } else {
+            verify(mMockZenModeHelper, times(1)).setNotificationPolicy(any(), anyInt(), anyInt());
+        }
         resetZenModeHelper();
     }
 
@@ -2911,7 +2981,11 @@
         mTestNotificationPolicy = new NotificationManager.Policy(0, 0, 0, 0, 0, 0);
         when(mMockZenModeHelper.getNotificationPolicy()).thenReturn(mTestNotificationPolicy);
         assertFalse(mHelper.areChannelsBypassingDnd());
-        verify(mMockZenModeHelper, never()).setNotificationPolicy(any(), anyInt(), anyInt());
+        if (android.app.Flags.modesUi()) {
+            verify(mMockZenModeHelper, never()).updateHasPriorityChannels(anyBoolean());
+        } else {
+            verify(mMockZenModeHelper, never()).setNotificationPolicy(any(), anyInt(), anyInt());
+        }
         resetZenModeHelper();
     }
 
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
index 294027b..8b3ac2b 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
@@ -7027,6 +7027,29 @@
                 ZenModeConfig.EVENTS_OBSOLETE_RULE_ID);
     }
 
+    @Test
+    @EnableFlags({FLAG_MODES_API, FLAG_MODES_UI})
+    public void updateHasPriorityChannels_keepsChannelSettings() {
+        setupZenConfig();
+
+        // Set priority channels setting on manual mode to confirm that it is unaffected by changes
+        // to the state describing the existence of such channels.
+        mZenModeHelper.mConfig.manualRule.zenPolicy =
+                new ZenPolicy.Builder(mZenModeHelper.mConfig.manualRule.zenPolicy)
+                        .allowPriorityChannels(false)
+                        .build();
+
+        mZenModeHelper.updateHasPriorityChannels(true);
+        assertThat(mZenModeHelper.getNotificationPolicy().hasPriorityChannels()).isTrue();
+
+        // getNotificationPolicy() gets its policy from the manual rule; channels not permitted
+        assertThat(mZenModeHelper.getNotificationPolicy().allowPriorityChannels()).isFalse();
+
+        mZenModeHelper.updateHasPriorityChannels(false);
+        assertThat(mZenModeHelper.getNotificationPolicy().hasPriorityChannels()).isFalse();
+        assertThat(mZenModeHelper.getNotificationPolicy().allowPriorityChannels()).isFalse();
+    }
+
     private static void addZenRule(ZenModeConfig config, String id, String ownerPkg, int zenMode,
             @Nullable ZenPolicy zenPolicy) {
         ZenRule rule = new ZenRule();
diff --git a/services/tests/vibrator/src/com/android/server/vibrator/DeviceAdapterTest.java b/services/tests/vibrator/src/com/android/server/vibrator/DeviceAdapterTest.java
index 1493253..d7ae046 100644
--- a/services/tests/vibrator/src/com/android/server/vibrator/DeviceAdapterTest.java
+++ b/services/tests/vibrator/src/com/android/server/vibrator/DeviceAdapterTest.java
@@ -35,7 +35,9 @@
 import android.os.vibrator.StepSegment;
 import android.os.vibrator.VibrationConfig;
 import android.os.vibrator.VibrationEffectSegment;
+import android.platform.test.annotations.DisableFlags;
 import android.platform.test.annotations.RequiresFlagsEnabled;
+import android.platform.test.flag.junit.SetFlagsRule;
 import android.util.SparseArray;
 
 import androidx.test.core.app.ApplicationProvider;
@@ -63,6 +65,8 @@
 
     @Rule
     public MockitoRule mMockitoRule = MockitoJUnit.rule();
+    @Rule
+    public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
 
     @Mock
     private PackageManagerInternal mPackageManagerInternalMock;
@@ -186,6 +190,7 @@
     }
 
     @Test
+    @DisableFlags(android.os.vibrator.Flags.FLAG_NORMALIZED_PWLE_EFFECTS)
     public void testStepAndRampSegments_withValidFreqMapping_returnsClippedValuesOnlyInRamps() {
         VibrationEffect.Composed effect = new VibrationEffect.Composed(Arrays.asList(
                 // Individual step without frequency control, will not use PWLE composition
diff --git a/services/tests/vibrator/src/com/android/server/vibrator/HapticFeedbackVibrationProviderTest.java b/services/tests/vibrator/src/com/android/server/vibrator/HapticFeedbackVibrationProviderTest.java
index f7127df..3b2f532 100644
--- a/services/tests/vibrator/src/com/android/server/vibrator/HapticFeedbackVibrationProviderTest.java
+++ b/services/tests/vibrator/src/com/android/server/vibrator/HapticFeedbackVibrationProviderTest.java
@@ -453,20 +453,7 @@
     }
 
     @Test
-    public void testVibrationAttribute_scrollFeedback_inputCustomizedFlag_useTouchUsage() {
-        mSetFlagsRule.enableFlags(FLAG_HAPTIC_FEEDBACK_INPUT_SOURCE_CUSTOMIZATION_ENABLED);
-        HapticFeedbackVibrationProvider provider = createProviderWithoutCustomizations();
-
-        for (int effectId : SCROLL_FEEDBACK_CONSTANTS) {
-            VibrationAttributes attrs = provider.getVibrationAttributes(effectId, /* flags */
-                    0, /* privFlags */ 0);
-            assertWithMessage("Expected USAGE_TOUCH for scroll effect " + effectId
-                    + ", if no input customization").that(attrs.getUsage()).isEqualTo(USAGE_TOUCH);
-        }
-    }
-
-    @Test
-    public void testVibrationAttribute_scrollFeedback_noInputCustomizedFlag_useHardwareFeedback() {
+    public void testVibrationAttribute_scrollFeedback_useHardwareFeedback() {
         HapticFeedbackVibrationProvider provider = createProviderWithoutCustomizations();
 
         for (int effectId : SCROLL_FEEDBACK_CONSTANTS) {
diff --git a/services/tests/vibrator/src/com/android/server/vibrator/RampToStepAdapterTest.java b/services/tests/vibrator/src/com/android/server/vibrator/RampToStepAdapterTest.java
index 867c061..96f0fda2 100644
--- a/services/tests/vibrator/src/com/android/server/vibrator/RampToStepAdapterTest.java
+++ b/services/tests/vibrator/src/com/android/server/vibrator/RampToStepAdapterTest.java
@@ -26,8 +26,11 @@
 import android.os.vibrator.RampSegment;
 import android.os.vibrator.StepSegment;
 import android.os.vibrator.VibrationEffectSegment;
+import android.platform.test.annotations.DisableFlags;
+import android.platform.test.flag.junit.SetFlagsRule;
 
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 
 import java.util.ArrayList;
@@ -39,8 +42,8 @@
     private static final int TEST_STEP_DURATION = 5;
     private static final float[] TEST_AMPLITUDE_MAP = new float[]{
             /* 50Hz= */ 0.1f, 0.2f, 0.4f, 0.8f, /* 150Hz= */ 1f, 0.9f, /* 200Hz= */ 0.8f};
-    private static final VibratorInfo.FrequencyProfile TEST_FREQUENCY_PROFILE =
-            new VibratorInfo.FrequencyProfile(
+    private static final VibratorInfo.FrequencyProfileLegacy TEST_FREQUENCY_PROFILE =
+            new VibratorInfo.FrequencyProfileLegacy(
                     /* resonantFrequencyHz= */ 150f, /* minFrequencyHz= */ 50f,
                     /* frequencyResolutionHz= */ 25f, TEST_AMPLITUDE_MAP);
     private static final VibratorInfo EMPTY_VIBRATOR_INFO = createVibratorInfo();
@@ -49,6 +52,9 @@
 
     private RampToStepAdapter mAdapter;
 
+    @Rule
+    public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+
     @Before
     public void setUp() throws Exception {
         mAdapter = new RampToStepAdapter(TEST_STEP_DURATION);
@@ -87,6 +93,7 @@
     }
 
     @Test
+    @DisableFlags(android.os.vibrator.Flags.FLAG_NORMALIZED_PWLE_EFFECTS)
     public void testRampSegments_withoutPwleCapability_convertsRampsToSteps() {
         List<VibrationEffectSegment> segments = new ArrayList<>(Arrays.asList(
                 new StepSegment(/* amplitude= */ 0, /* frequencyHz= */ 1, /* duration= */ 10),
@@ -121,7 +128,7 @@
     private static VibratorInfo createVibratorInfo(int... capabilities) {
         return new VibratorInfo.Builder(0)
                 .setCapabilities(IntStream.of(capabilities).reduce((a, b) -> a | b).orElse(0))
-                .setFrequencyProfile(TEST_FREQUENCY_PROFILE)
+                .setFrequencyProfileLegacy(TEST_FREQUENCY_PROFILE)
                 .build();
     }
 }
diff --git a/services/tests/vibrator/src/com/android/server/vibrator/SplitSegmentsAdapterTest.java b/services/tests/vibrator/src/com/android/server/vibrator/SplitSegmentsAdapterTest.java
index 6630cca..53e49e0 100644
--- a/services/tests/vibrator/src/com/android/server/vibrator/SplitSegmentsAdapterTest.java
+++ b/services/tests/vibrator/src/com/android/server/vibrator/SplitSegmentsAdapterTest.java
@@ -26,8 +26,11 @@
 import android.os.vibrator.RampSegment;
 import android.os.vibrator.StepSegment;
 import android.os.vibrator.VibrationEffectSegment;
+import android.platform.test.annotations.DisableFlags;
+import android.platform.test.flag.junit.SetFlagsRule;
 
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 
 import java.util.ArrayList;
@@ -41,8 +44,8 @@
     private static final float[] TEST_AMPLITUDE_MAP = new float[]{
             /* 50Hz= */ 0.1f, 0.2f, 0.4f, 0.8f, /* 150Hz= */ 1f, 0.9f, /* 200Hz= */ 0.8f};
 
-    private static final VibratorInfo.FrequencyProfile TEST_FREQUENCY_PROFILE =
-            new VibratorInfo.FrequencyProfile(
+    private static final VibratorInfo.FrequencyProfileLegacy TEST_FREQUENCY_PROFILE =
+            new VibratorInfo.FrequencyProfileLegacy(
                     /* resonantFrequencyHz= */ 150f, /* minFrequencyHz= */ 50f,
                     /* frequencyResolutionHz= */ 25f, TEST_AMPLITUDE_MAP);
 
@@ -52,6 +55,9 @@
 
     private SplitSegmentsAdapter mAdapter;
 
+    @Rule
+    public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+
     @Before
     public void setUp() throws Exception {
         mAdapter = new SplitSegmentsAdapter();
@@ -97,6 +103,7 @@
     }
 
     @Test
+    @DisableFlags(android.os.vibrator.Flags.FLAG_NORMALIZED_PWLE_EFFECTS)
     public void testRampSegments_withPwleDurationLimit_splitsLongRampsAndPreserveOtherSegments() {
         List<VibrationEffectSegment> segments = new ArrayList<>(Arrays.asList(
                 new StepSegment(/* amplitude= */ 1, /* frequencyHz= */ 40f, /* duration= */ 100),
@@ -125,7 +132,7 @@
         VibratorInfo vibratorInfo = new VibratorInfo.Builder(0)
                 .setCapabilities(IVibrator.CAP_COMPOSE_PWLE_EFFECTS)
                 .setPwlePrimitiveDurationMax(10)
-                .setFrequencyProfile(TEST_FREQUENCY_PROFILE)
+                .setFrequencyProfileLegacy(TEST_FREQUENCY_PROFILE)
                 .build();
 
         // Update repeat index to skip the ramp splits.
@@ -137,7 +144,7 @@
     private static VibratorInfo createVibratorInfo(int... capabilities) {
         return new VibratorInfo.Builder(0)
                 .setCapabilities(IntStream.of(capabilities).reduce((a, b) -> a | b).orElse(0))
-                .setFrequencyProfile(TEST_FREQUENCY_PROFILE)
+                .setFrequencyProfileLegacy(TEST_FREQUENCY_PROFILE)
                 .setPwlePrimitiveDurationMax(PWLE_COMPOSITION_PRIMITIVE_DURATION_MAX)
                 .build();
     }
diff --git a/services/tests/vibrator/src/com/android/server/vibrator/StepToRampAdapterTest.java b/services/tests/vibrator/src/com/android/server/vibrator/StepToRampAdapterTest.java
index 82deff0..fae634d 100644
--- a/services/tests/vibrator/src/com/android/server/vibrator/StepToRampAdapterTest.java
+++ b/services/tests/vibrator/src/com/android/server/vibrator/StepToRampAdapterTest.java
@@ -26,8 +26,11 @@
 import android.os.vibrator.RampSegment;
 import android.os.vibrator.StepSegment;
 import android.os.vibrator.VibrationEffectSegment;
+import android.platform.test.annotations.DisableFlags;
+import android.platform.test.flag.junit.SetFlagsRule;
 
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 
 import java.util.ArrayList;
@@ -38,8 +41,8 @@
 public class StepToRampAdapterTest {
     private static final float[] TEST_AMPLITUDE_MAP = new float[]{
             /* 50Hz= */ 0.1f, 0.2f, 0.4f, 0.8f, /* 150Hz= */ 1f, 0.9f, /* 200Hz= */ 0.8f};
-    private static final VibratorInfo.FrequencyProfile TEST_FREQUENCY_PROFILE =
-            new VibratorInfo.FrequencyProfile(
+    private static final VibratorInfo.FrequencyProfileLegacy TEST_FREQUENCY_PROFILE =
+            new VibratorInfo.FrequencyProfileLegacy(
                     /* resonantFrequencyHz= */ 150f, /* minFrequencyHz= */ 50f,
                     /* frequencyResolutionHz= */ 25f, TEST_AMPLITUDE_MAP);
     private static final VibratorInfo EMPTY_VIBRATOR_INFO = createVibratorInfo();
@@ -48,6 +51,9 @@
 
     private StepToRampAdapter mAdapter;
 
+    @Rule
+    public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+
     @Before
     public void setUp() throws Exception {
         mAdapter = new StepToRampAdapter();
@@ -134,6 +140,7 @@
     }
 
     @Test
+    @DisableFlags(android.os.vibrator.Flags.FLAG_NORMALIZED_PWLE_EFFECTS)
     public void testStepSegments_withPwleCapabilityAndFrequency_convertsStepsToRamps() {
         List<VibrationEffectSegment> segments = new ArrayList<>(Arrays.asList(
                 new StepSegment(/* amplitude= */ 0, /* frequencyHz= */ 100, /* duration= */ 10),
@@ -153,7 +160,7 @@
     private static VibratorInfo createVibratorInfo(int... capabilities) {
         return new VibratorInfo.Builder(0)
                 .setCapabilities(IntStream.of(capabilities).reduce((a, b) -> a | b).orElse(0))
-                .setFrequencyProfile(TEST_FREQUENCY_PROFILE)
+                .setFrequencyProfileLegacy(TEST_FREQUENCY_PROFILE)
                 .build();
     }
 }
diff --git a/services/tests/vibrator/src/com/android/server/vibrator/VibrationThreadTest.java b/services/tests/vibrator/src/com/android/server/vibrator/VibrationThreadTest.java
index 7536f5f..58a1e84 100644
--- a/services/tests/vibrator/src/com/android/server/vibrator/VibrationThreadTest.java
+++ b/services/tests/vibrator/src/com/android/server/vibrator/VibrationThreadTest.java
@@ -63,9 +63,11 @@
 import android.os.vibrator.StepSegment;
 import android.os.vibrator.VibrationConfig;
 import android.os.vibrator.VibrationEffectSegment;
+import android.platform.test.annotations.DisableFlags;
 import android.platform.test.annotations.RequiresFlagsEnabled;
 import android.platform.test.flag.junit.CheckFlagsRule;
 import android.platform.test.flag.junit.DeviceFlagsValueProvider;
+import android.platform.test.flag.junit.SetFlagsRule;
 import android.provider.Settings;
 import android.util.SparseArray;
 
@@ -113,6 +115,8 @@
     @Rule
     public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
     @Rule
+    public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+    @Rule
     public FakeSettingsProviderRule mSettingsProviderRule = FakeSettingsProvider.rule();
 
     @Mock private PackageManagerInternal mPackageManagerInternalMock;
@@ -780,6 +784,7 @@
     }
 
     @Test
+    @DisableFlags(android.os.vibrator.Flags.FLAG_NORMALIZED_PWLE_EFFECTS)
     public void vibrate_singleVibratorComposedEffects_runsDifferentVibrations() {
         FakeVibratorControllerProvider fakeVibrator = mVibratorProviders.get(VIBRATOR_ID);
         fakeVibrator.setSupportedEffects(VibrationEffect.EFFECT_CLICK);
@@ -870,6 +875,7 @@
     }
 
     @Test
+    @DisableFlags(android.os.vibrator.Flags.FLAG_NORMALIZED_PWLE_EFFECTS)
     public void vibrate_singleVibratorPwle_runsComposePwle() {
         FakeVibratorControllerProvider fakeVibrator = mVibratorProviders.get(VIBRATOR_ID);
         fakeVibrator.setCapabilities(IVibrator.CAP_COMPOSE_PWLE_EFFECTS);
@@ -1724,6 +1730,7 @@
     }
 
     @Test
+    @DisableFlags(android.os.vibrator.Flags.FLAG_NORMALIZED_PWLE_EFFECTS)
     public void vibrate_pwleWithRampDown_doesNotAddRampDown() {
         when(mVibrationConfigMock.getRampDownDurationMs()).thenReturn(15);
         FakeVibratorControllerProvider fakeVibrator = mVibratorProviders.get(VIBRATOR_ID);
diff --git a/services/tests/vibrator/src/com/android/server/vibrator/VibratorControllerTest.java b/services/tests/vibrator/src/com/android/server/vibrator/VibratorControllerTest.java
index e8ca8bf..8179369 100644
--- a/services/tests/vibrator/src/com/android/server/vibrator/VibratorControllerTest.java
+++ b/services/tests/vibrator/src/com/android/server/vibrator/VibratorControllerTest.java
@@ -334,13 +334,14 @@
     }
 
     private void mockVibratorCapabilities(int capabilities) {
-        VibratorInfo.FrequencyProfile frequencyProfile = new VibratorInfo.FrequencyProfile(
+        VibratorInfo.FrequencyProfileLegacy
+                frequencyProfile = new VibratorInfo.FrequencyProfileLegacy(
                 Float.NaN, Float.NaN, Float.NaN, null);
         when(mNativeWrapperMock.getInfo(any(VibratorInfo.Builder.class)))
                 .then(invocation -> {
                     ((VibratorInfo.Builder) invocation.getArgument(0))
                             .setCapabilities(capabilities)
-                            .setFrequencyProfile(frequencyProfile);
+                            .setFrequencyProfileLegacy(frequencyProfile);
                     return true;
                 });
     }
diff --git a/services/tests/vibrator/utils/com/android/server/vibrator/FakeVibratorControllerProvider.java b/services/tests/vibrator/utils/com/android/server/vibrator/FakeVibratorControllerProvider.java
index 946e1ea..6dc1b10 100644
--- a/services/tests/vibrator/utils/com/android/server/vibrator/FakeVibratorControllerProvider.java
+++ b/services/tests/vibrator/utils/com/android/server/vibrator/FakeVibratorControllerProvider.java
@@ -76,6 +76,9 @@
     private float mFrequencyResolution = Float.NaN;
     private float mQFactor = Float.NaN;
     private float[] mMaxAmplitudes;
+
+    private float[] mFrequenciesHz;
+    private float[] mOutputAccelerationsGs;
     private long mVendorEffectDuration = EFFECT_DURATION;
 
     void recordEffectSegment(long vibrationId, VibrationEffectSegment segment) {
@@ -218,8 +221,11 @@
             }
             infoBuilder.setCompositionSizeMax(mCompositionSizeMax);
             infoBuilder.setQFactor(mQFactor);
-            infoBuilder.setFrequencyProfile(new VibratorInfo.FrequencyProfile(
+            infoBuilder.setFrequencyProfileLegacy(new VibratorInfo.FrequencyProfileLegacy(
                     mResonantFrequency, mMinFrequency, mFrequencyResolution, mMaxAmplitudes));
+            infoBuilder.setFrequencyProfile(
+                    new VibratorInfo.FrequencyProfile(mResonantFrequency, mFrequenciesHz,
+                            mOutputAccelerationsGs));
             infoBuilder.setMaxEnvelopeEffectSize(mMaxEnvelopeEffectSize);
             infoBuilder.setMinEnvelopeEffectControlPointDurationMillis(
                     mMinEnvelopeEffectControlPointDurationMillis);
@@ -360,6 +366,16 @@
         mMaxAmplitudes = maxAmplitudes;
     }
 
+    /** Set the list of available frequencies. */
+    public void setFrequenciesHz(float[] frequenciesHz) {
+        mFrequenciesHz = frequenciesHz;
+    }
+
+    /** Set the max output acceleration achievable by the supported frequencies. */
+    public void setOutputAccelerationsGs(float[] outputAccelerationsGs) {
+        mOutputAccelerationsGs = outputAccelerationsGs;
+    }
+
     /** Set the duration of vendor effects in fake vibrator hardware. */
     public void setVendorEffectDuration(long durationMs) {
         mVendorEffectDuration = durationMs;
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppCompatCameraPolicyTest.java b/services/tests/wmtests/src/com/android/server/wm/AppCompatCameraPolicyTest.java
index 9b9040b..cb5afd8 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppCompatCameraPolicyTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppCompatCameraPolicyTest.java
@@ -18,7 +18,6 @@
 
 import static android.content.pm.ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_ONLY_FOR_CAMERA;
 
-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.AppCompatCameraPolicy.isTreatmentEnabledForActivity;
 import static com.android.server.wm.AppCompatCameraPolicy.shouldOverrideMinAspectRatioForCamera;
@@ -26,7 +25,6 @@
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
-import static org.mockito.ArgumentMatchers.any;
 
 import android.compat.testing.PlatformCompatChangeRule;
 import android.platform.test.annotations.DisableFlags;
@@ -90,7 +88,7 @@
     @EnableFlags(FLAG_ENABLE_CAMERA_COMPAT_FOR_DESKTOP_WINDOWING)
     public void testCameraCompatFreeformPolicy_presentWhenEnabledAndDW() {
         runTestScenario((robot) -> {
-            robot.allowEnterDesktopMode(/* isAllowed= */ true);
+            robot.dw().allowEnterDesktopMode(/* isAllowed= */ true);
             robot.activity().createActivityWithComponentInNewTaskAndDisplay();
             robot.checkTopActivityHasCameraCompatFreeformPolicy(/* exists= */ true);
         });
@@ -100,7 +98,7 @@
     @EnableFlags(FLAG_ENABLE_CAMERA_COMPAT_FOR_DESKTOP_WINDOWING)
     public void testCameraCompatFreeformPolicy_notPresentWhenNoDW() {
         runTestScenario((robot) -> {
-            robot.allowEnterDesktopMode(/* isAllowed= */ false);
+            robot.dw().allowEnterDesktopMode(/* isAllowed= */ false);
             robot.activity().createActivityWithComponentInNewTaskAndDisplay();
             robot.checkTopActivityHasCameraCompatFreeformPolicy(/* exists= */ false);
         });
@@ -110,7 +108,7 @@
     @DisableFlags(FLAG_ENABLE_CAMERA_COMPAT_FOR_DESKTOP_WINDOWING)
     public void testCameraCompatFreeformPolicy_notPresentWhenNoFlag() {
         runTestScenario((robot) -> {
-            robot.allowEnterDesktopMode(/* isAllowed= */ true);
+            robot.dw().allowEnterDesktopMode(/* isAllowed= */ true);
             robot.activity().createActivityWithComponentInNewTaskAndDisplay();
             robot.checkTopActivityHasCameraCompatFreeformPolicy(/* exists= */ false);
         });
@@ -120,7 +118,7 @@
     @EnableFlags(FLAG_ENABLE_CAMERA_COMPAT_FOR_DESKTOP_WINDOWING)
     public void testCameraCompatFreeformPolicy_notPresentWhenNoFlagAndNoDW() {
         runTestScenario((robot) -> {
-            robot.allowEnterDesktopMode(/* isAllowed= */ false);
+            robot.dw().allowEnterDesktopMode(/* isAllowed= */ false);
             robot.activity().createActivityWithComponentInNewTaskAndDisplay();
             robot.checkTopActivityHasCameraCompatFreeformPolicy(/* exists= */ false);
         });
@@ -130,7 +128,7 @@
     @EnableFlags(FLAG_ENABLE_CAMERA_COMPAT_FOR_DESKTOP_WINDOWING)
     public void testCameraCompatFreeformPolicy_startedWhenEnabledAndDW() {
         runTestScenario((robot) -> {
-            robot.allowEnterDesktopMode(/* isAllowed= */ true);
+            robot.dw().allowEnterDesktopMode(/* isAllowed= */ true);
             robot.activity().createActivityWithComponentInNewTaskAndDisplay();
             robot.checkTopActivityHasCameraCompatFreeformPolicy(/* exists= */ true);
             robot.checkTopActivityCameraCompatFreeformPolicyIsRunning();
@@ -141,7 +139,7 @@
     @EnableFlags(FLAG_ENABLE_CAMERA_COMPAT_FOR_DESKTOP_WINDOWING)
     public void testCameraStateManager_existsWhenCameraCompatFreeformExists() {
         runTestScenario((robot) -> {
-            robot.allowEnterDesktopMode(true);
+            robot.dw().allowEnterDesktopMode(true);
             robot.activity().createActivityWithComponentInNewTaskAndDisplay();
             robot.checkTopActivityHasCameraCompatFreeformPolicy(/* exists= */ true);
             robot.checkTopActivityHasCameraStateMonitor(/* exists= */ true);
@@ -152,7 +150,7 @@
     @EnableFlags(FLAG_ENABLE_CAMERA_COMPAT_FOR_DESKTOP_WINDOWING)
     public void testCameraStateManager_startedWhenCameraCompatFreeformExists() {
         runTestScenario((robot) -> {
-            robot.allowEnterDesktopMode(true);
+            robot.dw().allowEnterDesktopMode(true);
             robot.activity().createActivityWithComponentInNewTaskAndDisplay();
             robot.checkTopActivityHasCameraCompatFreeformPolicy(/* exists= */ true);
             robot.checkTopActivityHasCameraStateMonitor(/* exists= */ true);
@@ -224,7 +222,7 @@
     public void testShouldOverrideMinAspectRatioForCamera_whenCameraIsNotRunning() {
         runTestScenario((robot) -> {
             robot.applyOnActivity((a)-> {
-                robot.allowEnterDesktopMode(true);
+                robot.dw().allowEnterDesktopMode(true);
                 robot.conf().enableCameraCompatTreatmentAtBuildTime(/* enabled= */ true);
                 a.createActivityWithComponentInNewTaskAndDisplay();
                 a.setIsCameraRunningAndWindowingModeEligibleFullscreen(/* enabled */ false);
@@ -239,7 +237,7 @@
     public void testShouldOverrideMinAspectRatioForCamera_whenCameraIsRunning_overrideDisabled() {
         runTestScenario((robot) -> {
             robot.applyOnActivity((a)-> {
-                robot.allowEnterDesktopMode(true);
+                robot.dw().allowEnterDesktopMode(true);
                 robot.conf().enableCameraCompatTreatmentAtBuildTime(/* enabled= */ true);
                 a.createActivityWithComponentInNewTaskAndDisplay();
                 a.setIsCameraRunningAndWindowingModeEligibleFullscreen(/* active */ true);
@@ -270,7 +268,7 @@
     public void testShouldOverrideMinAspectRatioForCameraFreeform_cameraRunning_overrideEnabled() {
         runTestScenario((robot) -> {
             robot.applyOnActivity((a)-> {
-                robot.allowEnterDesktopMode(true);
+                robot.dw().allowEnterDesktopMode(true);
                 a.createActivityWithComponentInNewTaskAndDisplay();
                 a.setIsCameraRunningAndWindowingModeEligibleFreeform(/* active */ true);
             });
@@ -346,11 +344,5 @@
         void checkShouldOverrideMinAspectRatioForCamera(boolean expected) {
             assertEquals(expected, shouldOverrideMinAspectRatioForCamera(activity().top()));
         }
-
-        // TODO(b/350460645): Create Desktop Windowing Robot to reuse common functionalities.
-        void allowEnterDesktopMode(boolean isAllowed) {
-            doReturn(isAllowed).when(() ->
-                    DesktopModeHelper.canEnterDesktopMode(any()));
-        }
     }
 }
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppCompatOrientationOverridesTest.java b/services/tests/wmtests/src/com/android/server/wm/AppCompatOrientationOverridesTest.java
index d9b5f37..8747cfa 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppCompatOrientationOverridesTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppCompatOrientationOverridesTest.java
@@ -17,11 +17,13 @@
 
 import static android.content.pm.ActivityInfo.OVERRIDE_ENABLE_COMPAT_IGNORE_ORIENTATION_REQUEST_WHEN_LOOP_DETECTED;
 import static android.content.pm.ActivityInfo.OVERRIDE_USE_DISPLAY_LANDSCAPE_NATURAL_ORIENTATION;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
 import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
 import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
 import static android.view.WindowManager.PROPERTY_COMPAT_ALLOW_DISPLAY_ORIENTATION_OVERRIDE;
 import static android.view.WindowManager.PROPERTY_COMPAT_ALLOW_IGNORING_ORIENTATION_REQUEST_WHEN_LOOP_DETECTED;
 
+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.AppCompatOrientationOverrides.OrientationOverridesState.MIN_COUNT_TO_IGNORE_REQUEST_IN_LOOP;
 import static com.android.server.wm.AppCompatOrientationOverrides.OrientationOverridesState.SET_ORIENTATION_REQUEST_COUNTER_TIMEOUT_MS;
@@ -31,6 +33,7 @@
 import static org.junit.Assert.assertTrue;
 
 import android.compat.testing.PlatformCompatChangeRule;
+import android.content.pm.ActivityInfo.ScreenOrientation;
 import android.platform.test.annotations.Presubmit;
 
 import androidx.annotation.NonNull;
@@ -228,6 +231,25 @@
         });
     }
 
+    @Test
+    public void testOverrideRespectRequestedOrientationIsEnabled_bottomOrientationIsRespected() {
+        runTestScenario((robot) -> {
+            robot.applyOnActivity((a) -> {
+                a.setIgnoreOrientationRequest(true);
+                a.createActivityWithComponentInNewTask();
+                robot.setOverrideRespectRequestedOrientationEnabled(true);
+                a.configureUnresizableTopActivity(SCREEN_ORIENTATION_LANDSCAPE);
+                robot.checkDisplayShouldIgnoreOrientationRequest(SCREEN_ORIENTATION_LANDSCAPE,
+                        /* expected */ false);
+
+                a.createActivityWithComponentInNewTask();
+                a.setTopActivityInFreeformWindowingMode(true);
+            });
+            robot.checkDisplayShouldIgnoreOrientationRequest(SCREEN_ORIENTATION_LANDSCAPE,
+                    /* expected */ false);
+        });
+    }
+
     /**
      * Runs a test scenario providing a Robot.
      */
@@ -291,6 +313,22 @@
             }
         }
 
+        void setOverrideRespectRequestedOrientationEnabled(boolean override) {
+            spyOn(getTopOrientationOverrides());
+            doReturn(override).when(getTopOrientationOverrides())
+                    .isOverrideRespectRequestedOrientationEnabled();
+        }
+
+        void checkDisplayShouldIgnoreOrientationRequest(@ScreenOrientation int candidate,
+                boolean expected) {
+            assertEquals(expected, activity().displayContent()
+                    .shouldIgnoreOrientationRequest(candidate));
+        }
+
+        void checkExpectedDisplayOrientation(@ScreenOrientation int expected) {
+            assertEquals(expected, activity().displayContent().getOrientation());
+        }
+
         void checkShouldUseDisplayLandscapeNaturalOrientation(boolean expected) {
             assertEquals(expected,
                     getTopOrientationOverrides().shouldUseDisplayLandscapeNaturalOrientation());
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppCompatOrientationPolicyTest.java b/services/tests/wmtests/src/com/android/server/wm/AppCompatOrientationPolicyTest.java
index 76101d5..09ed9ba 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppCompatOrientationPolicyTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppCompatOrientationPolicyTest.java
@@ -37,12 +37,10 @@
 import static android.view.WindowManager.PROPERTY_COMPAT_ALLOW_USER_ASPECT_RATIO_FULLSCREEN_OVERRIDE;
 import static android.view.WindowManager.PROPERTY_COMPAT_IGNORE_REQUESTED_ORIENTATION;
 
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
 import static com.android.window.flags.Flags.FLAG_ENABLE_CAMERA_COMPAT_FOR_DESKTOP_WINDOWING;
 
 import static org.junit.Assert.assertEquals;
-import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.verify;
 
 import android.compat.testing.PlatformCompatChangeRule;
@@ -338,7 +336,7 @@
     public void testOverrideOrientationIfNeeded_fullscrOverrideFreeform_cameraActivity_unchanged() {
         runTestScenario((robot) -> {
             robot.applyOnActivity((a) -> {
-                robot.allowEnterDesktopMode(true);
+                robot.dw().allowEnterDesktopMode(true);
                 a.createActivityWithComponentInNewTaskAndDisplay();
                 a.setIsCameraRunningAndWindowingModeEligibleFreeform(false);
             });
@@ -610,11 +608,5 @@
         private AppCompatOrientationPolicy getTopAppCompatOrientationPolicy() {
             return activity().top().mAppCompatController.getOrientationPolicy();
         }
-
-        // TODO(b/350460645): Create Desktop Windowing Robot to reuse common functionalities.
-        void allowEnterDesktopMode(boolean isAllowed) {
-            doReturn(isAllowed).when(() ->
-                    DesktopModeHelper.canEnterDesktopMode(any()));
-        }
     }
 }
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppCompatRobotBase.java b/services/tests/wmtests/src/com/android/server/wm/AppCompatRobotBase.java
index 5f2a63a..0d929ab 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppCompatRobotBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppCompatRobotBase.java
@@ -39,6 +39,8 @@
     private final AppCompatComponentPropRobot mOptPropRobot;
     @NonNull
     private final AppCompatResourcesRobot mResourcesRobot;
+    @NonNull
+    private final DesktopWindowingRobot mDesktopWindowingRobot;
 
     AppCompatRobotBase(@NonNull WindowManagerService wm,
             @NonNull ActivityTaskManagerService atm,
@@ -51,6 +53,7 @@
                 new AppCompatConfigurationRobot(wm.mAppCompatConfiguration);
         mOptPropRobot = new AppCompatComponentPropRobot(wm);
         mResourcesRobot = new AppCompatResourcesRobot(wm.mContext.getResources());
+        mDesktopWindowingRobot = new DesktopWindowingRobot();
     }
 
     AppCompatRobotBase(@NonNull WindowManagerService wm,
@@ -111,6 +114,11 @@
         return mResourcesRobot;
     }
 
+    @NonNull
+    DesktopWindowingRobot dw() {
+        return mDesktopWindowingRobot;
+    }
+
     void applyOnResources(@NonNull Consumer<AppCompatResourcesRobot> consumer) {
         consumer.accept(mResourcesRobot);
     }
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppCompatUtilsTest.java b/services/tests/wmtests/src/com/android/server/wm/AppCompatUtilsTest.java
index d8373c5..50c2c2f 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppCompatUtilsTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppCompatUtilsTest.java
@@ -18,16 +18,26 @@
 
 import static android.app.CameraCompatTaskInfo.CAMERA_COMPAT_FREEFORM_PORTRAIT_DEVICE_IN_LANDSCAPE;
 
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
 
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.when;
 
 import android.app.CameraCompatTaskInfo.FreeformCameraCompatMode;
 import android.app.TaskInfo;
+import android.platform.test.annotations.EnableFlags;
 import android.platform.test.annotations.Presubmit;
+import android.view.DisplayInfo;
+import android.view.Surface;
 
 import androidx.annotation.NonNull;
 
+import com.android.window.flags.Flags;
+
 import org.junit.Assert;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -174,9 +184,13 @@
     }
 
     @Test
+    @EnableFlags(Flags.FLAG_ENABLE_CAMERA_COMPAT_FOR_DESKTOP_WINDOWING)
     public void getTaskInfoPropagatesCameraCompatMode() {
         runTestScenario((robot) -> {
-            robot.applyOnActivity(AppCompatActivityRobot::createActivityWithComponentInNewTask);
+            robot.dw().allowEnterDesktopMode(/* isAllowed= */ true);
+            robot.applyOnActivity(
+                    AppCompatActivityRobot::createActivityWithComponentInNewTaskAndDisplay);
+            robot.setCameraCompatTreatmentEnabledForActivity(/* enabled= */ true);
 
             robot.setFreeformCameraCompatMode(CAMERA_COMPAT_FREEFORM_PORTRAIT_DEVICE_IN_LANDSCAPE);
             robot.checkTaskInfoFreeformCameraCompatMode(
@@ -212,6 +226,15 @@
             spyOn(activity.mAppCompatController.getAppCompatAspectRatioPolicy());
         }
 
+        @Override
+        void onPostDisplayContentCreation(@NonNull DisplayContent displayContent) {
+            super.onPostDisplayContentCreation(displayContent);
+            mockPortraitDisplay(displayContent);
+            if (displayContent.mAppCompatCameraPolicy.hasCameraCompatFreeformPolicy()) {
+                spyOn(displayContent.mAppCompatCameraPolicy.mCameraCompatFreeformPolicy);
+            }
+        }
+
         void transparentActivity(@NonNull Consumer<AppCompatTransparentActivityRobot> consumer) {
             // We always create at least an opaque activity in a Task.
             activity().createNewTaskWithBaseActivity();
@@ -235,8 +258,8 @@
         }
 
         void setFreeformCameraCompatMode(@FreeformCameraCompatMode int mode) {
-            activity().top().mAppCompatController.getAppCompatCameraOverrides()
-                    .setFreeformCameraCompatMode(mode);
+            doReturn(mode).when(activity().top().mDisplayContent.mAppCompatCameraPolicy
+                    .mCameraCompatFreeformPolicy).getCameraCompatMode(activity().top());
         }
 
         void checkTopActivityLetterboxReason(@NonNull String expected) {
@@ -258,6 +281,24 @@
             Assert.assertEquals(mode, getTopTaskInfo().appCompatTaskInfo
                     .cameraCompatTaskInfo.freeformCameraCompatMode);
         }
-    }
 
+        void setCameraCompatTreatmentEnabledForActivity(boolean enabled) {
+            doReturn(enabled).when(activity().displayContent().mAppCompatCameraPolicy
+                    .mCameraCompatFreeformPolicy).isTreatmentEnabledForActivity(
+                            eq(activity().top()), anyBoolean());
+        }
+
+        private void mockPortraitDisplay(DisplayContent displayContent) {
+            doAnswer(invocation -> {
+                DisplayInfo displayInfo = new DisplayInfo();
+                displayContent.getDisplay().getDisplayInfo(displayInfo);
+                displayInfo.rotation = Surface.ROTATION_90;
+                // Set height and width so that the natural orientation (when rotation is 0) is
+                // portrait.
+                displayInfo.logicalHeight = 600;
+                displayInfo.logicalWidth =  800;
+                return displayInfo;
+            }).when(displayContent.mWmService.mDisplayManagerInternal).getDisplayInfo(anyInt());
+        }
+    }
 }
diff --git a/services/tests/wmtests/src/com/android/server/wm/CameraCompatFreeformPolicyTests.java b/services/tests/wmtests/src/com/android/server/wm/CameraCompatFreeformPolicyTests.java
index a8ccf95..a07fd23 100644
--- a/services/tests/wmtests/src/com/android/server/wm/CameraCompatFreeformPolicyTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/CameraCompatFreeformPolicyTests.java
@@ -223,10 +223,13 @@
         setDisplayRotation(Surface.ROTATION_270);
 
         mCameraAvailabilityCallback.onCameraOpened(CAMERA_ID_1, TEST_PACKAGE_1);
-        callOnActivityConfigurationChanging(mActivity);
+        callOnActivityConfigurationChanging(mActivity, /* letterboxNew= */ true,
+                /* lastLetterbox= */ false);
         mCameraAvailabilityCallback.onCameraClosed(CAMERA_ID_1);
         mCameraAvailabilityCallback.onCameraOpened(CAMERA_ID_1, TEST_PACKAGE_1);
-        callOnActivityConfigurationChanging(mActivity);
+        // Activity is letterboxed from the previous configuration change.
+        callOnActivityConfigurationChanging(mActivity, /* letterboxNew= */ true,
+                /* lastLetterbox= */ true);
 
         assertInCameraCompatMode(CAMERA_COMPAT_FREEFORM_PORTRAIT_DEVICE_IN_LANDSCAPE);
         assertActivityRefreshRequested(/* refreshRequested */ true);
@@ -264,6 +267,48 @@
 
     @Test
     @EnableFlags(FLAG_ENABLE_CAMERA_COMPAT_FOR_DESKTOP_WINDOWING)
+    public void testShouldRefreshActivity_appBoundsChanged_returnsTrue() {
+        configureActivity(SCREEN_ORIENTATION_PORTRAIT);
+        Configuration oldConfiguration = createConfiguration(/* letterbox= */ false);
+        Configuration newConfiguration = createConfiguration(/* letterbox= */ true);
+        mCameraAvailabilityCallback.onCameraOpened(CAMERA_ID_1, TEST_PACKAGE_1);
+
+        assertTrue(mCameraCompatFreeformPolicy.shouldRefreshActivity(mActivity, newConfiguration,
+                oldConfiguration));
+    }
+
+    @Test
+    @EnableFlags(FLAG_ENABLE_CAMERA_COMPAT_FOR_DESKTOP_WINDOWING)
+    public void testShouldRefreshActivity_displayRotationChanged_returnsTrue() {
+        configureActivity(SCREEN_ORIENTATION_PORTRAIT);
+        Configuration oldConfiguration = createConfiguration(/* letterbox= */ true);
+        Configuration newConfiguration = createConfiguration(/* letterbox= */ true);
+
+        oldConfiguration.windowConfiguration.setDisplayRotation(0);
+        newConfiguration.windowConfiguration.setDisplayRotation(90);
+        mCameraAvailabilityCallback.onCameraOpened(CAMERA_ID_1, TEST_PACKAGE_1);
+
+        assertTrue(mCameraCompatFreeformPolicy.shouldRefreshActivity(mActivity, newConfiguration,
+                oldConfiguration));
+    }
+
+    @Test
+    @EnableFlags(FLAG_ENABLE_CAMERA_COMPAT_FOR_DESKTOP_WINDOWING)
+    public void testShouldRefreshActivity_appBoundsNorDisplayChanged_returnsFalse() {
+        configureActivity(SCREEN_ORIENTATION_PORTRAIT);
+        Configuration oldConfiguration = createConfiguration(/* letterbox= */ true);
+        Configuration newConfiguration = createConfiguration(/* letterbox= */ true);
+
+        oldConfiguration.windowConfiguration.setDisplayRotation(0);
+        newConfiguration.windowConfiguration.setDisplayRotation(0);
+        mCameraAvailabilityCallback.onCameraOpened(CAMERA_ID_1, TEST_PACKAGE_1);
+
+        assertFalse(mCameraCompatFreeformPolicy.shouldRefreshActivity(mActivity, newConfiguration,
+                oldConfiguration));
+    }
+
+    @Test
+    @EnableFlags(FLAG_ENABLE_CAMERA_COMPAT_FOR_DESKTOP_WINDOWING)
     public void testOnActivityConfigurationChanging_refreshDisabledViaFlag_noRefresh()
             throws Exception {
         configureActivity(SCREEN_ORIENTATION_PORTRAIT);
@@ -306,6 +351,7 @@
     }
 
     @Test
+    @EnableFlags(FLAG_ENABLE_CAMERA_COMPAT_FOR_DESKTOP_WINDOWING)
     public void testGetCameraCompatAspectRatio_activityNotInCameraCompat_returnsDefaultAspRatio() {
         configureActivity(SCREEN_ORIENTATION_FULL_USER);
 
@@ -318,6 +364,7 @@
     }
 
     @Test
+    @EnableFlags(FLAG_ENABLE_CAMERA_COMPAT_FOR_DESKTOP_WINDOWING)
     public void testGetCameraCompatAspectRatio_activityInCameraCompat_returnsConfigAspectRatio() {
         configureActivity(SCREEN_ORIENTATION_PORTRAIT);
         final float configAspectRatio = 1.5f;
@@ -331,8 +378,8 @@
                 /* delta= */ 0.001);
     }
 
-
     @Test
+    @EnableFlags(FLAG_ENABLE_CAMERA_COMPAT_FOR_DESKTOP_WINDOWING)
     public void testGetCameraCompatAspectRatio_inCameraCompatPerAppOverride_returnDefAspectRatio() {
         configureActivity(SCREEN_ORIENTATION_PORTRAIT);
         final float configAspectRatio = 1.5f;
@@ -411,9 +458,15 @@
     }
 
     private void callOnActivityConfigurationChanging(ActivityRecord activity) {
+        callOnActivityConfigurationChanging(activity, /* letterboxNew= */ true,
+                /* lastLetterbox= */false);
+    }
+
+    private void callOnActivityConfigurationChanging(ActivityRecord activity, boolean letterboxNew,
+            boolean lastLetterbox) {
         mActivityRefresher.onActivityConfigurationChanging(activity,
-                /* newConfig */ createConfiguration(/*letterbox=*/ true),
-                /* lastReportedConfig */ createConfiguration(/*letterbox=*/ false));
+                /* newConfig */ createConfiguration(letterboxNew),
+                /* lastReportedConfig */ createConfiguration(lastLetterbox));
     }
 
     private Configuration createConfiguration(boolean letterbox) {
diff --git a/services/tests/wmtests/src/com/android/server/wm/ContentRecorderTests.java b/services/tests/wmtests/src/com/android/server/wm/ContentRecorderTests.java
index e443696..c51261f 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ContentRecorderTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ContentRecorderTests.java
@@ -52,6 +52,7 @@
 import android.os.IBinder;
 import android.platform.test.annotations.Presubmit;
 import android.view.ContentRecordingSession;
+import android.view.Display;
 import android.view.DisplayInfo;
 import android.view.Gravity;
 import android.view.SurfaceControl;
@@ -93,9 +94,11 @@
     private boolean mHandleAnisotropicDisplayMirroring = false;
 
     @Before public void setUp() {
+        mDisplayInfo.type = Display.TYPE_VIRTUAL;
         MockitoAnnotations.initMocks(this);
 
         doReturn(INVALID_DISPLAY).when(mWm.mDisplayManagerInternal).getDisplayIdToMirror(anyInt());
+        doReturn(false).when(mWm.mDisplayManagerInternal).isDisplayReadyForMirroring(anyInt());
 
         // Skip unnecessary operations of relayout.
         spyOn(mWm.mWindowPlacerLocked);
@@ -163,6 +166,25 @@
     }
 
     @Test
+    public void testUpdateRecording_externalDisplayWithoutUserConfirmation() {
+        mDisplayInfo.type = Display.TYPE_EXTERNAL;
+        defaultInit();
+        mContentRecorder.setContentRecordingSession(mDisplaySession);
+        mContentRecorder.updateRecording();
+        assertThat(mContentRecorder.isCurrentlyRecording()).isFalse();
+    }
+
+    @Test
+    public void testUpdateRecording_externalDisplayWithUserConfirmation() {
+        doReturn(true).when(mWm.mDisplayManagerInternal).isDisplayReadyForMirroring(anyInt());
+        mDisplayInfo.type = Display.TYPE_EXTERNAL;
+        defaultInit();
+        mContentRecorder.setContentRecordingSession(mDisplaySession);
+        mContentRecorder.updateRecording();
+        assertThat(mContentRecorder.isCurrentlyRecording()).isTrue();
+    }
+
+    @Test
     public void testUpdateRecording_display_invalidDisplayIdToMirror() {
         defaultInit();
         ContentRecordingSession session = ContentRecordingSession.createDisplaySession(
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/ui/viewmodel/PartitionedGridViewModelKosmos.kt b/services/tests/wmtests/src/com/android/server/wm/DesktopWindowingRobot.java
similarity index 61%
copy from packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/ui/viewmodel/PartitionedGridViewModelKosmos.kt
copy to services/tests/wmtests/src/com/android/server/wm/DesktopWindowingRobot.java
index fde174d..285a5e2 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/ui/viewmodel/PartitionedGridViewModelKosmos.kt
+++ b/services/tests/wmtests/src/com/android/server/wm/DesktopWindowingRobot.java
@@ -14,15 +14,15 @@
  * limitations under the License.
  */
 
-package com.android.systemui.qs.panels.ui.viewmodel
+package com.android.server.wm;
 
-import com.android.systemui.kosmos.Kosmos
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
 
-val Kosmos.partitionedGridViewModel by
-    Kosmos.Fixture {
-        PartitionedGridViewModel(
-            iconTilesViewModel,
-            fixedColumnsSizeViewModel,
-            iconLabelVisibilityViewModel,
-        )
+import static org.mockito.ArgumentMatchers.any;
+
+/** Robot for changing desktop windowing properties. */
+class DesktopWindowingRobot {
+    void allowEnterDesktopMode(boolean isAllowed) {
+        doReturn(isAllowed).when(() -> DesktopModeHelper.canEnterDesktopMode(any()));
     }
+}
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayRotationImmersiveAppCompatPolicyTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayRotationImmersiveAppCompatPolicyTests.java
index 5e8f347..c8fc482 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayRotationImmersiveAppCompatPolicyTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayRotationImmersiveAppCompatPolicyTests.java
@@ -26,7 +26,6 @@
 
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
 
 import static org.junit.Assert.assertFalse;
@@ -73,7 +72,6 @@
         when(mMockWindowState.getRequestedVisibleTypes()).thenReturn(0);
         when(mMockActivityRecord.findMainWindow()).thenReturn(mMockWindowState);
 
-        spy(mDisplayContent);
         doReturn(mMockActivityRecord).when(mDisplayContent).topRunningActivity();
         when(mDisplayContent.getIgnoreOrientationRequest()).thenReturn(true);
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java b/services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java
index b26c267..d2cf03d 100644
--- a/services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java
@@ -41,7 +41,10 @@
 import static org.mockito.Mockito.verify;
 
 import android.app.StatusBarManager;
+import android.graphics.Rect;
 import android.os.Binder;
+import android.platform.test.annotations.DisableFlags;
+import android.platform.test.annotations.EnableFlags;
 import android.platform.test.annotations.Presubmit;
 import android.view.InsetsFrameProvider;
 import android.view.InsetsSource;
@@ -52,6 +55,7 @@
 import androidx.test.filters.SmallTest;
 
 import com.android.server.statusbar.StatusBarManagerInternal;
+import com.android.window.flags.Flags;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -95,6 +99,7 @@
     }
 
     @Test
+    @DisableFlags(Flags.FLAG_ENABLE_FULLY_IMMERSIVE_IN_DESKTOP)
     public void testControlsForDispatch_freeformTaskVisible() {
         addStatusBar();
         addNavigationBar();
@@ -108,6 +113,37 @@
     }
 
     @Test
+    @EnableFlags(Flags.FLAG_ENABLE_FULLY_IMMERSIVE_IN_DESKTOP)
+    public void testControlsForDispatch_fullscreenFreeformTaskVisible() {
+        addStatusBar();
+        addNavigationBar();
+
+        final WindowState win = createWindow(null, WINDOWING_MODE_FREEFORM,
+                ACTIVITY_TYPE_STANDARD, TYPE_APPLICATION, mDisplayContent, "app");
+        win.setBounds(new Rect());
+        final InsetsSourceControl[] controls = addWindowAndGetControlsForDispatch(win);
+
+        // The freeform (w/fullscreen bounds) app window can control both system bars.
+        assertNotNull(controls);
+        assertEquals(2, controls.length);
+    }
+
+    @Test
+    @EnableFlags(Flags.FLAG_ENABLE_FULLY_IMMERSIVE_IN_DESKTOP)
+    public void testControlsForDispatch_nonFullscreenFreeformTaskVisible() {
+        addStatusBar();
+        addNavigationBar();
+
+        final WindowState win = createWindow(null, WINDOWING_MODE_FREEFORM,
+                ACTIVITY_TYPE_STANDARD, TYPE_APPLICATION, mDisplayContent, "app");
+        win.getTask().setBounds(new Rect(1, 1, 10, 10));
+        final InsetsSourceControl[] controls = addWindowAndGetControlsForDispatch(win);
+
+        // The freeform (but not fullscreen bounds) app window must not control any system bars.
+        assertNull(controls);
+    }
+
+    @Test
     public void testControlsForDispatch_forceStatusBarVisible() {
         addStatusBar().mAttrs.forciblyShownTypes |= statusBars();
         addNavigationBar();
diff --git a/services/tests/wmtests/src/com/android/server/wm/LetterboxAttachInputTest.java b/services/tests/wmtests/src/com/android/server/wm/LetterboxAttachInputTest.java
new file mode 100644
index 0000000..7e1de47
--- /dev/null
+++ b/services/tests/wmtests/src/com/android/server/wm/LetterboxAttachInputTest.java
@@ -0,0 +1,178 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm;
+
+import static com.android.server.testutils.MockitoUtilsKt.eq;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.clearInvocations;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+
+import android.graphics.Color;
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.os.InputConfig;
+import android.platform.test.annotations.DisableFlags;
+import android.platform.test.annotations.EnableFlags;
+import android.platform.test.annotations.Presubmit;
+import android.view.InputWindowHandle;
+import android.view.SurfaceControl;
+import android.view.WindowManager;
+
+import com.android.server.testutils.StubTransaction;
+import com.android.window.flags.Flags;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+
+/**
+ * Test class for {@link Letterbox}.
+ * <p>
+ * Build/Install/Run:
+ * atest WmTests:LetterboxAttachInputTest
+ */
+@Presubmit
+@RunWith(WindowTestRunner.class)
+public class LetterboxAttachInputTest extends WindowTestsBase {
+
+    private Letterbox mLetterbox;
+    private LetterboxTest.SurfaceControlMocker mSurfaces;
+
+    @Before
+    public void setUp() throws Exception {
+        mSurfaces = new LetterboxTest.SurfaceControlMocker();
+        AppCompatLetterboxOverrides letterboxOverrides = mock(AppCompatLetterboxOverrides.class);
+        doReturn(false).when(letterboxOverrides).shouldLetterboxHaveRoundedCorners();
+        doReturn(Color.valueOf(Color.BLACK)).when(letterboxOverrides)
+                .getLetterboxBackgroundColor();
+        doReturn(false).when(letterboxOverrides).hasWallpaperBackgroundForLetterbox();
+        doReturn(0).when(letterboxOverrides).getLetterboxWallpaperBlurRadiusPx();
+        doReturn(0.5f).when(letterboxOverrides).getLetterboxWallpaperDarkScrimAlpha();
+        mLetterbox = new Letterbox(mSurfaces, StubTransaction::new,
+                mock(AppCompatReachabilityPolicy.class), letterboxOverrides,
+                () -> mock(SurfaceControl.class));
+        mTransaction = spy(StubTransaction.class);
+    }
+
+    @DisableFlags(Flags.FLAG_SCROLLING_FROM_LETTERBOX)
+    @Test
+    public void testSurface_createdHasSlipperyInput_scrollingFromLetterboxDisabled() {
+        mLetterbox.layout(new Rect(0, 0, 10, 10), new Rect(0, 1, 10, 10), new Point(1000, 2000));
+
+        attachInput();
+        applySurfaceChanges();
+
+        assertNotNull(mSurfaces.top);
+        ArgumentCaptor<InputWindowHandle> handleCaptor =
+                ArgumentCaptor.forClass(InputWindowHandle.class);
+        verify(mTransaction).setInputWindowInfo(eq(mSurfaces.top), handleCaptor.capture());
+        InputWindowHandle capturedHandle = handleCaptor.getValue();
+        assertTrue((capturedHandle.inputConfig & InputConfig.SLIPPERY) != 0);
+        assertFalse((capturedHandle.inputConfig & InputConfig.SPY) != 0);
+    }
+
+    @DisableFlags(Flags.FLAG_SCROLLING_FROM_LETTERBOX)
+    @Test
+    public void testInputSurface_notCreated_scrollingFromLetterboxDisabled() {
+        mLetterbox.layout(new Rect(0, 0, 10, 10), new Rect(0, 1, 10, 10), new Point(1000, 2000));
+
+        attachInput();
+        applySurfaceChanges();
+
+        assertNull(mSurfaces.topInput);
+    }
+
+    @EnableFlags(Flags.FLAG_SCROLLING_FROM_LETTERBOX)
+    @Test
+    public void testSurface_createdHasNoInput_scrollingFromLetterboxEnabled() {
+        mLetterbox.layout(new Rect(0, 0, 10, 10), new Rect(0, 1, 10, 10), new Point(1000, 2000));
+
+        attachInput();
+        applySurfaceChanges();
+
+        assertNotNull(mSurfaces.top);
+        verify(mTransaction, never()).setInputWindowInfo(eq(mSurfaces.top), any());
+
+    }
+
+    @EnableFlags(Flags.FLAG_SCROLLING_FROM_LETTERBOX)
+    @Test
+    public void testInputSurface_createdHasSpyInput_scrollingFromLetterboxEnabled() {
+        mLetterbox.layout(new Rect(0, 0, 10, 10), new Rect(0, 1, 10, 10), new Point(1000, 2000));
+
+        attachInput();
+        applySurfaceChanges();
+
+        assertNotNull(mSurfaces.topInput);
+        ArgumentCaptor<InputWindowHandle> handleCaptor =
+                ArgumentCaptor.forClass(InputWindowHandle.class);
+        verify(mTransaction).setInputWindowInfo(eq(mSurfaces.topInput), handleCaptor.capture());
+        InputWindowHandle capturedHandle = handleCaptor.getValue();
+        assertTrue((capturedHandle.inputConfig & InputConfig.SPY) != 0);
+        assertFalse((capturedHandle.inputConfig & InputConfig.SLIPPERY) != 0);
+    }
+
+    @EnableFlags(Flags.FLAG_SCROLLING_FROM_LETTERBOX)
+    @Test
+    public void testInputSurfaceOrigin_applied_scrollingFromLetterboxEnabled() {
+        mLetterbox.layout(new Rect(0, 0, 10, 10), new Rect(0, 1, 10, 10), new Point(1000, 2000));
+
+        attachInput();
+        applySurfaceChanges();
+
+        verify(mTransaction).setPosition(mSurfaces.topInput, -1000, -2000);
+    }
+
+    @EnableFlags(Flags.FLAG_SCROLLING_FROM_LETTERBOX)
+    @Test
+    public void testInputSurfaceOrigin_changeCausesReapply_scrollingFromLetterboxEnabled() {
+        mLetterbox.layout(new Rect(0, 0, 10, 10), new Rect(0, 1, 10, 10), new Point(1000, 2000));
+
+        attachInput();
+        applySurfaceChanges();
+        clearInvocations(mTransaction);
+        mLetterbox.layout(new Rect(0, 0, 10, 10), new Rect(0, 1, 10, 10), new Point(0, 0));
+
+        assertTrue(mLetterbox.needsApplySurfaceChanges());
+
+        applySurfaceChanges();
+
+        verify(mTransaction).setPosition(mSurfaces.topInput, 0, 0);
+    }
+
+    private void applySurfaceChanges() {
+        mLetterbox.applySurfaceChanges(/* syncTransaction */ mTransaction,
+                /* pendingTransaction */ mTransaction);
+    }
+
+    private void attachInput() {
+        final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams();
+        final WindowToken windowToken = createTestWindowToken(0, mDisplayContent);
+        WindowState windowState = createWindowState(attrs, windowToken);
+        mLetterbox.attachInput(windowState);
+    }
+}
diff --git a/services/tests/wmtests/src/com/android/server/wm/LetterboxTest.java b/services/tests/wmtests/src/com/android/server/wm/LetterboxTest.java
index 400fe8b..0baa517 100644
--- a/services/tests/wmtests/src/com/android/server/wm/LetterboxTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/LetterboxTest.java
@@ -33,14 +33,19 @@
 import android.graphics.Color;
 import android.graphics.Point;
 import android.graphics.Rect;
+import android.platform.test.annotations.DisableFlags;
+import android.platform.test.annotations.EnableFlags;
 import android.platform.test.annotations.Presubmit;
+import android.platform.test.flag.junit.SetFlagsRule;
 import android.view.SurfaceControl;
 
 import androidx.test.filters.SmallTest;
 
 import com.android.server.testutils.StubTransaction;
+import com.android.window.flags.Flags;
 
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 import org.mockito.invocation.InvocationOnMock;
 
@@ -56,9 +61,12 @@
 @Presubmit
 public class LetterboxTest {
 
-    Letterbox mLetterbox;
-    SurfaceControlMocker mSurfaces;
-    SurfaceControl.Transaction mTransaction;
+    @Rule
+    public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+
+    private Letterbox mLetterbox;
+    private SurfaceControlMocker mSurfaces;
+    private SurfaceControl.Transaction mTransaction;
 
     private SurfaceControl mParentSurface = mock(SurfaceControl.class);
     private AppCompatLetterboxOverrides mLetterboxOverrides;
@@ -183,6 +191,38 @@
         verify(mTransaction).setPosition(mSurfaces.top, -1000, -2000);
     }
 
+    @DisableFlags(Flags.FLAG_SCROLLING_FROM_LETTERBOX)
+    @Test
+    public void testSurface_created_scrollingFromLetterboxDisabled() {
+        mLetterbox.layout(new Rect(0, 0, 10, 10), new Rect(0, 1, 10, 10), new Point(1000, 2000));
+        applySurfaceChanges();
+        assertNotNull(mSurfaces.top);
+    }
+
+    @DisableFlags(Flags.FLAG_SCROLLING_FROM_LETTERBOX)
+    @Test
+    public void testInputSurface_notCreated_scrollingFromLetterboxDisabled() {
+        mLetterbox.layout(new Rect(0, 0, 10, 10), new Rect(0, 1, 10, 10), new Point(1000, 2000));
+        applySurfaceChanges();
+        assertNull(mSurfaces.topInput);
+    }
+
+    @EnableFlags(Flags.FLAG_SCROLLING_FROM_LETTERBOX)
+    @Test
+    public void testSurface_created_scrollingFromLetterboxEnabled() {
+        mLetterbox.layout(new Rect(0, 0, 10, 10), new Rect(0, 1, 10, 10), new Point(1000, 2000));
+        applySurfaceChanges();
+        assertNotNull(mSurfaces.top);
+    }
+
+    @EnableFlags(Flags.FLAG_SCROLLING_FROM_LETTERBOX)
+    @Test
+    public void testInputSurface_notCreated_notAttachedInputAndScrollingFromLetterboxEnabled() {
+        mLetterbox.layout(new Rect(0, 0, 10, 10), new Rect(0, 1, 10, 10), new Point(1000, 2000));
+        applySurfaceChanges();
+        assertNull(mSurfaces.topInput);
+    }
+
     @Test
     public void testApplySurfaceChanges_setColor() {
         mLetterbox.layout(new Rect(0, 0, 10, 10), new Rect(0, 1, 10, 10), new Point(1000, 2000));
@@ -283,15 +323,11 @@
                 /* pendingTransaction */ mTransaction);
     }
 
-    class SurfaceControlMocker implements Supplier<SurfaceControl.Builder> {
-        private SurfaceControl.Builder mLeftBuilder;
-        public SurfaceControl left;
+    static class SurfaceControlMocker implements Supplier<SurfaceControl.Builder> {
         private SurfaceControl.Builder mTopBuilder;
         public SurfaceControl top;
-        private SurfaceControl.Builder mRightBuilder;
-        public SurfaceControl right;
-        private SurfaceControl.Builder mBottomBuilder;
-        public SurfaceControl bottom;
+        private SurfaceControl.Builder mTopInputBuilder;
+        public SurfaceControl topInput;
         private SurfaceControl.Builder mFullWindowSurfaceBuilder;
         public SurfaceControl fullWindowSurface;
 
@@ -300,32 +336,24 @@
             final SurfaceControl.Builder builder = mock(SurfaceControl.Builder.class,
                     InvocationOnMock::getMock);
             when(builder.setName(anyString())).then((i) -> {
-                if (((String) i.getArgument(0)).contains("left")) {
-                    mLeftBuilder = (SurfaceControl.Builder) i.getMock();
-                } else if (((String) i.getArgument(0)).contains("top")) {
+                if (((String) i.getArgument(0)).contains("Letterbox - top")) {
                     mTopBuilder = (SurfaceControl.Builder) i.getMock();
-                } else if (((String) i.getArgument(0)).contains("right")) {
-                    mRightBuilder = (SurfaceControl.Builder) i.getMock();
-                } else if (((String) i.getArgument(0)).contains("bottom")) {
-                    mBottomBuilder = (SurfaceControl.Builder) i.getMock();
-                } else if (((String) i.getArgument(0)).contains("fullWindow")) {
+                } else if (((String) i.getArgument(0)).contains("Letterbox - fullWindow")) {
                     mFullWindowSurfaceBuilder = (SurfaceControl.Builder) i.getMock();
+                } else if (((String) i.getArgument(0)).contains("LetterboxInput - top")) {
+                    mTopInputBuilder = (SurfaceControl.Builder) i.getMock();
                 }
                 return i.getMock();
             });
 
             doAnswer((i) -> {
                 final SurfaceControl control = mock(SurfaceControl.class);
-                if (i.getMock() == mLeftBuilder) {
-                    left = control;
-                } else if (i.getMock() == mTopBuilder) {
+                if (i.getMock() == mTopBuilder) {
                     top = control;
-                } else if (i.getMock() == mRightBuilder) {
-                    right = control;
-                } else if (i.getMock() == mBottomBuilder) {
-                    bottom = control;
                 } else if (i.getMock() == mFullWindowSurfaceBuilder) {
                     fullWindowSurface = control;
+                } else if (i.getMock() == mTopInputBuilder) {
+                    topInput = control;
                 }
                 return control;
             }).when(builder).build();
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 5b3fd53..7196acc 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
@@ -2933,6 +2933,11 @@
 
         controller.requestStartTransition(transit, task, null, null);
         player.start();
+        // always include config-at-end activity since it is considered "independent" due to
+        // changing at a different time.
+        assertTrue(player.mLastReady.getChanges().stream()
+                .anyMatch((change -> change.getActivityComponent() != null
+                        && (change.getFlags() & TransitionInfo.FLAG_CONFIG_AT_END) != 0)));
         assertTrue(activity.isConfigurationDispatchPaused());
         player.finish();
         assertFalse(activity.isConfigurationDispatchPaused());
@@ -2962,6 +2967,11 @@
 
         controller.requestStartTransition(transit, task, null, null);
         player.start();
+        // always include config-at-end activity since it is considered "independent" due to
+        // changing at a different time.
+        assertTrue(player.mLastReady.getChanges().stream()
+                .anyMatch((change -> change.getActivityComponent() != null
+                        && (change.getFlags() & TransitionInfo.FLAG_CONFIG_AT_END) != 0)));
         assertTrue(activity.isConfigurationDispatchPaused());
         player.finish();
         assertFalse(activity.isConfigurationDispatchPaused());
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java
index 6111a65..8bbba1b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java
@@ -94,6 +94,7 @@
 import android.view.ContentRecordingSession;
 import android.view.IWindow;
 import android.view.InputChannel;
+import android.view.InputDevice;
 import android.view.InsetsSourceControl;
 import android.view.InsetsState;
 import android.view.Surface;
@@ -1275,6 +1276,48 @@
     }
 
     @Test
+    public void testInputDeviceNotifyConfigurationChanged() {
+        mSetFlagsRule.enableFlags(Flags.FLAG_FILTER_IRRELEVANT_INPUT_DEVICE_CHANGE);
+        spyOn(mDisplayContent);
+        doReturn(false).when(mDisplayContent).sendNewConfiguration();
+        final InputDevice deviceA = mock(InputDevice.class);
+        final InputDevice deviceB = mock(InputDevice.class);
+        doReturn("deviceA").when(deviceA).getDescriptor();
+        doReturn("deviceB").when(deviceB).getDescriptor();
+        final InputDevice[] devices1 = { deviceA };
+        final InputDevice[] devices2 = { deviceB, deviceA };
+        final Runnable verifySendNewConfiguration = () -> {
+            clearInvocations(mDisplayContent);
+            mWm.mInputManagerCallback.notifyConfigurationChanged();
+            verify(mDisplayContent).sendNewConfiguration();
+        };
+        doReturn(devices1).when(mWm.mInputManager).getInputDevices();
+        verifySendNewConfiguration.run();
+
+        doReturn(devices2).when(mWm.mInputManager).getInputDevices();
+        verifySendNewConfiguration.run();
+
+        doReturn(true).when(deviceB).isEnabled();
+        verifySendNewConfiguration.run();
+
+        doReturn(true).when(deviceA).isExternal();
+        verifySendNewConfiguration.run();
+
+        doReturn(1).when(deviceA).getSources();
+        verifySendNewConfiguration.run();
+
+        doReturn(1).when(deviceA).getAssociatedDisplayId();
+        verifySendNewConfiguration.run();
+
+        doReturn(1).when(deviceA).getKeyboardType();
+        verifySendNewConfiguration.run();
+
+        clearInvocations(mDisplayContent);
+        mWm.mInputManagerCallback.notifyConfigurationChanged();
+        verify(mDisplayContent, never()).sendNewConfiguration();
+    }
+
+    @Test
     public void testReportSystemGestureExclusionChanged_invalidWindow() {
         final Session session = mock(Session.class);
         final IWindow window = mock(IWindow.class);
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
index f56825f..42e31de 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
@@ -16,6 +16,7 @@
 
 package com.android.server.wm;
 
+import static android.Manifest.permission.CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS;
 import static android.app.ActivityManager.START_CANCELED;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
@@ -28,6 +29,8 @@
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
+import static android.content.pm.PackageManager.PERMISSION_DENIED;
+import static android.content.pm.PackageManager.PERMISSION_GRANTED;
 import static android.content.res.Configuration.SCREEN_HEIGHT_DP_UNDEFINED;
 import static android.content.res.Configuration.SCREEN_WIDTH_DP_UNDEFINED;
 import static android.view.InsetsSource.FLAG_FORCE_CONSUMING;
@@ -37,6 +40,7 @@
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.never;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.times;
@@ -61,6 +65,7 @@
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.atLeastOnce;
 import static org.mockito.Mockito.clearInvocations;
+import static org.mockito.quality.Strictness.LENIENT;
 
 import android.annotation.NonNull;
 import android.app.ActivityManager;
@@ -69,6 +74,7 @@
 import android.app.ActivityTaskManager.RootTaskInfo;
 import android.app.IRequestFinishCallback;
 import android.app.PictureInPictureParams;
+import android.content.Intent;
 import android.content.pm.ActivityInfo;
 import android.content.pm.ParceledListSlice;
 import android.content.res.Configuration;
@@ -87,6 +93,7 @@
 import android.window.ITaskFragmentOrganizer;
 import android.window.ITaskOrganizer;
 import android.window.IWindowContainerTransactionCallback;
+import android.window.RemoteTransition;
 import android.window.StartingWindowInfo;
 import android.window.StartingWindowRemovalInfo;
 import android.window.TaskAppearedInfo;
@@ -102,6 +109,7 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
+import org.mockito.MockitoSession;
 
 import java.util.ArrayList;
 import java.util.HashSet;
@@ -638,6 +646,66 @@
     }
 
     @Test
+    public void testStartActivityInTaskFragment_checkCallerPermission() {
+        final ActivityStartController activityStartController =
+                mWm.mAtmService.getActivityStartController();
+        spyOn(activityStartController);
+        final ArgumentCaptor<SafeActivityOptions> activityOptionsCaptor =
+                ArgumentCaptor.forClass(SafeActivityOptions.class);
+
+        final int uid = Binder.getCallingUid();
+        final Task rootTask = new TaskBuilder(mSupervisor).setCreateActivity(true)
+                .setWindowingMode(WINDOWING_MODE_FULLSCREEN).build();
+        final WindowContainerTransaction t = new WindowContainerTransaction();
+        final TaskFragmentOrganizer organizer =
+                createTaskFragmentOrganizer(t, true /* isSystemOrganizer */);
+        final IBinder token = new Binder();
+        final TaskFragment taskFragment = new TaskFragmentBuilder(mAtm)
+                .setParentTask(rootTask)
+                .setFragmentToken(token)
+                .setOrganizer(organizer)
+                .createActivityCount(1)
+                .build();
+        mWm.mAtmService.mWindowOrganizerController.mLaunchTaskFragments.put(token, taskFragment);
+        final ActivityRecord ownerActivity = taskFragment.getTopMostActivity();
+
+        // Start Activity in TaskFragment with remote transition.
+        final RemoteTransition transition = mock(RemoteTransition.class);
+        final ActivityOptions options = ActivityOptions.makeRemoteTransition(transition);
+        final Intent intent = new Intent();
+        t.startActivityInTaskFragment(token, ownerActivity.token, intent, options.toBundle());
+        mWm.mAtmService.mWindowOrganizerController.applyTaskFragmentTransactionLocked(
+                t, TaskFragmentOrganizer.TASK_FRAGMENT_TRANSIT_OPEN,
+                false /* shouldApplyIndependently */, null /* remoteTransition */);
+
+        // Get the ActivityOptions.
+        verify(activityStartController).startActivityInTaskFragment(
+                eq(taskFragment), eq(intent), activityOptionsCaptor.capture(),
+                eq(ownerActivity.token), eq(uid), anyInt(), any());
+        final SafeActivityOptions safeActivityOptions = activityOptionsCaptor.getValue();
+
+        final MockitoSession session =
+                mockitoSession().strictness(LENIENT).spyStatic(ActivityTaskManagerService.class)
+                        .startMocking();
+        try {
+            // Without the CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS permission, start activity with
+            // remote transition is not allowed.
+            doReturn(PERMISSION_DENIED).when(() -> ActivityTaskManagerService.checkPermission(
+                    eq(CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS), anyInt(), eq(uid)));
+            assertThrows(SecurityException.class,
+                    () -> safeActivityOptions.getOptions(mWm.mAtmService.mTaskSupervisor));
+
+            // With the CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS permission, start activity with
+            // remote transition is allowed.
+            doReturn(PERMISSION_GRANTED).when(() -> ActivityTaskManagerService.checkPermission(
+                    eq(CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS), anyInt(), eq(uid)));
+            safeActivityOptions.getOptions(mWm.mAtmService.mTaskSupervisor);
+        } finally {
+            session.finishMocking();
+        }
+    }
+
+    @Test
     public void testTaskFragmentChangeHidden_throwsWhenNotSystemOrganizer() {
         // Non-system organizers are not allow to update the hidden state.
         testTaskFragmentChangesWithoutSystemOrganizerThrowException(
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java
index 714eb4b..35328a0e 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java
@@ -23,6 +23,7 @@
 import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
 import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
 
+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.policy.WindowManagerPolicy.TRANSIT_EXIT;
 
@@ -157,7 +158,16 @@
         // Verify that the other token window is still around.
         assertEquals(1, token.getWindowsCount());
 
+        final TransitionController transitionController = token.mTransitionController;
+        spyOn(transitionController);
+        doReturn(true).when(transitionController).isPlayingTarget(token);
         window2.removeImmediately();
+        assertTrue(token.mIsExiting);
+        assertNotNull("Defer removal for playing transition", token.getParent());
+
+        doReturn(false).when(transitionController).isPlayingTarget(token);
+        token.handleCompleteDeferredRemoval();
+        assertFalse(token.mIsExiting);
         // Verify that the token is no-longer attached to its parent
         assertNull(token.getParent());
         // Verify that the token windows are no longer attached to it.
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java
index 1a42e80..19a6ddc 100644
--- a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java
@@ -504,6 +504,11 @@
             pw.println("\n##Sound Model Stats dump:\n");
             mSoundModelStatTracker.dump(pw);
         }
+
+        @Override
+        protected void onUnhandledException(int code, int flags, Exception e) {
+            Slog.wtf(TAG, "Unhandled exception code: " + code, e);
+        }
     }
 
     class SoundTriggerSessionStub extends ISoundTriggerSession.Stub {
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index ff966ae..fee4587 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -2741,7 +2741,7 @@
 
     /**
      * Returns a constant indicating the device phone type.  This
-     * indicates the type of radio used to transmit voice calls.
+     * indicates the type of radio used to transmit voice/data calls.
      *
      * @see #PHONE_TYPE_NONE
      * @see #PHONE_TYPE_GSM
@@ -2753,7 +2753,7 @@
      */
     @RequiresFeature(PackageManager.FEATURE_TELEPHONY)
     public int getPhoneType() {
-        if (!isVoiceCapable()) {
+        if (!isVoiceCapable() && !isDataCapable()) {
             return PHONE_TYPE_NONE;
         }
         return getCurrentPhoneType();
@@ -19180,15 +19180,19 @@
     public @interface EmergencyCallbackModeType {}
 
     /**
-     * The callback mode is due to emergency call.
+     * The emergency callback mode is due to emergency call.
      * @hide
      */
+    @FlaggedApi(Flags.FLAG_EMERGENCY_CALLBACK_MODE_NOTIFICATION)
+    @SystemApi
     public static final int EMERGENCY_CALLBACK_MODE_CALL = 1;
 
     /**
-     * The callback mode is due to emergency SMS.
+     * The emergency callback mode is due to emergency SMS.
      * @hide
      */
+    @FlaggedApi(Flags.FLAG_EMERGENCY_CALLBACK_MODE_NOTIFICATION)
+    @SystemApi
     public static final int EMERGENCY_CALLBACK_MODE_SMS = 2;
 
     /**
@@ -19209,45 +19213,64 @@
     public @interface EmergencyCallbackModeStopReason {}
 
     /**
-     * unknown reason.
+     * Indicates that emergency callback mode has been stopped for an unknown reason.
      * @hide
      */
+    @FlaggedApi(Flags.FLAG_EMERGENCY_CALLBACK_MODE_NOTIFICATION)
+    @SystemApi
     public static final int STOP_REASON_UNKNOWN = 0;
 
     /**
-     * The call back mode is exited due to a new normal call is originated.
+     * Indicates that emergency callback mode has been stopped because a new non-emergency call was
+     * initiated.
      * @hide
      */
+    @FlaggedApi(Flags.FLAG_EMERGENCY_CALLBACK_MODE_NOTIFICATION)
+    @SystemApi
     public static final int STOP_REASON_OUTGOING_NORMAL_CALL_INITIATED = 1;
 
     /**
-     * The call back mode is exited due to a new normal SMS is originated.
+     * Indicates that emergency callback mode has been stopped because a new non-emergency SMS was
+     * sent.
      * @hide
      */
+    @FlaggedApi(Flags.FLAG_EMERGENCY_CALLBACK_MODE_NOTIFICATION)
+    @SystemApi
     public static final int STOP_REASON_NORMAL_SMS_SENT = 2;
 
     /**
-     * The call back mode is exited due to a new emergency call is originated.
+     * Indicates that emergency callback mode has been stopped because a new outgoing emergency
+     * call was initiated.
      * @hide
      */
+    @FlaggedApi(Flags.FLAG_EMERGENCY_CALLBACK_MODE_NOTIFICATION)
+    @SystemApi
     public static final int STOP_REASON_OUTGOING_EMERGENCY_CALL_INITIATED = 3;
 
     /**
-     * The call back mode is exited due to a new emergency SMS is originated.
+     * Indicates that emergency callback mode has been stopped because a new emergency SMS was sent.
      * @hide
      */
+    @FlaggedApi(Flags.FLAG_EMERGENCY_CALLBACK_MODE_NOTIFICATION)
+    @SystemApi
     public static final int STOP_REASON_EMERGENCY_SMS_SENT = 4;
 
     /**
-     * The call back mode is exited due to timer expiry.
+     * Indicates that emergency callback mode has been stopped due to the emergency callback mode
+     * timer expiry.
      * @hide
      */
+    @FlaggedApi(Flags.FLAG_EMERGENCY_CALLBACK_MODE_NOTIFICATION)
+    @SystemApi
     public static final int STOP_REASON_TIMER_EXPIRED = 5;
 
     /**
-     * The call back mode is exited due to user action.
+     * Indicates that emergency callback mode has been stopped due to user ending the emergency
+     * mode by clicking the notification.
      * @hide
      */
+    @FlaggedApi(Flags.FLAG_EMERGENCY_CALLBACK_MODE_NOTIFICATION)
+    @SystemApi
     public static final int STOP_REASON_USER_ACTION = 6;
 
     /**
diff --git a/telephony/java/android/telephony/satellite/SatelliteManager.java b/telephony/java/android/telephony/satellite/SatelliteManager.java
index 49ca6f3..44de65a 100644
--- a/telephony/java/android/telephony/satellite/SatelliteManager.java
+++ b/telephony/java/android/telephony/satellite/SatelliteManager.java
@@ -1965,13 +1965,14 @@
     }
 
     /**
-     * Inform whether the device is aligned with the satellite for demo mode.
+     * Inform whether the device is aligned with the satellite in both real and demo mode.
      *
-     * Framework can send datagram to modem only when device is aligned with the satellite.
-     * This method helps framework to simulate the experience of sending datagram over satellite.
+     * In demo mode, framework will send datagram to modem only when device is aligned with
+     * the satellite. This method helps framework to simulate the experience of sending datagram
+     * over satellite.
      *
-     * @param isAligned {@true} Device is aligned with the satellite for demo mode
-     *                  {@false} Device is not aligned with the satellite for demo mode
+     * @param isAligned {code @true} Device is aligned with the satellite
+     *                  {code @false} Device is not aligned with the satellite
      *
      * @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/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 61f0146..231c8f5 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -2977,10 +2977,10 @@
     void requestTimeForNextSatelliteVisibility(in ResultReceiver receiver);
 
     /**
-     * Inform whether the device is aligned with the satellite within in margin for demo mode.
+     * Inform whether the device is aligned with the satellite in both real and demo mode.
      *
-     * @param isAligned {@true} Device is aligned with the satellite for demo mode
-     *                  {@false} Device is not aligned with the satellite for demo mode
+     * @param isAligned {@true} Device is aligned with the satellite.
+     *                  {@false} Device is not aligned with the satellite.
      */
     @JavaPassthrough(annotation="@android.annotation.RequiresPermission("
             + "android.Manifest.permission.SATELLITE_COMMUNICATION)")
diff --git a/tests/FlickerTests/ActivityEmbedding/Android.bp b/tests/FlickerTests/ActivityEmbedding/Android.bp
index c681ce9..529f84a 100644
--- a/tests/FlickerTests/ActivityEmbedding/Android.bp
+++ b/tests/FlickerTests/ActivityEmbedding/Android.bp
@@ -24,71 +24,6 @@
     default_applicable_licenses: ["frameworks_base_license"],
 }
 
-////////////////////////////////////////////////////////////////////////////////
-// Begin to cleanup after CL merges
-
-filegroup {
-    name: "FlickerTestsOtherCommon-src",
-    srcs: ["src/**/ActivityEmbeddingTestBase.kt"],
-}
-
-filegroup {
-    name: "FlickerTestsOtherOpen-src",
-    srcs: ["src/**/open/*"],
-}
-
-filegroup {
-    name: "FlickerTestsOtherRotation-src",
-    srcs: ["src/**/rotation/*"],
-}
-
-java_library {
-    name: "FlickerTestsOtherCommon",
-    defaults: ["FlickerTestsDefault"],
-    srcs: [":FlickerTestsOtherCommon-src"],
-    static_libs: ["FlickerTestsBase"],
-}
-
-java_defaults {
-    name: "FlickerTestsOtherDefaults",
-    defaults: ["FlickerTestsDefault"],
-    manifest: "AndroidManifest.xml",
-    package_name: "com.android.server.wm.flicker",
-    instrumentation_target_package: "com.android.server.wm.flicker",
-    test_config_template: "AndroidTestTemplate.xml",
-    static_libs: [
-        "FlickerTestsBase",
-        "FlickerTestsOtherCommon",
-    ],
-    data: ["trace_config/*"],
-}
-
-android_test {
-    name: "FlickerTestsOtherOpen",
-    defaults: ["FlickerTestsOtherDefaults"],
-    srcs: [":FlickerTestsOtherOpen-src"],
-}
-
-android_test {
-    name: "FlickerTestsOtherRotation",
-    defaults: ["FlickerTestsOtherDefaults"],
-    srcs: [":FlickerTestsOtherRotation-src"],
-}
-
-android_test {
-    name: "FlickerTestsOther",
-    defaults: ["FlickerTestsOtherDefaults"],
-    srcs: ["src/**/*"],
-    exclude_srcs: [
-        ":FlickerTestsOtherOpen-src",
-        ":FlickerTestsOtherRotation-src",
-        ":FlickerTestsOtherCommon-src",
-    ],
-}
-
-// End to cleanup after CL merges
-////////////////////////////////////////////////////////////////////////////////
-
 android_test {
     name: "FlickerTestsActivityEmbedding",
     defaults: ["FlickerTestsDefault"],
@@ -97,10 +32,7 @@
     instrumentation_target_package: "com.android.server.wm.flicker",
     test_config_template: "AndroidTestTemplate.xml",
     srcs: ["src/**/*"],
-    static_libs: [
-        "FlickerTestsBase",
-        "FlickerTestsOtherCommon",
-    ],
+    static_libs: ["FlickerTestsBase"],
     data: ["trace_config/*"],
 }
 
diff --git a/tests/FlickerTests/ActivityEmbedding/OWNERS b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/OWNERS
similarity index 100%
rename from tests/FlickerTests/ActivityEmbedding/OWNERS
rename to tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/OWNERS
diff --git a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/close/CloseSecondaryActivityInSplitTest.kt b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/close/CloseSecondaryActivityInSplitTest.kt
index 519b429..f44e282 100644
--- a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/close/CloseSecondaryActivityInSplitTest.kt
+++ b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/close/CloseSecondaryActivityInSplitTest.kt
@@ -38,7 +38,7 @@
  * Setup: Launch A|B in split with B being the secondary activity. Transitions: Finish B and expect
  * A to become fullscreen.
  *
- * To run this test: `atest FlickerTestsOther:CloseSecondaryActivityInSplitTest`
+ * To run this test: `atest FlickerTestsActivityEmbedding:CloseSecondaryActivityInSplitTest`
  */
 @RequiresDevice
 @RunWith(Parameterized::class)
diff --git a/tests/FlickerTests/ActivityEmbedding/OWNERS b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/close/OWNERS
similarity index 100%
copy from tests/FlickerTests/ActivityEmbedding/OWNERS
copy to tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/close/OWNERS
diff --git a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/layoutchange/HorizontalSplitChangeRatioTest.kt b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/layoutchange/HorizontalSplitChangeRatioTest.kt
index 4cd6d15b..7a76dd9 100644
--- a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/layoutchange/HorizontalSplitChangeRatioTest.kt
+++ b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/layoutchange/HorizontalSplitChangeRatioTest.kt
@@ -39,7 +39,7 @@
  * windows are equal in size. B is on the top and A is on the bottom. Transitions: Change the split
  * ratio to A:B=0.7:0.3, expect bounds change for both A and B.
  *
- * To run this test: `atest FlickerTestsOther:HorizontalSplitChangeRatioTest`
+ * To run this test: `atest FlickerTestsActivityEmbedding:HorizontalSplitChangeRatioTest`
  */
 @RequiresDevice
 @RunWith(Parameterized::class)
diff --git a/tests/FlickerTests/ActivityEmbedding/OWNERS b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/layoutchange/OWNERS
similarity index 100%
copy from tests/FlickerTests/ActivityEmbedding/OWNERS
copy to tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/layoutchange/OWNERS
diff --git a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/open/MainActivityStartsSecondaryWithAlwaysExpandTest.kt b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/open/MainActivityStartsSecondaryWithAlwaysExpandTest.kt
index 5df8b572..08b5f38 100644
--- a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/open/MainActivityStartsSecondaryWithAlwaysExpandTest.kt
+++ b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/open/MainActivityStartsSecondaryWithAlwaysExpandTest.kt
@@ -39,7 +39,7 @@
  * Setup: Launch A|B in split with B being the secondary activity. Transitions: A start C with
  * alwaysExpand=true, expect C to launch in fullscreen and cover split A|B.
  *
- * To run this test: `atest FlickerTestsOther:MainActivityStartsSecondaryWithAlwaysExpandTest`
+ * To run this test: `atest FlickerTestsActivityEmbedding:MainActivityStartsSecondaryWithAlwaysExpandTest`
  */
 @RequiresDevice
 @RunWith(Parameterized::class)
diff --git a/tests/FlickerTests/ActivityEmbedding/OWNERS b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/open/OWNERS
similarity index 100%
copy from tests/FlickerTests/ActivityEmbedding/OWNERS
copy to tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/open/OWNERS
diff --git a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/open/OpenActivityEmbeddingPlaceholderSplitTest.kt b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/open/OpenActivityEmbeddingPlaceholderSplitTest.kt
index 5009c7c..1f002a0 100644
--- a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/open/OpenActivityEmbeddingPlaceholderSplitTest.kt
+++ b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/open/OpenActivityEmbeddingPlaceholderSplitTest.kt
@@ -34,7 +34,7 @@
  * Test opening an activity that will launch another activity as ActivityEmbedding placeholder in
  * split.
  *
- * To run this test: `atest FlickerTestsOther:OpenActivityEmbeddingPlaceholderSplitTest`
+ * To run this test: `atest FlickerTestsActivityEmbedding:OpenActivityEmbeddingPlaceholderSplitTest`
  */
 @RequiresDevice
 @RunWith(Parameterized::class)
diff --git a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/open/OpenActivityEmbeddingSecondaryToSplitTest.kt b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/open/OpenActivityEmbeddingSecondaryToSplitTest.kt
index 6327d92..b78c3ec 100644
--- a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/open/OpenActivityEmbeddingSecondaryToSplitTest.kt
+++ b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/open/OpenActivityEmbeddingSecondaryToSplitTest.kt
@@ -34,7 +34,7 @@
 /**
  * Test opening a secondary activity that will split with the main activity.
  *
- * To run this test: `atest FlickerTestsOther:OpenActivityEmbeddingSecondaryToSplitTest`
+ * To run this test: `atest FlickerTestsActivityEmbedding:OpenActivityEmbeddingSecondaryToSplitTest`
  */
 @RequiresDevice
 @RunWith(Parameterized::class)
diff --git a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/open/OpenThirdActivityOverSplitTest.kt b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/open/OpenThirdActivityOverSplitTest.kt
index 78004cc..10167d71 100644
--- a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/open/OpenThirdActivityOverSplitTest.kt
+++ b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/open/OpenThirdActivityOverSplitTest.kt
@@ -39,7 +39,7 @@
  *
  * Transitions: Let B start C, expect C to cover B and end up in split A|C.
  *
- * To run this test: `atest FlickerTestsOther:OpenThirdActivityOverSplitTest`
+ * To run this test: `atest FlickerTestsActivityEmbedding:OpenThirdActivityOverSplitTest`
  */
 @RequiresDevice
 @RunWith(Parameterized::class)
diff --git a/tests/FlickerTests/ActivityEmbedding/OWNERS b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/pip/OWNERS
similarity index 100%
copy from tests/FlickerTests/ActivityEmbedding/OWNERS
copy to tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/pip/OWNERS
diff --git a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/pip/SecondaryActivityEnterPipTest.kt b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/pip/SecondaryActivityEnterPipTest.kt
index eed9225..a0b910b 100644
--- a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/pip/SecondaryActivityEnterPipTest.kt
+++ b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/pip/SecondaryActivityEnterPipTest.kt
@@ -41,7 +41,7 @@
  * Setup: Start from a split A|B. Transition: B enters PIP, observe the window first goes fullscreen
  * then shrink to the bottom right corner on screen.
  *
- * To run this test: `atest FlickerTestsOther:SecondaryActivityEnterPipTest`
+ * To run this test: `atest FlickerTestsActivityEmbedding:SecondaryActivityEnterPipTest`
  */
 @RequiresDevice
 @RunWith(Parameterized::class)
diff --git a/tests/FlickerTests/ActivityEmbedding/OWNERS b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/rotation/OWNERS
similarity index 100%
copy from tests/FlickerTests/ActivityEmbedding/OWNERS
copy to tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/rotation/OWNERS
diff --git a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/rotation/RotateSplitNoChangeTest.kt b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/rotation/RotateSplitNoChangeTest.kt
index f5e6c78..ea13f5f 100644
--- a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/rotation/RotateSplitNoChangeTest.kt
+++ b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/rotation/RotateSplitNoChangeTest.kt
@@ -36,7 +36,7 @@
  * Setup: Launch A|B in split with B being the secondary activity. Transitions: Rotate display, and
  * expect A and B to split evenly in new rotation.
  *
- * To run this test: `atest FlickerTestsOther:RotateSplitNoChangeTest`
+ * To run this test: `atest FlickerTestsActivityEmbedding:RotateSplitNoChangeTest`
  */
 @RequiresDevice
 @RunWith(Parameterized::class)
diff --git a/tests/FlickerTests/ActivityEmbedding/OWNERS b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/rtl/OWNERS
similarity index 100%
copy from tests/FlickerTests/ActivityEmbedding/OWNERS
copy to tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/rtl/OWNERS
diff --git a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/rtl/RTLStartSecondaryWithPlaceholderTest.kt b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/rtl/RTLStartSecondaryWithPlaceholderTest.kt
index 65a23e8..2a177d5 100644
--- a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/rtl/RTLStartSecondaryWithPlaceholderTest.kt
+++ b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/rtl/RTLStartSecondaryWithPlaceholderTest.kt
@@ -37,7 +37,7 @@
  * PlaceholderPrimary, which is configured to launch with PlaceholderSecondary in RTL. Expect split
  * PlaceholderSecondary|PlaceholderPrimary covering split B|A.
  *
- * To run this test: `atest FlickerTestsOther:RTLStartSecondaryWithPlaceholderTest`
+ * To run this test: `atest FlickerTestsActivityEmbedding:RTLStartSecondaryWithPlaceholderTest`
  */
 @RequiresDevice
 @RunWith(Parameterized::class)
diff --git a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/splitscreen/EnterSystemSplitTest.kt b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/splitscreen/EnterSystemSplitTest.kt
index c3e1a1f..0ca8f37 100644
--- a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/splitscreen/EnterSystemSplitTest.kt
+++ b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/splitscreen/EnterSystemSplitTest.kt
@@ -47,7 +47,7 @@
  * Setup: Launch A|B in split and secondaryApp, return to home. Transitions: Let AE Split A|B enter
  * splitscreen with secondaryApp. Resulting in A|B|secondaryApp.
  *
- * To run this test: `atest FlickerTestsOther:EnterSystemSplitTest`
+ * To run this test: `atest FlickerTestsActivityEmbedding:EnterSystemSplitTest`
  */
 @RequiresDevice
 @RunWith(Parameterized::class)
diff --git a/tests/FlickerTests/ActivityEmbedding/OWNERS b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/splitscreen/OWNERS
similarity index 100%
copy from tests/FlickerTests/ActivityEmbedding/OWNERS
copy to tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/splitscreen/OWNERS
diff --git a/tests/FlickerTests/Android.bp b/tests/FlickerTests/Android.bp
index 27e9ffa..1e997b3 100644
--- a/tests/FlickerTests/Android.bp
+++ b/tests/FlickerTests/Android.bp
@@ -47,7 +47,6 @@
 
 java_library {
     name: "wm-flicker-common-assertions",
-    platform_apis: true,
     optimize: {
         enabled: false,
     },
diff --git a/tests/FlickerTests/AppClose/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt b/tests/FlickerTests/AppClose/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt
index e19e1ce..56b718a 100644
--- a/tests/FlickerTests/AppClose/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt
+++ b/tests/FlickerTests/AppClose/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt
@@ -31,7 +31,7 @@
 /**
  * Test app closes by pressing back button
  *
- * To run this test: `atest FlickerTests:CloseAppBackButtonTest`
+ * To run this test: `atest FlickerTestsAppClose:CloseAppBackButtonTest`
  *
  * Actions:
  * ```
diff --git a/tests/FlickerTests/AppClose/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt b/tests/FlickerTests/AppClose/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt
index 47ed642..5deacaf 100644
--- a/tests/FlickerTests/AppClose/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt
+++ b/tests/FlickerTests/AppClose/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt
@@ -31,7 +31,7 @@
 /**
  * Test app closes by pressing home button
  *
- * To run this test: `atest FlickerTests:CloseAppHomeButtonTest`
+ * To run this test: `atest FlickerTestsAppClose:CloseAppHomeButtonTest`
  *
  * Actions:
  * ```
diff --git a/tests/FlickerTests/AppLaunch/Android.bp b/tests/FlickerTests/AppLaunch/Android.bp
index b61739f..17d0f96 100644
--- a/tests/FlickerTests/AppLaunch/Android.bp
+++ b/tests/FlickerTests/AppLaunch/Android.bp
@@ -24,69 +24,13 @@
     default_applicable_licenses: ["frameworks_base_license"],
 }
 
-////////////////////////////////////////////////////////////////////////////////
-// Begin to cleanup after CL merges
-
-filegroup {
-    name: "FlickerTestsAppLaunchCommon-src",
-    srcs: ["src/**/common/*"],
-}
-
-filegroup {
-    name: "FlickerTestsAppLaunch1-src",
-    srcs: ["src/**/OpenAppFrom*"],
-}
-
-java_library {
-    name: "FlickerTestsAppLaunchCommon",
-    defaults: ["FlickerTestsDefault"],
-    srcs: [":FlickerTestsAppLaunchCommon-src"],
-    static_libs: ["FlickerTestsBase"],
-}
-
-android_test {
-    name: "FlickerTestsAppLaunch1",
-    defaults: ["FlickerTestsDefault"],
-    manifest: "AndroidManifest.xml",
-    test_config_template: "AndroidTestTemplate.xml",
-    srcs: [":FlickerTestsAppLaunch1-src"],
-    static_libs: [
-        "FlickerTestsBase",
-        "FlickerTestsAppLaunchCommon",
-    ],
-    data: ["trace_config/*"],
-}
-
-android_test {
-    name: "FlickerTestsAppLaunch2",
-    defaults: ["FlickerTestsDefault"],
-    manifest: "AndroidManifest.xml",
-    test_config_template: "AndroidTestTemplate.xml",
-    srcs: ["src/**/*"],
-    exclude_srcs: [
-        ":FlickerTestsAppLaunchCommon-src",
-        ":FlickerTestsAppLaunch1-src",
-    ],
-    static_libs: [
-        "FlickerTestsBase",
-        "FlickerTestsAppLaunchCommon",
-    ],
-    data: ["trace_config/*"],
-}
-
-// End to cleanup after CL merges
-////////////////////////////////////////////////////////////////////////////////
-
 android_test {
     name: "FlickerTestsAppLaunch",
     defaults: ["FlickerTestsDefault"],
     manifest: "AndroidManifest.xml",
     test_config_template: "AndroidTestTemplate.xml",
     srcs: ["src/**/*"],
-    static_libs: [
-        "FlickerTestsBase",
-        "FlickerTestsAppLaunchCommon",
-    ],
+    static_libs: ["FlickerTestsBase"],
     data: ["trace_config/*"],
 }
 
diff --git a/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/ActivityTransitionTest.kt b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/ActivityTransitionTest.kt
index ffa90a3..01cdbb8 100644
--- a/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/ActivityTransitionTest.kt
+++ b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/ActivityTransitionTest.kt
@@ -35,7 +35,7 @@
 /**
  * Test the back and forward transition between 2 activities.
  *
- * To run this test: `atest FlickerTests:ActivitiesTransitionTest`
+ * To run this test: `atest FlickerTestsAppLaunch:ActivitiesTransitionTest`
  *
  * Actions:
  * ```
diff --git a/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromIconColdTest.kt b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromIconColdTest.kt
index 8c285bd..3d9321c 100644
--- a/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromIconColdTest.kt
+++ b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromIconColdTest.kt
@@ -30,7 +30,7 @@
 /**
  * Test cold launching an app from launcher
  *
- * To run this test: `atest FlickerTests:OpenAppColdFromIcon`
+ * To run this test: `atest FlickerTestsAppLaunch:OpenAppColdFromIcon`
  *
  * Actions:
  * ```
diff --git a/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromIntentColdAfterCameraTest.kt b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromIntentColdAfterCameraTest.kt
index 57da05f..9207530 100644
--- a/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromIntentColdAfterCameraTest.kt
+++ b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromIntentColdAfterCameraTest.kt
@@ -30,7 +30,7 @@
 /**
  * Test launching an app after cold opening camera
  *
- * To run this test: `atest FlickerTests:OpenAppAfterCameraTest`
+ * To run this test: `atest FlickerTestsAppLaunch:OpenAppAfterCameraTest`
  *
  * Notes: Some default assertions are inherited [OpenAppTransition]
  */
diff --git a/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromIntentColdTest.kt b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromIntentColdTest.kt
index 267f282..cbe7c32 100644
--- a/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromIntentColdTest.kt
+++ b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromIntentColdTest.kt
@@ -35,7 +35,7 @@
 /**
  * Test cold launching an app from launcher
  *
- * To run this test: `atest FlickerTests:OpenAppColdTest`
+ * To run this test: `atest FlickerTestsAppLaunch:OpenAppColdTest`
  *
  * Actions:
  * ```
diff --git a/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromIntentWarmTest.kt b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromIntentWarmTest.kt
index 83065de..b2941e7 100644
--- a/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromIntentWarmTest.kt
+++ b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromIntentWarmTest.kt
@@ -34,7 +34,7 @@
 /**
  * Test warm launching an app from launcher
  *
- * To run this test: `atest FlickerTests:OpenAppWarmTest`
+ * To run this test: `atest FlickerTestsAppLaunch:OpenAppWarmTest`
  *
  * Actions:
  * ```
diff --git a/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromLockscreenViaIntentTest.kt b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromLockscreenViaIntentTest.kt
index 6e6a327..4048e0c 100644
--- a/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromLockscreenViaIntentTest.kt
+++ b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromLockscreenViaIntentTest.kt
@@ -41,7 +41,7 @@
  *
  * This test assumes the device doesn't have AOD enabled
  *
- * To run this test: `atest FlickerTests:OpenAppNonResizeableTest`
+ * To run this test: `atest FlickerTestsAppLaunch:OpenAppNonResizeableTest`
  *
  * Actions:
  * ```
diff --git a/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt
index 6d3eaeb..064c76f 100644
--- a/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt
+++ b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt
@@ -35,7 +35,7 @@
 /**
  * Test launching an app from the recents app view (the overview)
  *
- * To run this test: `atest FlickerTests:OpenAppFromOverviewTest`
+ * To run this test: `atest FlickerTestsAppLaunch:OpenAppFromOverviewTest`
  *
  * Actions:
  * ```
diff --git a/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenCameraFromHomeOnDoubleClickPowerButtonTest.kt b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenCameraFromHomeOnDoubleClickPowerButtonTest.kt
index bec02d0..41423fd 100644
--- a/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenCameraFromHomeOnDoubleClickPowerButtonTest.kt
+++ b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenCameraFromHomeOnDoubleClickPowerButtonTest.kt
@@ -41,7 +41,7 @@
 /**
  * Test cold launching camera from launcher by double pressing power button
  *
- * To run this test: `atest FlickerTests:OpenCameraOnDoubleClickPowerButton`
+ * To run this test: `atest FlickerTestsAppLaunch:OpenCameraOnDoubleClickPowerButton`
  *
  * Actions:
  * ```
diff --git a/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenTransferSplashscreenAppFromLauncherTransition.kt b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenTransferSplashscreenAppFromLauncherTransition.kt
index e0aef8d..9d7a9c6 100644
--- a/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenTransferSplashscreenAppFromLauncherTransition.kt
+++ b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenTransferSplashscreenAppFromLauncherTransition.kt
@@ -34,7 +34,7 @@
 /**
  * Test cold launching an app from launcher
  *
- * To run this test: `atest FlickerTests:OpenTransferSplashscreenAppFromLauncherTransition`
+ * To run this test: `atest FlickerTestsAppLaunch:OpenTransferSplashscreenAppFromLauncherTransition`
  *
  * Actions:
  * ```
diff --git a/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OverrideTaskTransitionTest.kt b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OverrideTaskTransitionTest.kt
index f114499..7e2d472 100644
--- a/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OverrideTaskTransitionTest.kt
+++ b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OverrideTaskTransitionTest.kt
@@ -42,7 +42,7 @@
 /**
  * Test the [android.app.ActivityOptions.makeCustomTaskAnimation].
  *
- * To run this test: `atest FlickerTests:OverrideTaskTransitionTest`
+ * To run this test: `atest FlickerTestsAppLaunch:OverrideTaskTransitionTest`
  *
  * Actions:
  * ```
diff --git a/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/TaskTransitionTest.kt b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/TaskTransitionTest.kt
index a71599d..95e8126 100644
--- a/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/TaskTransitionTest.kt
+++ b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/TaskTransitionTest.kt
@@ -49,7 +49,7 @@
 /**
  * Test the back and forward transition between 2 activities.
  *
- * To run this test: `atest FlickerTests:TaskTransitionTest`
+ * To run this test: `atest FlickerTestsAppLaunch:TaskTransitionTest`
  *
  * Actions:
  * ```
diff --git a/tests/FlickerTests/IME/Android.bp b/tests/FlickerTests/IME/Android.bp
index f80e6b4..cba3d09 100644
--- a/tests/FlickerTests/IME/Android.bp
+++ b/tests/FlickerTests/IME/Android.bp
@@ -24,27 +24,6 @@
     default_applicable_licenses: ["frameworks_base_license"],
 }
 
-////////////////////////////////////////////////////////////////////////////////
-// Begin to cleanup after CL merges
-
-filegroup {
-    name: "FlickerTestsImeCommon-src",
-    srcs: ["src/**/common/*"],
-}
-
-filegroup {
-    name: "FlickerTestsIme1-src",
-    srcs: ["src/**/Close*"],
-}
-
-filegroup {
-    name: "FlickerTestsIme2-src",
-    srcs: ["src/**/ShowImeOnAppStart*"],
-}
-
-// End to cleanup after CL merges
-////////////////////////////////////////////////////////////////////////////////
-
 android_test {
     name: "FlickerTestsIme",
     defaults: ["FlickerTestsDefault"],
@@ -60,67 +39,6 @@
 }
 
 ////////////////////////////////////////////////////////////////////////////////
-// Begin to cleanup after CL merges
-
-java_library {
-    name: "FlickerTestsImeCommon",
-    defaults: ["FlickerTestsDefault"],
-    srcs: [":FlickerTestsImeCommon-src"],
-    static_libs: ["FlickerTestsBase"],
-}
-
-android_test {
-    name: "FlickerTestsIme1",
-    defaults: ["FlickerTestsDefault"],
-    manifest: "AndroidManifest.xml",
-    test_config_template: "AndroidTestTemplate.xml",
-    test_suites: [
-        "device-tests",
-        "device-platinum-tests",
-    ],
-    srcs: [":FlickerTestsIme1-src"],
-    static_libs: [
-        "FlickerTestsBase",
-        "FlickerTestsImeCommon",
-    ],
-    data: ["trace_config/*"],
-}
-
-android_test {
-    name: "FlickerTestsIme2",
-    defaults: ["FlickerTestsDefault"],
-    manifest: "AndroidManifest.xml",
-    test_config_template: "AndroidTestTemplate.xml",
-    srcs: [":FlickerTestsIme2-src"],
-    static_libs: [
-        "FlickerTestsBase",
-        "FlickerTestsImeCommon",
-    ],
-    data: ["trace_config/*"],
-}
-
-android_test {
-    name: "FlickerTestsIme3",
-    defaults: ["FlickerTestsDefault"],
-    manifest: "AndroidManifest.xml",
-    test_config_template: "AndroidTestTemplate.xml",
-    srcs: ["src/**/*"],
-    exclude_srcs: [
-        ":FlickerTestsIme1-src",
-        ":FlickerTestsIme2-src",
-        ":FlickerTestsImeCommon-src",
-    ],
-    static_libs: [
-        "FlickerTestsBase",
-        "FlickerTestsImeCommon",
-    ],
-    data: ["trace_config/*"],
-}
-
-// End to cleanup after CL merges
-////////////////////////////////////////////////////////////////////////////////
-
-////////////////////////////////////////////////////////////////////////////////
 // Begin breakdowns for FlickerTestsIme module
 
 test_module_config {
diff --git a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeOnDismissPopupDialogTest.kt b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeOnDismissPopupDialogTest.kt
index 2b6ddcb..48ca36f 100644
--- a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeOnDismissPopupDialogTest.kt
+++ b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeOnDismissPopupDialogTest.kt
@@ -33,7 +33,7 @@
 import org.junit.runners.Parameterized
 
 /**
- * To run this test: `atest FlickerTestsIme1:CloseImeOnDismissPopupDialogTest`
+ * To run this test: `atest FlickerTestsIme:CloseImeOnDismissPopupDialogTest`
  */
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
diff --git a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeOnGoHomeTest.kt b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeOnGoHomeTest.kt
index 0344197..e3f3aca 100644
--- a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeOnGoHomeTest.kt
+++ b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeOnGoHomeTest.kt
@@ -34,7 +34,7 @@
 
 /**
  * Test IME window closing to home transitions.
- * To run this test: `atest FlickerTestsIme1:CloseImeOnGoHomeTest`
+ * To run this test: `atest FlickerTestsIme:CloseImeOnGoHomeTest`
  */
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
diff --git a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeShownOnAppStartOnGoHomeTest.kt b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeShownOnAppStartOnGoHomeTest.kt
index fde1373..3509e5b 100644
--- a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeShownOnAppStartOnGoHomeTest.kt
+++ b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeShownOnAppStartOnGoHomeTest.kt
@@ -42,7 +42,7 @@
  *
  * More details on b/190352379
  *
- * To run this test: `atest FlickerTestsIme1:CloseImeShownOnAppStartOnGoHomeTest`
+ * To run this test: `atest FlickerTestsIme:CloseImeShownOnAppStartOnGoHomeTest`
  */
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
diff --git a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeShownOnAppStartToAppOnPressBackTest.kt b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeShownOnAppStartToAppOnPressBackTest.kt
index ed6e8df..53d7a3f 100644
--- a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeShownOnAppStartToAppOnPressBackTest.kt
+++ b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeShownOnAppStartToAppOnPressBackTest.kt
@@ -43,7 +43,7 @@
  *
  * More details on b/190352379
  *
- * To run this test: `atest FlickerTestsIme1:CloseImeShownOnAppStartToAppOnPressBackTest`
+ * To run this test: `atest FlickerTestsIme:CloseImeShownOnAppStartToAppOnPressBackTest`
  */
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
diff --git a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeToAppOnPressBackTest.kt b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeToAppOnPressBackTest.kt
index 522c68b..4bc2705 100644
--- a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeToAppOnPressBackTest.kt
+++ b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeToAppOnPressBackTest.kt
@@ -35,7 +35,7 @@
 
 /**
  * Test IME window closing back to app window transitions.
- * To run this test: `atest FlickerTestsIme1:CloseImeToAppOnPressBackTest`
+ * To run this test: `atest FlickerTestsIme:CloseImeToAppOnPressBackTest`
  */
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
diff --git a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeToHomeOnFinishActivityTest.kt b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeToHomeOnFinishActivityTest.kt
index 05771e8..6117bb0 100644
--- a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeToHomeOnFinishActivityTest.kt
+++ b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeToHomeOnFinishActivityTest.kt
@@ -40,7 +40,7 @@
  * Unlike {@link OpenImeWindowTest} testing IME window opening transitions, this test also verify
  * there is no flickering when back to the simple activity without requesting IME to show.
  *
- * To run this test: `atest FlickerTestsIme1:CloseImeToHomeOnFinishActivityTest`
+ * To run this test: `atest FlickerTestsIme:CloseImeToHomeOnFinishActivityTest`
  */
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
diff --git a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/OpenImeWindowToFixedPortraitAppTest.kt b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/OpenImeWindowToFixedPortraitAppTest.kt
index 336fe6f..9b8d86d 100644
--- a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/OpenImeWindowToFixedPortraitAppTest.kt
+++ b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/OpenImeWindowToFixedPortraitAppTest.kt
@@ -37,7 +37,7 @@
 
 /**
  * Test IME window shown on the app with fixing portrait orientation.
- * To run this test: `atest FlickerTestsIme2:OpenImeWindowToFixedPortraitAppTest`
+ * To run this test: `atest FlickerTestsIme:OpenImeWindowToFixedPortraitAppTest`
  */
 @RequiresDevice
 @RunWith(Parameterized::class)
diff --git a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromOverviewTest.kt b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromOverviewTest.kt
index 34a7085..f806fae 100644
--- a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromOverviewTest.kt
+++ b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromOverviewTest.kt
@@ -34,7 +34,7 @@
 
 /**
  * Test IME window opening transitions.
- * To run this test: `atest FlickerTestsIme2:ShowImeOnAppStartWhenLaunchingAppFromOverviewTest`
+ * To run this test: `atest FlickerTestsIme:ShowImeOnAppStartWhenLaunchingAppFromOverviewTest`
  */
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
diff --git a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromQuickSwitchTest.kt b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromQuickSwitchTest.kt
index 7c72c31..cc19f62 100644
--- a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromQuickSwitchTest.kt
+++ b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromQuickSwitchTest.kt
@@ -36,7 +36,7 @@
 
 /**
  * Test IME windows switching with 2-Buttons or gestural navigation.
- * To run this test: `atest FlickerTestsIme2:ShowImeOnAppStartWhenLaunchingAppFromQuickSwitchTest`
+ * To run this test: `atest FlickerTestsIme:ShowImeOnAppStartWhenLaunchingAppFromQuickSwitchTest`
  */
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
diff --git a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppTest.kt b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppTest.kt
index fe5320c..4a4d372 100644
--- a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppTest.kt
+++ b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppTest.kt
@@ -36,7 +36,7 @@
 /**
  * Launch an app that automatically displays the IME
  *
- * To run this test: `atest FlickerTestsIme2:ShowImeOnAppStartWhenLaunchingAppTest`
+ * To run this test: `atest FlickerTestsIme:ShowImeOnAppStartWhenLaunchingAppTest`
  *
  * Actions:
  * ```
diff --git a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnUnlockScreenTest.kt b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnUnlockScreenTest.kt
index 82e53c8..d47e7ad 100644
--- a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnUnlockScreenTest.kt
+++ b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnUnlockScreenTest.kt
@@ -36,7 +36,7 @@
 
 /**
  * Test IME window closing on lock and opening on screen unlock.
- * To run this test: `atest FlickerTestsIme2:ShowImeOnUnlockScreenTest`
+ * To run this test: `atest FlickerTestsIme:ShowImeOnUnlockScreenTest`
  */
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
diff --git a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeWhenFocusingOnInputFieldTest.kt b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeWhenFocusingOnInputFieldTest.kt
index 9eaf998..47bf324 100644
--- a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeWhenFocusingOnInputFieldTest.kt
+++ b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeWhenFocusingOnInputFieldTest.kt
@@ -33,7 +33,7 @@
 
 /**
  * Test IME window opening transitions.
- * To run this test: `atest FlickerTestsIme2:ShowImeWhenFocusingOnInputFieldTest`
+ * To run this test: `atest FlickerTestsIme:ShowImeWhenFocusingOnInputFieldTest`
  */
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
diff --git a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeWhileDismissingThemedPopupDialogTest.kt b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeWhileDismissingThemedPopupDialogTest.kt
index 7186a2c..e3118b4 100644
--- a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeWhileDismissingThemedPopupDialogTest.kt
+++ b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeWhileDismissingThemedPopupDialogTest.kt
@@ -41,7 +41,7 @@
 
 /**
  * Test IME snapshot mechanism won't apply when transitioning from non-IME focused dialog activity.
- * To run this test: `atest FlickerTestsIme2:ShowImeWhileDismissingThemedPopupDialogTest`
+ * To run this test: `atest FlickerTestsIme:ShowImeWhileDismissingThemedPopupDialogTest`
  */
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
diff --git a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeWhileEnteringOverviewTest.kt b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeWhileEnteringOverviewTest.kt
index eb63e49..064c07e 100644
--- a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeWhileEnteringOverviewTest.kt
+++ b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeWhileEnteringOverviewTest.kt
@@ -39,7 +39,7 @@
 
 /**
  * Test IME window layer will be associated with the app task when going to the overview screen.
- * To run this test: `atest FlickerTestsIme2:ShowImeWhileEnteringOverviewTest`
+ * To run this test: `atest FlickerTestsIme:ShowImeWhileEnteringOverviewTest`
  */
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
diff --git a/tests/FlickerTests/QuickSwitch/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTest.kt b/tests/FlickerTests/QuickSwitch/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTest.kt
index 9bb62e1..1a32f20 100644
--- a/tests/FlickerTests/QuickSwitch/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTest.kt
+++ b/tests/FlickerTests/QuickSwitch/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTest.kt
@@ -38,7 +38,7 @@
 /**
  * Test quick switching back to previous app from last opened app
  *
- * To run this test: `atest FlickerTests:QuickSwitchBetweenTwoAppsBackTest`
+ * To run this test: `atest FlickerTestsQuickswitch:QuickSwitchBetweenTwoAppsBackTest`
  *
  * Actions:
  * ```
diff --git a/tests/FlickerTests/QuickSwitch/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTest.kt b/tests/FlickerTests/QuickSwitch/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTest.kt
index 491b994..d82dddd 100644
--- a/tests/FlickerTests/QuickSwitch/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTest.kt
+++ b/tests/FlickerTests/QuickSwitch/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTest.kt
@@ -37,7 +37,7 @@
 /**
  * Test quick switching back to previous app from last opened app
  *
- * To run this test: `atest FlickerTests:QuickSwitchBetweenTwoAppsForwardTest`
+ * To run this test: `atest FlickerTestsQuickswitch:QuickSwitchBetweenTwoAppsForwardTest`
  *
  * Actions:
  * ```
diff --git a/tests/FlickerTests/QuickSwitch/src/com/android/server/wm/flicker/quickswitch/QuickSwitchFromLauncherTest.kt b/tests/FlickerTests/QuickSwitch/src/com/android/server/wm/flicker/quickswitch/QuickSwitchFromLauncherTest.kt
index de54c95..ab36628 100644
--- a/tests/FlickerTests/QuickSwitch/src/com/android/server/wm/flicker/quickswitch/QuickSwitchFromLauncherTest.kt
+++ b/tests/FlickerTests/QuickSwitch/src/com/android/server/wm/flicker/quickswitch/QuickSwitchFromLauncherTest.kt
@@ -38,7 +38,7 @@
 /**
  * Test quick switching to last opened app from launcher
  *
- * To run this test: `atest FlickerTests:QuickSwitchFromLauncherTest`
+ * To run this test: `atest FlickerTestsQuickswitch:QuickSwitchFromLauncherTest`
  *
  * Actions:
  * ```
diff --git a/tests/FlickerTests/Rotation/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt b/tests/FlickerTests/Rotation/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt
index 05ab364..49e2553 100644
--- a/tests/FlickerTests/Rotation/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt
+++ b/tests/FlickerTests/Rotation/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt
@@ -48,7 +48,7 @@
  *     Stop tracing
  * ```
  *
- * To run this test: `atest FlickerTests:ChangeAppRotationTest`
+ * To run this test: `atest FlickerTestsRotation:ChangeAppRotationTest`
  *
  * To run only the presubmit assertions add: `--
  *
diff --git a/tests/FlickerTests/Rotation/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt b/tests/FlickerTests/Rotation/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt
index a413628..d7f91e0 100644
--- a/tests/FlickerTests/Rotation/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt
+++ b/tests/FlickerTests/Rotation/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt
@@ -55,7 +55,7 @@
  *     Stop tracing
  * ```
  *
- * To run this test: `atest FlickerTests:SeamlessAppRotationTest`
+ * To run this test: `atest FlickerTestsRotation:SeamlessAppRotationTest`
  *
  * To run only the presubmit assertions add: `--
  *
diff --git a/tests/FlickerTests/test-apps/app-helpers/Android.bp b/tests/FlickerTests/test-apps/app-helpers/Android.bp
index fc4d71c..e8bb64a 100644
--- a/tests/FlickerTests/test-apps/app-helpers/Android.bp
+++ b/tests/FlickerTests/test-apps/app-helpers/Android.bp
@@ -25,7 +25,6 @@
 
 java_library {
     name: "wm-flicker-common-app-helpers",
-    platform_apis: true,
     optimize: {
         enabled: false,
     },
diff --git a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/LetterboxAppHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/LetterboxAppHelper.kt
index 634b6ee..8d27c1d 100644
--- a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/LetterboxAppHelper.kt
+++ b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/LetterboxAppHelper.kt
@@ -33,9 +33,9 @@
 @JvmOverloads
 constructor(
     instr: Instrumentation,
-    launcherName: String = ActivityOptions.NonResizeablePortraitActivity.LABEL,
+    launcherName: String = ActivityOptions.NonResizeableFixedAspectRatioPortraitActivity.LABEL,
     component: ComponentNameMatcher =
-        ActivityOptions.NonResizeablePortraitActivity.COMPONENT.toFlickerComponent()
+        ActivityOptions.NonResizeableFixedAspectRatioPortraitActivity.COMPONENT.toFlickerComponent()
 ) : StandardAppHelper(instr, launcherName, component) {
 
     private val gestureHelper: GestureHelper = GestureHelper(instrumentation)
diff --git a/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml b/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml
index f891606..f2e3425 100644
--- a/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml
+++ b/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml
@@ -115,6 +115,19 @@
                 <category android:name="android.intent.category.LAUNCHER"/>
             </intent-filter>
         </activity>
+        <activity android:name=".NonResizeableFixedAspectRatioPortraitActivity"
+            android:theme="@style/CutoutNever"
+            android:resizeableActivity="false"
+            android:screenOrientation="portrait"
+            android:minAspectRatio="1.77"
+            android:taskAffinity="com.android.server.wm.flicker.testapp.NonResizeableFixedAspectRatioPortraitActivity"
+            android:label="NonResizeableFixedAspectRatioPortraitActivity"
+            android:exported="true">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN"/>
+                <category android:name="android.intent.category.LAUNCHER"/>
+            </intent-filter>
+        </activity>
         <activity android:name=".StartMediaProjectionActivity"
             android:theme="@style/CutoutNever"
             android:resizeableActivity="false"
@@ -143,6 +156,7 @@
         <activity android:name=".LaunchTransparentActivity"
                   android:resizeableActivity="false"
                   android:screenOrientation="portrait"
+                  android:minAspectRatio="1.77"
                   android:theme="@style/OptOutEdgeToEdge"
                   android:taskAffinity="com.android.server.wm.flicker.testapp.LaunchTransparentActivity"
                   android:label="LaunchTransparentActivity"
diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityOptions.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityOptions.java
index e4de2c5..73625da 100644
--- a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityOptions.java
+++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityOptions.java
@@ -85,6 +85,12 @@
                 FLICKER_APP_PACKAGE + ".NonResizeablePortraitActivity");
     }
 
+    public static class NonResizeableFixedAspectRatioPortraitActivity {
+        public static final String LABEL = "NonResizeableFixedAspectRatioPortraitActivity";
+        public static final ComponentName COMPONENT = new ComponentName(FLICKER_APP_PACKAGE,
+                FLICKER_APP_PACKAGE + ".NonResizeableFixedAspectRatioPortraitActivity");
+    }
+
     public static class StartMediaProjectionActivity {
         public static final String LABEL = "StartMediaProjectionActivity";
         public static final ComponentName COMPONENT = new ComponentName(FLICKER_APP_PACKAGE,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/FixedColumnsSizeInteractorKosmos.kt b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/NonResizeableFixedAspectRatioPortraitActivity.java
similarity index 64%
copy from packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/FixedColumnsSizeInteractorKosmos.kt
copy to tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/NonResizeableFixedAspectRatioPortraitActivity.java
index f4d281d..be38c25 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/FixedColumnsSizeInteractorKosmos.kt
+++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/NonResizeableFixedAspectRatioPortraitActivity.java
@@ -14,10 +14,15 @@
  * limitations under the License.
  */
 
-package com.android.systemui.qs.panels.domain.interactor
+package com.android.server.wm.flicker.testapp;
 
-import com.android.systemui.kosmos.Kosmos
-import com.android.systemui.qs.panels.data.repository.fixedColumnsRepository
+import android.app.Activity;
+import android.os.Bundle;
 
-val Kosmos.fixedColumnsSizeInteractor by
-    Kosmos.Fixture { FixedColumnsSizeInteractor(fixedColumnsRepository) }
+public class NonResizeableFixedAspectRatioPortraitActivity extends Activity {
+    @Override
+    protected void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+        setContentView(R.layout.activity_non_resizeable);
+    }
+}
diff --git a/tests/graphics/SilkFX/res/layout/view_blur_behind.xml b/tests/graphics/SilkFX/res/layout/view_blur_behind.xml
new file mode 100644
index 0000000..83b1fa4
--- /dev/null
+++ b/tests/graphics/SilkFX/res/layout/view_blur_behind.xml
@@ -0,0 +1,148 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2024 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:orientation="vertical">
+
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:padding="8dp"
+            android:textSize="24dp"
+            android:text="~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" />
+
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:padding="8dp"
+            android:textSize="24dp"
+            android:text="wowwowwowwowwowwowwowwowwowwowwowwowwowwowwow" />
+
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:padding="8dp"
+            android:textSize="24dp"
+            android:text="I'm a little teapot" />
+
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:padding="8dp"
+            android:textSize="24dp"
+            android:text="Something. Something." />
+
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:padding="8dp"
+            android:textSize="24dp"
+            android:text="/\\/\\/\\/\\/\\/\\/\\/\\/\\/" />
+
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:padding="8dp"
+            android:textSize="24dp"
+            android:text="^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^" />
+
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:padding="8dp"
+            android:textSize="24dp"
+            android:text="~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" />
+
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:padding="8dp"
+            android:textSize="24dp"
+            android:text="wowwowwowwowwowwowwowwowwowwowwowwowwowwowwow" />
+
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:padding="8dp"
+            android:textSize="24dp"
+            android:text="I'm a little teapot" />
+
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:padding="8dp"
+            android:textSize="24dp"
+            android:text="Something. Something." />
+
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:padding="8dp"
+            android:textSize="24dp"
+            android:text="/\\/\\/\\/\\/\\/\\/\\/\\/\\/" />
+
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:padding="8dp"
+            android:textSize="24dp"
+            android:text="^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^" />
+
+    </LinearLayout>
+
+    <ScrollView
+        android:layout_width="match_parent"
+        android:layout_height="match_parent">
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:orientation="vertical">
+
+            <View
+                android:layout_width="match_parent"
+                android:layout_height="300dp" />
+
+            <com.android.test.silkfx.materials.BlurBehindContainer
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:background="#33AAAAAA"
+                android:padding="32dp">
+
+                <TextView
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:textSize="48dp"
+                    android:text="Blur!" />
+
+            </com.android.test.silkfx.materials.BlurBehindContainer>
+
+            <View
+                android:layout_width="match_parent"
+                android:layout_height="1024dp" />
+
+        </LinearLayout>
+
+    </ScrollView>
+
+</FrameLayout>
\ No newline at end of file
diff --git a/tests/graphics/SilkFX/src/com/android/test/silkfx/Main.kt b/tests/graphics/SilkFX/src/com/android/test/silkfx/Main.kt
index 59a6078..6b6d3b8 100644
--- a/tests/graphics/SilkFX/src/com/android/test/silkfx/Main.kt
+++ b/tests/graphics/SilkFX/src/com/android/test/silkfx/Main.kt
@@ -61,7 +61,8 @@
         )),
         DemoGroup("Materials", listOf(
                 Demo("Glass", GlassActivity::class),
-                Demo("Background Blur", BackgroundBlurActivity::class)
+                Demo("Background Blur", BackgroundBlurActivity::class),
+                Demo("View blur behind", R.layout.view_blur_behind, commonControls = false)
         ))
 )
 
diff --git a/tests/graphics/SilkFX/src/com/android/test/silkfx/materials/BlurBehindContainer.kt b/tests/graphics/SilkFX/src/com/android/test/silkfx/materials/BlurBehindContainer.kt
new file mode 100644
index 0000000..ce6348e
--- /dev/null
+++ b/tests/graphics/SilkFX/src/com/android/test/silkfx/materials/BlurBehindContainer.kt
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.test.silkfx.materials
+
+import android.content.Context
+import android.graphics.RenderEffect
+import android.graphics.Shader
+import android.util.AttributeSet
+import android.widget.FrameLayout
+
+class BlurBehindContainer(context: Context, attributeSet: AttributeSet) : FrameLayout(context, attributeSet) {
+    override fun onFinishInflate() {
+        super.onFinishInflate()
+        setBackdropRenderEffect(
+            RenderEffect.createBlurEffect(16.0f, 16.0f, Shader.TileMode.CLAMP))
+    }
+}
\ No newline at end of file
diff --git a/tests/testables/Android.bp b/tests/testables/Android.bp
index f211185..17cc0b2 100644
--- a/tests/testables/Android.bp
+++ b/tests/testables/Android.bp
@@ -35,4 +35,8 @@
         "androidx.test.rules",
         "mockito-target-inline-minus-junit4",
     ],
+    static_libs: [
+        "PlatformMotionTesting",
+        "kotlinx_coroutines_test",
+    ],
 }
diff --git a/tests/testables/src/android/animation/AnimatorTestRuleToolkit.kt b/tests/testables/src/android/animation/AnimatorTestRuleToolkit.kt
new file mode 100644
index 0000000..b27b826
--- /dev/null
+++ b/tests/testables/src/android/animation/AnimatorTestRuleToolkit.kt
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.animation
+
+import android.animation.AnimatorTestRuleToolkit.Companion.TAG
+import android.util.Log
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.Job
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.asStateFlow
+import kotlinx.coroutines.flow.take
+import kotlinx.coroutines.flow.takeWhile
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runCurrent
+import platform.test.motion.MotionTestRule
+import platform.test.motion.RecordedMotion
+import platform.test.motion.RecordedMotion.Companion.create
+import platform.test.motion.golden.DataPoint
+import platform.test.motion.golden.Feature
+import platform.test.motion.golden.FrameId
+import platform.test.motion.golden.TimeSeries
+import platform.test.motion.golden.TimeSeriesCaptureScope
+import platform.test.motion.golden.TimestampFrameId
+
+class AnimatorTestRuleToolkit(val animatorTestRule: AnimatorTestRule, val testScope: TestScope) {
+    internal companion object {
+        const val TAG = "AnimatorRuleToolkit"
+    }
+}
+
+/**
+ * Controls the timing of the motion recording.
+ *
+ * The time series is recorded while the [recording] function is running.
+ */
+class MotionControl(val recording: MotionControlFn)
+
+typealias MotionControlFn = suspend MotionControlScope.() -> Unit
+
+interface MotionControlScope {
+    /** Waits until [check] returns true. Invoked on each frame. */
+    suspend fun awaitCondition(check: () -> Boolean)
+
+    /** Waits for [count] frames to be processed. */
+    suspend fun awaitFrames(count: Int = 1)
+}
+
+/** Defines the sampling of features during a test run. */
+data class AnimatorRuleRecordingSpec<T>(
+    /** The root `observing` object, available in [timeSeriesCapture]'s [TimeSeriesCaptureScope]. */
+    val captureRoot: T,
+
+    /** The timing for the recording. */
+    val motionControl: MotionControl,
+
+    /** Time interval between frame captures, in milliseconds. */
+    val frameDurationMs: Long = 16L,
+
+    /**  Produces the time-series, invoked on each animation frame. */
+    val timeSeriesCapture: TimeSeriesCaptureScope<T>.() -> Unit,
+)
+
+/** Records the time-series of the features specified in [recordingSpec]. */
+fun <T> MotionTestRule<AnimatorTestRuleToolkit>.recordMotion(
+    recordingSpec: AnimatorRuleRecordingSpec<T>,
+): RecordedMotion {
+    with(toolkit.animatorTestRule) {
+        val frameIdCollector = mutableListOf<FrameId>()
+        val propertyCollector = mutableMapOf<String, MutableList<DataPoint<*>>>()
+
+        fun recordFrame(frameId: FrameId) {
+            Log.i(TAG, "recordFrame($frameId)")
+            frameIdCollector.add(frameId)
+            recordingSpec.timeSeriesCapture.invoke(
+                TimeSeriesCaptureScope(recordingSpec.captureRoot, propertyCollector)
+            )
+        }
+
+        val motionControl =
+            MotionControlImpl(
+                toolkit.animatorTestRule,
+                toolkit.testScope,
+                recordingSpec.frameDurationMs,
+                recordingSpec.motionControl,
+            )
+
+        Log.i(TAG, "recordMotion() begin recording")
+
+        val startFrameTime = currentTime
+        while (!motionControl.recordingEnded) {
+            recordFrame(TimestampFrameId(currentTime - startFrameTime))
+            motionControl.nextFrame()
+        }
+
+        Log.i(TAG, "recordMotion() end recording")
+
+        val timeSeries =
+            TimeSeries(
+                frameIdCollector.toList(),
+                propertyCollector.entries.map { entry -> Feature(entry.key, entry.value) },
+            )
+
+        return create(timeSeries, null)
+    }
+}
+
+@OptIn(ExperimentalCoroutinesApi::class)
+private class MotionControlImpl(
+    val animatorTestRule: AnimatorTestRule,
+    val testScope: TestScope,
+    val frameMs: Long,
+    motionControl: MotionControl,
+) : MotionControlScope {
+    private val recordingJob = motionControl.recording.launch()
+
+    private val frameEmitter = MutableStateFlow<Long>(0)
+    private val onFrame = frameEmitter.asStateFlow()
+
+    var recordingEnded: Boolean = false
+
+    fun nextFrame() {
+        animatorTestRule.advanceTimeBy(frameMs)
+
+        frameEmitter.tryEmit(animatorTestRule.currentTime)
+        testScope.runCurrent()
+
+        if (recordingJob.isCompleted) {
+            recordingEnded = true
+        }
+    }
+
+    override suspend fun awaitCondition(check: () -> Boolean) {
+        onFrame.takeWhile { !check() }.collect {}
+    }
+
+    override suspend fun awaitFrames(count: Int) {
+        onFrame.take(count).collect {}
+    }
+
+    private fun MotionControlFn.launch(): Job {
+        val function = this
+        return testScope.launch { function() }
+    }
+}
diff --git a/tests/testables/tests/Android.bp b/tests/testables/tests/Android.bp
index c23f41a..7110564 100644
--- a/tests/testables/tests/Android.bp
+++ b/tests/testables/tests/Android.bp
@@ -29,13 +29,17 @@
         "src/**/*.kt",
         "src/**/I*.aidl",
     ],
+    asset_dirs: ["goldens"],
     resource_dirs: ["res"],
     static_libs: [
+        "PlatformMotionTesting",
         "androidx.core_core-animation",
         "androidx.core_core-ktx",
+        "androidx.test.ext.junit",
         "androidx.test.rules",
         "androidx.test.ext.junit",
         "hamcrest-library",
+        "kotlinx_coroutines_test",
         "mockito-target-inline-minus-junit4",
         "testables",
         "truth",
diff --git a/tests/testables/tests/goldens/recordMotion_withAnimator.json b/tests/testables/tests/goldens/recordMotion_withAnimator.json
new file mode 100644
index 0000000..87fece5
--- /dev/null
+++ b/tests/testables/tests/goldens/recordMotion_withAnimator.json
@@ -0,0 +1,64 @@
+{
+  "frame_ids": [
+    0,
+    20,
+    40,
+    60,
+    80,
+    100,
+    120,
+    140,
+    160,
+    180,
+    200,
+    220,
+    240,
+    260,
+    280,
+    300,
+    320,
+    340,
+    360,
+    380,
+    400,
+    420,
+    440,
+    460,
+    480,
+    500
+  ],
+  "features": [
+    {
+      "name": "value",
+      "type": "float",
+      "data_points": [
+        1,
+        0.9960574,
+        0.98429155,
+        0.9648882,
+        0.9381534,
+        0.9045085,
+        0.8644843,
+        0.818712,
+        0.76791346,
+        0.7128896,
+        0.65450853,
+        0.5936906,
+        0.5313952,
+        0.46860474,
+        0.40630943,
+        0.34549147,
+        0.2871104,
+        0.23208654,
+        0.181288,
+        0.13551569,
+        0.09549153,
+        0.061846733,
+        0.035111785,
+        0.015708387,
+        0.003942609,
+        0
+      ]
+    }
+  ]
+}
diff --git a/tests/testables/tests/goldens/recordMotion_withSpring.json b/tests/testables/tests/goldens/recordMotion_withSpring.json
new file mode 100644
index 0000000..e9fb5b4
--- /dev/null
+++ b/tests/testables/tests/goldens/recordMotion_withSpring.json
@@ -0,0 +1,48 @@
+{
+  "frame_ids": [
+    0,
+    16,
+    32,
+    48,
+    64,
+    80,
+    96,
+    112,
+    128,
+    144,
+    160,
+    176,
+    192,
+    208,
+    224,
+    240,
+    256,
+    272
+  ],
+  "features": [
+    {
+      "name": "value",
+      "type": "float",
+      "data_points": [
+        1,
+        0.9488604,
+        0.83574325,
+        0.7016156,
+        0.5691678,
+        0.4497436,
+        0.34789434,
+        0.26431116,
+        0.19766562,
+        0.14572789,
+        0.10601636,
+        0.076149896,
+        0.05401709,
+        0.037837274,
+        0.026161024,
+        0.017839976,
+        0.011983856,
+        0.007914998
+      ]
+    }
+  ]
+}
diff --git a/tests/testables/tests/src/android/animation/AnimatorTestRuleToolkitTest.kt b/tests/testables/tests/src/android/animation/AnimatorTestRuleToolkitTest.kt
new file mode 100644
index 0000000..fbef489
--- /dev/null
+++ b/tests/testables/tests/src/android/animation/AnimatorTestRuleToolkitTest.kt
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.animation
+
+import android.util.FloatProperty
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation
+import com.android.internal.dynamicanimation.animation.SpringAnimation
+import com.android.internal.dynamicanimation.animation.SpringForce
+import kotlinx.coroutines.test.TestScope
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import platform.test.motion.MotionTestRule
+import platform.test.motion.RecordedMotion
+import platform.test.motion.golden.FeatureCapture
+import platform.test.motion.golden.asDataPoint
+import platform.test.motion.testing.createGoldenPathManager
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class AnimatorTestRuleToolkitTest {
+    companion object {
+        private val GOLDEN_PATH_MANAGER =
+            createGoldenPathManager("frameworks/base/tests/testables/tests/goldens")
+
+        private val TEST_PROPERTY =
+            object : FloatProperty<TestState>("value") {
+                override fun get(state: TestState): Float {
+                    return state.animatedValue
+                }
+
+                override fun setValue(state: TestState, value: Float) {
+                    state.animatedValue = value
+                }
+            }
+    }
+
+    @get:Rule(order = 0) val animatorTestRule = AnimatorTestRule(this)
+    @get:Rule(order = 1)
+    val motionRule =
+        MotionTestRule(AnimatorTestRuleToolkit(animatorTestRule, TestScope()), GOLDEN_PATH_MANAGER)
+
+    @Test
+    fun recordMotion_withAnimator() {
+        val state = TestState()
+        AnimatorSet().apply {
+            duration = 500
+            play(
+                ValueAnimator.ofFloat(state.animatedValue, 0f).apply {
+                    addUpdateListener { state.animatedValue = it.animatedValue as Float }
+                }
+            )
+            getInstrumentation().runOnMainSync { start() }
+        }
+
+        val recordedMotion =
+            record(state, MotionControl { awaitFrames(count = 26) }, sampleIntervalMs = 20L)
+
+        motionRule.assertThat(recordedMotion).timeSeriesMatchesGolden("recordMotion_withAnimator")
+    }
+
+    @Test
+    fun recordMotion_withSpring() {
+        val state = TestState()
+        var isDone = false
+        SpringAnimation(state, TEST_PROPERTY).apply {
+            spring =
+                SpringForce(0f).apply {
+                    stiffness = 500f
+                    dampingRatio = 0.95f
+                }
+
+            setStartValue(1f)
+            setMinValue(0f)
+            setMaxValue(1f)
+            minimumVisibleChange = 0.01f
+
+            addEndListener { _, _, _, _ -> isDone = true }
+            getInstrumentation().runOnMainSync { start() }
+        }
+
+        val recordedMotion =
+            record(state, MotionControl { awaitCondition { isDone } }, sampleIntervalMs = 16L)
+
+        motionRule.assertThat(recordedMotion).timeSeriesMatchesGolden("recordMotion_withSpring")
+    }
+
+    private fun record(
+        state: TestState,
+        motionControl: MotionControl,
+        sampleIntervalMs: Long,
+    ): RecordedMotion {
+        var recordedMotion: RecordedMotion? = null
+        getInstrumentation().runOnMainSync {
+            recordedMotion =
+                motionRule.recordMotion(
+                    AnimatorRuleRecordingSpec(
+                        state,
+                        motionControl,
+                        sampleIntervalMs,
+                    ) {
+                        feature(
+                            FeatureCapture("value") { state -> state.animatedValue.asDataPoint() },
+                            "value",
+                        )
+                    }
+                )
+        }
+        return recordedMotion!!
+    }
+
+    data class TestState(var animatedValue: Float = 1f)
+}
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGen.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGen.kt
index 165bb57..6d8d7b7 100644
--- a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGen.kt
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGen.kt
@@ -27,7 +27,7 @@
 import com.android.hoststubgen.filters.KeepNativeFilter
 import com.android.hoststubgen.filters.OutputFilter
 import com.android.hoststubgen.filters.SanitizationFilter
-import com.android.hoststubgen.filters.createFilterFromTextPolicyFile
+import com.android.hoststubgen.filters.TextFileFilterPolicyParser
 import com.android.hoststubgen.filters.printAsTextPolicy
 import com.android.hoststubgen.utils.ClassFilter
 import com.android.hoststubgen.visitors.BaseAdapter
@@ -178,8 +178,10 @@
 
         // Next, "text based" filter, which allows to override polices without touching
         // the target code.
-        options.policyOverrideFile.ifSet {
-            filter = createFilterFromTextPolicyFile(it, allClasses, filter)
+        if (options.policyOverrideFiles.isNotEmpty()) {
+            val parser = TextFileFilterPolicyParser(allClasses, filter)
+            options.policyOverrideFiles.forEach(parser::parse)
+            filter = parser.createOutputFilter()
         }
 
         // Apply the implicit filter.
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGenOptions.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGenOptions.kt
index b083d89..55e853e 100644
--- a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGenOptions.kt
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGenOptions.kt
@@ -100,7 +100,7 @@
         var defaultClassLoadHook: SetOnce<String?> = SetOnce(null),
         var defaultMethodCallHook: SetOnce<String?> = SetOnce(null),
 
-        var policyOverrideFile: SetOnce<String?> = SetOnce(null),
+        var policyOverrideFiles: MutableList<String> = mutableListOf(),
 
         var defaultPolicy: SetOnce<FilterPolicy> = SetOnce(FilterPolicy.Remove),
 
@@ -164,7 +164,7 @@
                         "--out-jar", "--out-impl-jar" -> ret.outJar.set(nextArg())
 
                         "--policy-override-file" ->
-                            ret.policyOverrideFile.set(nextArg())!!.ensureFileExists()
+                            ret.policyOverrideFiles.add(nextArg().ensureFileExists())
 
                         "--clean-up-on-error" -> ret.cleanUpOnError.set(true)
                         "--no-clean-up-on-error" -> ret.cleanUpOnError.set(false)
@@ -291,7 +291,7 @@
               annotationAllowedClassesFile=$annotationAllowedClassesFile,
               defaultClassLoadHook=$defaultClassLoadHook,
               defaultMethodCallHook=$defaultMethodCallHook,
-              policyOverrideFile=$policyOverrideFile,
+              policyOverrideFiles=${policyOverrideFiles.toTypedArray().contentToString()},
               defaultPolicy=$defaultPolicy,
               cleanUpOnError=$cleanUpOnError,
               enableClassChecker=$enableClassChecker,
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/TextFileFilterPolicyParser.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/TextFileFilterPolicyParser.kt
index 073b503..caf80eb 100644
--- a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/TextFileFilterPolicyParser.kt
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/TextFileFilterPolicyParser.kt
@@ -23,13 +23,10 @@
 import com.android.hoststubgen.log
 import com.android.hoststubgen.normalizeTextLine
 import com.android.hoststubgen.whitespaceRegex
-import org.objectweb.asm.Opcodes
-import org.objectweb.asm.tree.ClassNode
-import java.io.BufferedReader
-import java.io.FileReader
+import java.io.File
 import java.io.PrintWriter
-import java.util.Objects
 import java.util.regex.Pattern
+import org.objectweb.asm.tree.ClassNode
 
 /**
  * Print a class node as a "keep" policy.
@@ -49,256 +46,56 @@
     }
 }
 
-/** Return true if [access] is either public or protected. */
-private fun isVisible(access: Int): Boolean {
-    return (access and (Opcodes.ACC_PUBLIC or Opcodes.ACC_PROTECTED)) != 0
-}
-
 private const val FILTER_REASON = "file-override"
 
-/**
- * Read a given "policy" file and return as an [OutputFilter]
- */
-fun createFilterFromTextPolicyFile(
-        filename: String,
-        classes: ClassNodes,
-        fallback: OutputFilter,
-        ): OutputFilter {
-    log.i("Loading offloaded annotations from $filename ...")
-    log.withIndent {
-        val subclassFilter = SubclassFilter(classes, fallback)
-        val packageFilter = PackageFilter(subclassFilter)
-        val imf = InMemoryOutputFilter(classes, packageFilter)
+private enum class SpecialClass {
+    NotSpecial,
+    Aidl,
+    FeatureFlags,
+    Sysprops,
+    RFile,
+}
 
-        var lineNo = 0
+class TextFileFilterPolicyParser(
+    private val classes: ClassNodes,
+    fallback: OutputFilter
+) {
+    private val subclassFilter = SubclassFilter(classes, fallback)
+    private val packageFilter = PackageFilter(subclassFilter)
+    private val imf = InMemoryOutputFilter(classes, packageFilter)
+    private var aidlPolicy: FilterPolicyWithReason? = null
+    private var featureFlagsPolicy: FilterPolicyWithReason? = null
+    private var syspropsPolicy: FilterPolicyWithReason? = null
+    private var rFilePolicy: FilterPolicyWithReason? = null
+    private val typeRenameSpec = mutableListOf<TextFilePolicyRemapperFilter.TypeRenameSpec>()
+    private val methodReplaceSpec =
+        mutableListOf<TextFilePolicyMethodReplaceFilter.MethodCallReplaceSpec>()
 
-        var aidlPolicy: FilterPolicyWithReason? = null
-        var featureFlagsPolicy: FilterPolicyWithReason? = null
-        var syspropsPolicy: FilterPolicyWithReason? = null
-        var rFilePolicy: FilterPolicyWithReason? = null
-        val typeRenameSpec = mutableListOf<TextFilePolicyRemapperFilter.TypeRenameSpec>()
-        val methodReplaceSpec =
-            mutableListOf<TextFilePolicyMethodReplaceFilter.MethodCallReplaceSpec>()
+    private lateinit var currentClassName: String
 
-        try {
-            BufferedReader(FileReader(filename)).use { reader ->
-                var className = ""
-
-                while (true) {
-                    var line = reader.readLine() ?: break
+    /**
+     * Read a given "policy" file and return as an [OutputFilter]
+     */
+    fun parse(file: String) {
+        log.i("Loading offloaded annotations from $file ...")
+        log.withIndent {
+            var lineNo = 0
+            try {
+                File(file).forEachLine {
                     lineNo++
-
-                    line = normalizeTextLine(line)
-
+                    val line = normalizeTextLine(it)
                     if (line.isEmpty()) {
-                        continue // skip empty lines.
+                        return@forEachLine // skip empty lines.
                     }
-
-
-                    // TODO: Method too long, break it up.
-
-                    val fields = line.split(whitespaceRegex).toTypedArray()
-                    when (fields[0].lowercase()) {
-                        "p", "package" -> {
-                            if (fields.size < 3) {
-                                throw ParseException("Package ('p') expects 2 fields.")
-                            }
-                            val name = fields[1]
-                            val rawPolicy = fields[2]
-                            if (resolveExtendingClass(name) != null) {
-                                throw ParseException("Package can't be a super class type")
-                            }
-                            if (resolveSpecialClass(name) != SpecialClass.NotSpecial) {
-                                throw ParseException("Package can't be a special class type")
-                            }
-                            if (rawPolicy.startsWith("!")) {
-                                throw ParseException("Package can't have a substitution")
-                            }
-                            if (rawPolicy.startsWith("~")) {
-                                throw ParseException("Package can't have a class load hook")
-                            }
-                            val policy = parsePolicy(rawPolicy)
-                            if (!policy.isUsableWithClasses) {
-                                throw ParseException("Package can't have policy '$policy'")
-                            }
-                            packageFilter.addPolicy(name, policy.withReason(FILTER_REASON))
-                        }
-
-                        "c", "class" -> {
-                            if (fields.size < 3) {
-                                throw ParseException("Class ('c') expects 2 fields.")
-                            }
-                            className = fields[1]
-
-                            // superClass is set when the class name starts with a "*".
-                            val superClass = resolveExtendingClass(className)
-
-                            // :aidl, etc?
-                            val classType = resolveSpecialClass(className)
-
-                            if (fields[2].startsWith("!")) {
-                                if (classType != SpecialClass.NotSpecial) {
-                                    // We could support it, but not needed at least for now.
-                                    throw ParseException(
-                                            "Special class can't have a substitution")
-                                }
-                                // It's a redirection class.
-                                val toClass = fields[2].substring(1)
-                                imf.setRedirectionClass(className, toClass)
-                            } else if (fields[2].startsWith("~")) {
-                                if (classType != SpecialClass.NotSpecial) {
-                                    // We could support it, but not needed at least for now.
-                                    throw ParseException(
-                                            "Special class can't have a class load hook")
-                                }
-                                // It's a class-load hook
-                                val callback = fields[2].substring(1)
-                                imf.setClassLoadHook(className, callback)
-                            } else {
-                                val policy = parsePolicy(fields[2])
-                                if (!policy.isUsableWithClasses) {
-                                    throw ParseException("Class can't have policy '$policy'")
-                                }
-                                Objects.requireNonNull(className)
-
-                                when (classType) {
-                                    SpecialClass.NotSpecial -> {
-                                        // TODO: Duplicate check, etc
-                                        if (superClass == null) {
-                                            imf.setPolicyForClass(
-                                                className, policy.withReason(FILTER_REASON)
-                                            )
-                                        } else {
-                                            subclassFilter.addPolicy(superClass,
-                                                policy.withReason("extends $superClass"))
-                                        }
-                                    }
-                                    SpecialClass.Aidl -> {
-                                        if (aidlPolicy != null) {
-                                            throw ParseException(
-                                                    "Policy for AIDL classes already defined")
-                                        }
-                                        aidlPolicy = policy.withReason(
-                                                "$FILTER_REASON (special-class AIDL)")
-                                    }
-                                    SpecialClass.FeatureFlags -> {
-                                        if (featureFlagsPolicy != null) {
-                                            throw ParseException(
-                                                    "Policy for feature flags already defined")
-                                        }
-                                        featureFlagsPolicy = policy.withReason(
-                                                "$FILTER_REASON (special-class feature flags)")
-                                    }
-                                    SpecialClass.Sysprops -> {
-                                        if (syspropsPolicy != null) {
-                                            throw ParseException(
-                                                    "Policy for sysprops already defined")
-                                        }
-                                        syspropsPolicy = policy.withReason(
-                                                "$FILTER_REASON (special-class sysprops)")
-                                    }
-                                    SpecialClass.RFile -> {
-                                        if (rFilePolicy != null) {
-                                            throw ParseException(
-                                                "Policy for R file already defined")
-                                        }
-                                        rFilePolicy = policy.withReason(
-                                            "$FILTER_REASON (special-class R file)")
-                                    }
-                                }
-                            }
-                        }
-
-                        "f", "field" -> {
-                            if (fields.size < 3) {
-                                throw ParseException("Field ('f') expects 2 fields.")
-                            }
-                            val name = fields[1]
-                            val policy = parsePolicy(fields[2])
-                            if (!policy.isUsableWithFields) {
-                                throw ParseException("Field can't have policy '$policy'")
-                            }
-                            Objects.requireNonNull(className)
-
-                            // TODO: Duplicate check, etc
-                            imf.setPolicyForField(className, name, policy.withReason(FILTER_REASON))
-                        }
-
-                        "m", "method" -> {
-                            if (fields.size < 4) {
-                                throw ParseException("Method ('m') expects 3 fields.")
-                            }
-                            val name = fields[1]
-                            val signature = fields[2]
-                            val policy = parsePolicy(fields[3])
-
-                            if (!policy.isUsableWithMethods) {
-                                throw ParseException("Method can't have policy '$policy'")
-                            }
-
-                            Objects.requireNonNull(className)
-
-                            imf.setPolicyForMethod(className, name, signature,
-                                    policy.withReason(FILTER_REASON))
-                            if (policy == FilterPolicy.Substitute) {
-                                val fromName = fields[3].substring(1)
-
-                                if (fromName == name) {
-                                    throw ParseException(
-                                            "Substitution must have a different name")
-                                }
-
-                                // Set the policy for the "from" method.
-                                imf.setPolicyForMethod(className, fromName, signature,
-                                    FilterPolicy.Keep.withReason(FILTER_REASON))
-
-                                val classAndMethod = splitWithLastPeriod(fromName)
-                                if (classAndMethod != null) {
-                                    // If the substitution target contains a ".", then
-                                    // it's a method call redirect.
-                                    methodReplaceSpec.add(
-                                        TextFilePolicyMethodReplaceFilter.MethodCallReplaceSpec(
-                                            className.toJvmClassName(),
-                                            name,
-                                            signature,
-                                            classAndMethod.first.toJvmClassName(),
-                                            classAndMethod.second,
-                                        )
-                                    )
-                                } else {
-                                    // It's an in-class replace.
-                                    // ("@RavenwoodReplace" equivalent)
-                                    imf.setRenameTo(className, fromName, signature, name)
-                                }
-                            }
-                        }
-                        "r", "rename" -> {
-                            if (fields.size < 3) {
-                                throw ParseException("Rename ('r') expects 2 fields.")
-                            }
-                            // Add ".*" to make it a prefix match.
-                            val pattern = Pattern.compile(fields[1] + ".*")
-
-                            // Removing the leading /'s from the prefix. This allows
-                            // using a single '/' as an empty suffix, which is useful to have a
-                            // "negative" rename rule to avoid subsequent raname's from getting
-                            // applied. (Which is needed for services.jar)
-                            val prefix = fields[2].trimStart('/')
-
-                            typeRenameSpec += TextFilePolicyRemapperFilter.TypeRenameSpec(
-                                pattern, prefix)
-                        }
-
-                        else -> {
-                            throw ParseException("Unknown directive \"${fields[0]}\"")
-                        }
-                    }
+                    parseLine(line)
                 }
+            } catch (e: ParseException) {
+                throw e.withSourceInfo(file, lineNo)
             }
-        } catch (e: ParseException) {
-            throw e.withSourceInfo(filename, lineNo)
         }
+    }
 
+    fun createOutputFilter(): OutputFilter {
         var ret: OutputFilter = imf
         if (typeRenameSpec.isNotEmpty()) {
             ret = TextFilePolicyRemapperFilter(typeRenameSpec, ret)
@@ -309,54 +106,271 @@
 
         // Wrap the in-memory-filter with AHF.
         ret = AndroidHeuristicsFilter(
-                classes, aidlPolicy, featureFlagsPolicy, syspropsPolicy, rFilePolicy, ret)
+            classes, aidlPolicy, featureFlagsPolicy, syspropsPolicy, rFilePolicy, ret
+        )
 
         return ret
     }
-}
 
-private enum class SpecialClass {
-    NotSpecial,
-    Aidl,
-    FeatureFlags,
-    Sysprops,
-    RFile,
-}
-
-private fun resolveSpecialClass(className: String): SpecialClass {
-    if (!className.startsWith(":")) {
-        return SpecialClass.NotSpecial
+    private fun parseLine(line: String) {
+        val fields = line.split(whitespaceRegex).toTypedArray()
+        when (fields[0].lowercase()) {
+            "p", "package" -> parsePackage(fields)
+            "c", "class" -> parseClass(fields)
+            "f", "field" -> parseField(fields)
+            "m", "method" -> parseMethod(fields)
+            "r", "rename" -> parseRename(fields)
+            else -> throw ParseException("Unknown directive \"${fields[0]}\"")
+        }
     }
-    when (className.lowercase()) {
-        ":aidl" -> return SpecialClass.Aidl
-        ":feature_flags" -> return SpecialClass.FeatureFlags
-        ":sysprops" -> return SpecialClass.Sysprops
-        ":r" -> return SpecialClass.RFile
-    }
-    throw ParseException("Invalid special class name \"$className\"")
-}
 
-private fun resolveExtendingClass(className: String): String? {
-    if (!className.startsWith("*")) {
-        return null
+    private fun resolveSpecialClass(className: String): SpecialClass {
+        if (!className.startsWith(":")) {
+            return SpecialClass.NotSpecial
+        }
+        when (className.lowercase()) {
+            ":aidl" -> return SpecialClass.Aidl
+            ":feature_flags" -> return SpecialClass.FeatureFlags
+            ":sysprops" -> return SpecialClass.Sysprops
+            ":r" -> return SpecialClass.RFile
+        }
+        throw ParseException("Invalid special class name \"$className\"")
     }
-    return className.substring(1)
-}
 
-private fun parsePolicy(s: String): FilterPolicy {
-    return when (s.lowercase()) {
-        "k", "keep" -> FilterPolicy.Keep
-        "t", "throw" -> FilterPolicy.Throw
-        "r", "remove" -> FilterPolicy.Remove
-        "kc", "keepclass" -> FilterPolicy.KeepClass
-        "i", "ignore" -> FilterPolicy.Ignore
-        "rdr", "redirect" -> FilterPolicy.Redirect
-        else -> {
-            if (s.startsWith("@")) {
-                FilterPolicy.Substitute
-            } else {
-                throw ParseException("Invalid policy \"$s\"")
+    private fun resolveExtendingClass(className: String): String? {
+        if (!className.startsWith("*")) {
+            return null
+        }
+        return className.substring(1)
+    }
+
+    private fun parsePolicy(s: String): FilterPolicy {
+        return when (s.lowercase()) {
+            "k", "keep" -> FilterPolicy.Keep
+            "t", "throw" -> FilterPolicy.Throw
+            "r", "remove" -> FilterPolicy.Remove
+            "kc", "keepclass" -> FilterPolicy.KeepClass
+            "i", "ignore" -> FilterPolicy.Ignore
+            "rdr", "redirect" -> FilterPolicy.Redirect
+            else -> {
+                if (s.startsWith("@")) {
+                    FilterPolicy.Substitute
+                } else {
+                    throw ParseException("Invalid policy \"$s\"")
+                }
             }
         }
     }
+
+    private fun parsePackage(fields: Array<String>) {
+        if (fields.size < 3) {
+            throw ParseException("Package ('p') expects 2 fields.")
+        }
+        val name = fields[1]
+        val rawPolicy = fields[2]
+        if (resolveExtendingClass(name) != null) {
+            throw ParseException("Package can't be a super class type")
+        }
+        if (resolveSpecialClass(name) != SpecialClass.NotSpecial) {
+            throw ParseException("Package can't be a special class type")
+        }
+        if (rawPolicy.startsWith("!")) {
+            throw ParseException("Package can't have a substitution")
+        }
+        if (rawPolicy.startsWith("~")) {
+            throw ParseException("Package can't have a class load hook")
+        }
+        val policy = parsePolicy(rawPolicy)
+        if (!policy.isUsableWithClasses) {
+            throw ParseException("Package can't have policy '$policy'")
+        }
+        packageFilter.addPolicy(name, policy.withReason(FILTER_REASON))
+    }
+
+    private fun parseClass(fields: Array<String>) {
+        if (fields.size < 3) {
+            throw ParseException("Class ('c') expects 2 fields.")
+        }
+        currentClassName = fields[1]
+
+        // superClass is set when the class name starts with a "*".
+        val superClass = resolveExtendingClass(currentClassName)
+
+        // :aidl, etc?
+        val classType = resolveSpecialClass(currentClassName)
+
+        if (fields[2].startsWith("!")) {
+            if (classType != SpecialClass.NotSpecial) {
+                // We could support it, but not needed at least for now.
+                throw ParseException(
+                    "Special class can't have a substitution"
+                )
+            }
+            // It's a redirection class.
+            val toClass = fields[2].substring(1)
+            imf.setRedirectionClass(currentClassName, toClass)
+        } else if (fields[2].startsWith("~")) {
+            if (classType != SpecialClass.NotSpecial) {
+                // We could support it, but not needed at least for now.
+                throw ParseException(
+                    "Special class can't have a class load hook"
+                )
+            }
+            // It's a class-load hook
+            val callback = fields[2].substring(1)
+            imf.setClassLoadHook(currentClassName, callback)
+        } else {
+            val policy = parsePolicy(fields[2])
+            if (!policy.isUsableWithClasses) {
+                throw ParseException("Class can't have policy '$policy'")
+            }
+
+            when (classType) {
+                SpecialClass.NotSpecial -> {
+                    // TODO: Duplicate check, etc
+                    if (superClass == null) {
+                        imf.setPolicyForClass(
+                            currentClassName, policy.withReason(FILTER_REASON)
+                        )
+                    } else {
+                        subclassFilter.addPolicy(
+                            superClass,
+                            policy.withReason("extends $superClass")
+                        )
+                    }
+                }
+
+                SpecialClass.Aidl -> {
+                    if (aidlPolicy != null) {
+                        throw ParseException(
+                            "Policy for AIDL classes already defined"
+                        )
+                    }
+                    aidlPolicy = policy.withReason(
+                        "$FILTER_REASON (special-class AIDL)"
+                    )
+                }
+
+                SpecialClass.FeatureFlags -> {
+                    if (featureFlagsPolicy != null) {
+                        throw ParseException(
+                            "Policy for feature flags already defined"
+                        )
+                    }
+                    featureFlagsPolicy = policy.withReason(
+                        "$FILTER_REASON (special-class feature flags)"
+                    )
+                }
+
+                SpecialClass.Sysprops -> {
+                    if (syspropsPolicy != null) {
+                        throw ParseException(
+                            "Policy for sysprops already defined"
+                        )
+                    }
+                    syspropsPolicy = policy.withReason(
+                        "$FILTER_REASON (special-class sysprops)"
+                    )
+                }
+
+                SpecialClass.RFile -> {
+                    if (rFilePolicy != null) {
+                        throw ParseException(
+                            "Policy for R file already defined"
+                        )
+                    }
+                    rFilePolicy = policy.withReason(
+                        "$FILTER_REASON (special-class R file)"
+                    )
+                }
+            }
+        }
+    }
+
+    private fun parseField(fields: Array<String>) {
+        if (fields.size < 3) {
+            throw ParseException("Field ('f') expects 2 fields.")
+        }
+        val name = fields[1]
+        val policy = parsePolicy(fields[2])
+        if (!policy.isUsableWithFields) {
+            throw ParseException("Field can't have policy '$policy'")
+        }
+        require(this::currentClassName.isInitialized)
+
+        // TODO: Duplicate check, etc
+        imf.setPolicyForField(currentClassName, name, policy.withReason(FILTER_REASON))
+    }
+
+    private fun parseMethod(fields: Array<String>) {
+        if (fields.size < 4) {
+            throw ParseException("Method ('m') expects 3 fields.")
+        }
+        val name = fields[1]
+        val signature = fields[2]
+        val policy = parsePolicy(fields[3])
+
+        if (!policy.isUsableWithMethods) {
+            throw ParseException("Method can't have policy '$policy'")
+        }
+
+        require(this::currentClassName.isInitialized)
+
+        imf.setPolicyForMethod(
+            currentClassName, name, signature,
+            policy.withReason(FILTER_REASON)
+        )
+        if (policy == FilterPolicy.Substitute) {
+            val fromName = fields[3].substring(1)
+
+            if (fromName == name) {
+                throw ParseException(
+                    "Substitution must have a different name"
+                )
+            }
+
+            // Set the policy for the "from" method.
+            imf.setPolicyForMethod(
+                currentClassName, fromName, signature,
+                FilterPolicy.Keep.withReason(FILTER_REASON)
+            )
+
+            val classAndMethod = splitWithLastPeriod(fromName)
+            if (classAndMethod != null) {
+                // If the substitution target contains a ".", then
+                // it's a method call redirect.
+                methodReplaceSpec.add(
+                    TextFilePolicyMethodReplaceFilter.MethodCallReplaceSpec(
+                        currentClassName.toJvmClassName(),
+                        name,
+                        signature,
+                        classAndMethod.first.toJvmClassName(),
+                        classAndMethod.second,
+                    )
+                )
+            } else {
+                // It's an in-class replace.
+                // ("@RavenwoodReplace" equivalent)
+                imf.setRenameTo(currentClassName, fromName, signature, name)
+            }
+        }
+    }
+
+    private fun parseRename(fields: Array<String>) {
+        if (fields.size < 3) {
+            throw ParseException("Rename ('r') expects 2 fields.")
+        }
+        // Add ".*" to make it a prefix match.
+        val pattern = Pattern.compile(fields[1] + ".*")
+
+        // Removing the leading /'s from the prefix. This allows
+        // using a single '/' as an empty suffix, which is useful to have a
+        // "negative" rename rule to avoid subsequent raname's from getting
+        // applied. (Which is needed for services.jar)
+        val prefix = fields[2].trimStart('/')
+
+        typeRenameSpec += TextFilePolicyRemapperFilter.TypeRenameSpec(
+            pattern, prefix
+        )
+    }
 }
diff --git a/wifi/java/src/android/net/wifi/WifiMigration.java b/wifi/java/src/android/net/wifi/WifiMigration.java
index f1850dd..28e9c45 100644
--- a/wifi/java/src/android/net/wifi/WifiMigration.java
+++ b/wifi/java/src/android/net/wifi/WifiMigration.java
@@ -38,6 +38,8 @@
 import android.util.Log;
 import android.util.SparseArray;
 
+import com.android.internal.os.BackgroundThread;
+
 import java.io.File;
 import java.io.FileNotFoundException;
 import java.io.InputStream;
@@ -48,6 +50,8 @@
 import java.util.List;
 import java.util.Objects;
 import java.util.Set;
+import java.util.concurrent.Executor;
+import java.util.function.IntConsumer;
 
 /**
  * Class used to provide one time hooks for existing OEM devices to migrate their config store
@@ -605,13 +609,35 @@
     /**
      * Migrate any certificates in Legacy Keystore to the newer WifiBlobstore database.
      *
-     * If there are no certificates to migrate, this method will return immediately.
+     * Operation will be handled on the BackgroundThread, and the result will be posted
+     * to the provided Executor.
+     *
+     * @param executor The executor on which callback will be invoked
+     * @param resultsCallback Callback to receive the status code
      *
      * @hide
      */
     @FlaggedApi(Flags.FLAG_LEGACY_KEYSTORE_TO_WIFI_BLOBSTORE_MIGRATION_READ_ONLY)
     @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
-    public static @KeystoreMigrationStatus int migrateLegacyKeystoreToWifiBlobstore() {
+    public static void migrateLegacyKeystoreToWifiBlobstore(
+            @NonNull Executor executor, @NonNull IntConsumer resultsCallback) {
+        Objects.requireNonNull(executor, "executor cannot be null");
+        Objects.requireNonNull(resultsCallback, "resultsCallback cannot be null");
+        BackgroundThread.getHandler().post(() -> {
+            int status = migrateLegacyKeystoreToWifiBlobstoreInternal();
+            executor.execute(() -> {
+                resultsCallback.accept(status);
+            });
+        });
+    }
+
+    /**
+     * Synchronously perform the Keystore migration described in
+     * {@link #migrateLegacyKeystoreToWifiBlobstore(Executor, IntConsumer)}
+     *
+     * @hide
+     */
+    public static @KeystoreMigrationStatus int migrateLegacyKeystoreToWifiBlobstoreInternal() {
         if (!WifiBlobStore.supplicantCanAccessBlobstore()) {
             // Supplicant cannot access WifiBlobstore, so keep the certs in Legacy Keystore
             Log.i(TAG, "Avoiding migration since supplicant cannot access WifiBlobstore");
diff --git a/wifi/tests/src/android/net/wifi/WifiMigrationTest.java b/wifi/tests/src/android/net/wifi/WifiMigrationTest.java
index 0aa299f..ce5b60a 100644
--- a/wifi/tests/src/android/net/wifi/WifiMigrationTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiMigrationTest.java
@@ -81,7 +81,7 @@
     public void testKeystoreMigrationAvoidedOnLegacyVendorPartition() {
         when(WifiBlobStore.supplicantCanAccessBlobstore()).thenReturn(false);
         assertEquals(WifiMigration.KEYSTORE_MIGRATION_SUCCESS_MIGRATION_NOT_NEEDED,
-                WifiMigration.migrateLegacyKeystoreToWifiBlobstore());
+                WifiMigration.migrateLegacyKeystoreToWifiBlobstoreInternal());
         verifyNoMoreInteractions(mLegacyKeystore, mWifiBlobStore);
     }
 
@@ -93,7 +93,7 @@
     public void testKeystoreMigrationNoLegacyAliases() throws Exception {
         when(mLegacyKeystore.list(anyString(), anyInt())).thenReturn(new String[0]);
         assertEquals(WifiMigration.KEYSTORE_MIGRATION_SUCCESS_MIGRATION_NOT_NEEDED,
-                WifiMigration.migrateLegacyKeystoreToWifiBlobstore());
+                WifiMigration.migrateLegacyKeystoreToWifiBlobstoreInternal());
         verify(mLegacyKeystore).list(anyString(), anyInt());
         verifyNoMoreInteractions(mLegacyKeystore, mWifiBlobStore);
     }
@@ -110,7 +110,7 @@
         when(mWifiBlobStore.list(anyString())).thenReturn(blobstoreAliases);
 
         assertEquals(WifiMigration.KEYSTORE_MIGRATION_SUCCESS_MIGRATION_COMPLETE,
-                WifiMigration.migrateLegacyKeystoreToWifiBlobstore());
+                WifiMigration.migrateLegacyKeystoreToWifiBlobstoreInternal());
         verify(mWifiBlobStore, times(legacyAliases.length)).put(anyString(), any(byte[].class));
     }
 
@@ -129,7 +129,7 @@
 
         // Expect that only the unique legacy alias is migrated to the blobstore
         assertEquals(WifiMigration.KEYSTORE_MIGRATION_SUCCESS_MIGRATION_COMPLETE,
-                WifiMigration.migrateLegacyKeystoreToWifiBlobstore());
+                WifiMigration.migrateLegacyKeystoreToWifiBlobstoreInternal());
         verify(mWifiBlobStore).list(anyString());
         verify(mWifiBlobStore).put(eq(uniqueLegacyAlias), any(byte[].class));
         verifyNoMoreInteractions(mWifiBlobStore);
@@ -146,7 +146,7 @@
         when(mLegacyKeystore.list(anyString(), anyInt())).thenThrow(
                 new ServiceSpecificException(ILegacyKeystore.ERROR_SYSTEM_ERROR));
         assertEquals(WifiMigration.KEYSTORE_MIGRATION_SUCCESS_MIGRATION_NOT_NEEDED,
-                WifiMigration.migrateLegacyKeystoreToWifiBlobstore());
+                WifiMigration.migrateLegacyKeystoreToWifiBlobstoreInternal());
     }
 
     /**
@@ -157,6 +157,6 @@
     public void testKeystoreMigrationFailsIfExceptionEncountered() throws Exception {
         when(mLegacyKeystore.list(anyString(), anyInt())).thenThrow(new RemoteException());
         assertEquals(WifiMigration.KEYSTORE_MIGRATION_FAILURE_ENCOUNTERED_EXCEPTION,
-                WifiMigration.migrateLegacyKeystoreToWifiBlobstore());
+                WifiMigration.migrateLegacyKeystoreToWifiBlobstoreInternal());
     }
 }